1 /* 2 * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 25 26 package org.graalvm.compiler.core.aarch64; 27 28 import jdk.vm.ci.meta.AllocatableValue; 29 import jdk.vm.ci.meta.JavaKind; 30 import jdk.vm.ci.meta.Value; 31 import jdk.internal.vm.compiler.collections.EconomicMap; 32 import jdk.internal.vm.compiler.collections.Equivalence; 33 import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; 34 import org.graalvm.compiler.core.common.LIRKind; 35 import org.graalvm.compiler.core.gen.NodeMatchRules; 36 import org.graalvm.compiler.core.match.ComplexMatchResult; 37 import org.graalvm.compiler.core.match.MatchRule; 38 import org.graalvm.compiler.graph.Node; 39 import org.graalvm.compiler.lir.LIRFrameState; 40 import org.graalvm.compiler.lir.Variable; 41 import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp; 42 import org.graalvm.compiler.lir.gen.LIRGeneratorTool; 43 import org.graalvm.compiler.nodes.ConstantNode; 44 import org.graalvm.compiler.nodes.DeoptimizingNode; 45 import org.graalvm.compiler.nodes.NodeView; 46 import org.graalvm.compiler.nodes.ValueNode; 47 import org.graalvm.compiler.nodes.calc.AddNode; 48 import org.graalvm.compiler.nodes.calc.AndNode; 49 import org.graalvm.compiler.nodes.calc.BinaryNode; 50 import org.graalvm.compiler.nodes.calc.LeftShiftNode; 51 import org.graalvm.compiler.nodes.calc.NotNode; 52 import org.graalvm.compiler.nodes.calc.OrNode; 53 import org.graalvm.compiler.nodes.calc.RightShiftNode; 54 import org.graalvm.compiler.nodes.calc.SubNode; 55 import org.graalvm.compiler.nodes.calc.UnsignedRightShiftNode; 56 import org.graalvm.compiler.nodes.calc.XorNode; 57 import org.graalvm.compiler.nodes.memory.Access; 58 59 import jdk.vm.ci.aarch64.AArch64Kind; 60 61 public class AArch64NodeMatchRules extends NodeMatchRules { 62 private static final EconomicMap<Class<? extends Node>, AArch64ArithmeticOp> nodeOpMap; 63 64 private static final EconomicMap<Class<? extends BinaryNode>, AArch64MacroAssembler.ShiftType> shiftTypeMap; 65 66 static { 67 nodeOpMap = EconomicMap.create(Equivalence.IDENTITY, 5); 68 nodeOpMap.put(AddNode.class, AArch64ArithmeticOp.ADD); 69 nodeOpMap.put(SubNode.class, AArch64ArithmeticOp.SUB); 70 nodeOpMap.put(AndNode.class, AArch64ArithmeticOp.AND); 71 nodeOpMap.put(OrNode.class, AArch64ArithmeticOp.OR); 72 nodeOpMap.put(XorNode.class, AArch64ArithmeticOp.XOR); 73 74 shiftTypeMap = EconomicMap.create(Equivalence.IDENTITY, 3); 75 shiftTypeMap.put(LeftShiftNode.class, AArch64MacroAssembler.ShiftType.LSL); 76 shiftTypeMap.put(RightShiftNode.class, AArch64MacroAssembler.ShiftType.ASR); 77 shiftTypeMap.put(UnsignedRightShiftNode.class, AArch64MacroAssembler.ShiftType.LSR); 78 } 79 80 public AArch64NodeMatchRules(LIRGeneratorTool gen) { 81 super(gen); 82 } 83 84 protected LIRFrameState getState(Access access) { 85 if (access instanceof DeoptimizingNode) { 86 return state((DeoptimizingNode) access); 87 } 88 return null; 89 } 90 91 protected AArch64Kind getMemoryKind(Access access) { 92 return (AArch64Kind) gen.getLIRKind(access.asNode().stamp(NodeView.DEFAULT)).getPlatformKind(); 93 } 94 95 private AllocatableValue moveSp(AllocatableValue value) { 96 return getLIRGeneratorTool().moveSp(value); 97 } 98 99 private ComplexMatchResult emitBinaryShift(AArch64ArithmeticOp op, ValueNode value, BinaryNode shift, boolean isShiftNot) { 100 AArch64MacroAssembler.ShiftType shiftType = shiftTypeMap.get(shift.getClass()); 101 assert shiftType != null; 102 assert value.getStackKind().isNumericInteger(); 103 assert shift.getX().getStackKind().isNumericInteger(); 104 assert shift.getY() instanceof ConstantNode; 105 106 return builder -> { 107 Value a = operand(value); 108 Value b = operand(shift.getX()); 109 Variable result = gen.newVariable(LIRKind.combine(a, b)); 110 AllocatableValue x = moveSp(gen.asAllocatable(a)); 111 AllocatableValue y = moveSp(gen.asAllocatable(b)); 112 int shiftAmount = shift.getY().asJavaConstant().asInt(); 113 gen.append(new AArch64ArithmeticOp.BinaryShiftOp(op, result, x, y, shiftType, shiftAmount, isShiftNot)); 114 return result; 115 }; 116 } 117 118 @MatchRule("(Add=binary a (LeftShift=shift b Constant))") 119 @MatchRule("(Add=binary a (RightShift=shift b Constant))") 120 @MatchRule("(Add=binary a (UnsignedRightShift=shift b Constant))") 121 @MatchRule("(Sub=binary a (LeftShift=shift b Constant))") 122 @MatchRule("(Sub=binary a (RightShift=shift b Constant))") 123 @MatchRule("(Sub=binary a (UnsignedRightShift=shift b Constant))") 124 public ComplexMatchResult addSubShift(BinaryNode binary, ValueNode a, BinaryNode shift) { 125 AArch64ArithmeticOp op = nodeOpMap.get(binary.getClass()); 126 assert op != null; 127 return emitBinaryShift(op, a, shift, false); 128 } 129 130 @MatchRule("(And=binary a (LeftShift=shift b Constant))") 131 @MatchRule("(And=binary a (RightShift=shift b Constant))") 132 @MatchRule("(And=binary a (UnsignedRightShift=shift b Constant))") 133 @MatchRule("(Or=binary a (LeftShift=shift b Constant))") 134 @MatchRule("(Or=binary a (RightShift=shift b Constant))") 135 @MatchRule("(Or=binary a (UnsignedRightShift=shift b Constant))") 136 @MatchRule("(Xor=binary a (LeftShift=shift b Constant))") 137 @MatchRule("(Xor=binary a (RightShift=shift b Constant))") 138 @MatchRule("(Xor=binary a (UnsignedRightShift=shift b Constant))") 139 @MatchRule("(And=binary a (Not (LeftShift=shift b Constant)))") 140 @MatchRule("(And=binary a (Not (RightShift=shift b Constant)))") 141 @MatchRule("(And=binary a (Not (UnsignedRightShift=shift b Constant)))") 142 @MatchRule("(Or=binary a (Not (LeftShift=shift b Constant)))") 143 @MatchRule("(Or=binary a (Not (RightShift=shift b Constant)))") 144 @MatchRule("(Or=binary a (Not (UnsignedRightShift=shift b Constant)))") 145 @MatchRule("(Xor=binary a (Not (LeftShift=shift b Constant)))") 146 @MatchRule("(Xor=binary a (Not (RightShift=shift b Constant)))") 147 @MatchRule("(Xor=binary a (Not (UnsignedRightShift=shift b Constant)))") 148 public ComplexMatchResult logicShift(BinaryNode binary, ValueNode a, BinaryNode shift) { 149 AArch64ArithmeticOp op = nodeOpMap.get(binary.getClass()); 150 assert op != null; 151 ValueNode operand = binary.getX() == a ? binary.getY() : binary.getX(); 152 boolean isShiftNot = operand instanceof NotNode; 153 return emitBinaryShift(op, a, shift, isShiftNot); 154 } 155 156 @MatchRule("(Mul (Negate a) b)") 157 @MatchRule("(Negate (Mul a b))") 158 public ComplexMatchResult multiplyNegate(ValueNode a, ValueNode b) { 159 if (a.getStackKind().isNumericInteger() && b.getStackKind().isNumericInteger()) { 160 return builder -> getArithmeticLIRGenerator().emitMNeg(operand(a), operand(b)); 161 } 162 return null; 163 } 164 165 @MatchRule("(Add=binary (Mul a b) c)") 166 @MatchRule("(Sub=binary c (Mul a b))") 167 public ComplexMatchResult multiplyAddSub(BinaryNode binary, ValueNode a, ValueNode b, ValueNode c) { 168 JavaKind kindA = a.getStackKind(); 169 JavaKind kindB = b.getStackKind(); 170 JavaKind kindC = c.getStackKind(); 171 if (!kindA.isNumericInteger() || !kindB.isNumericInteger() || !kindC.isNumericInteger()) { 172 return null; 173 } 174 175 if (binary instanceof AddNode) { 176 return builder -> getArithmeticLIRGenerator().emitMAdd(operand(a), operand(b), operand(c)); 177 } 178 return builder -> getArithmeticLIRGenerator().emitMSub(operand(a), operand(b), operand(c)); 179 } 180 181 @Override 182 public AArch64LIRGenerator getLIRGeneratorTool() { 183 return (AArch64LIRGenerator) gen; 184 } 185 186 protected AArch64ArithmeticLIRGenerator getArithmeticLIRGenerator() { 187 return (AArch64ArithmeticLIRGenerator) getLIRGeneratorTool().getArithmetic(); 188 } 189 }