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.LabelRef; 41 import org.graalvm.compiler.lir.Variable; 42 import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp; 43 import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow; 44 import org.graalvm.compiler.lir.gen.LIRGeneratorTool; 45 import org.graalvm.compiler.nodes.ConstantNode; 46 import org.graalvm.compiler.nodes.DeoptimizingNode; 47 import org.graalvm.compiler.nodes.IfNode; 48 import org.graalvm.compiler.nodes.NodeView; 49 import org.graalvm.compiler.nodes.ValueNode; 50 import org.graalvm.compiler.nodes.calc.AddNode; 51 import org.graalvm.compiler.nodes.calc.AndNode; 52 import org.graalvm.compiler.nodes.calc.BinaryNode; 53 import org.graalvm.compiler.nodes.calc.LeftShiftNode; 54 import org.graalvm.compiler.nodes.calc.NotNode; 55 import org.graalvm.compiler.nodes.calc.OrNode; 56 import org.graalvm.compiler.nodes.calc.RightShiftNode; 57 import org.graalvm.compiler.nodes.calc.SubNode; 58 import org.graalvm.compiler.nodes.calc.UnsignedRightShiftNode; 59 import org.graalvm.compiler.nodes.calc.XorNode; 60 import org.graalvm.compiler.nodes.memory.Access; 61 62 import jdk.vm.ci.aarch64.AArch64Kind; 63 64 public class AArch64NodeMatchRules extends NodeMatchRules { 65 private static final EconomicMap<Class<? extends Node>, AArch64ArithmeticOp> nodeOpMap; 66 67 private static final EconomicMap<Class<? extends BinaryNode>, AArch64MacroAssembler.ShiftType> shiftTypeMap; 68 69 static { 70 nodeOpMap = EconomicMap.create(Equivalence.IDENTITY, 5); 71 nodeOpMap.put(AddNode.class, AArch64ArithmeticOp.ADD); 72 nodeOpMap.put(SubNode.class, AArch64ArithmeticOp.SUB); 73 nodeOpMap.put(AndNode.class, AArch64ArithmeticOp.AND); 74 nodeOpMap.put(OrNode.class, AArch64ArithmeticOp.OR); 75 nodeOpMap.put(XorNode.class, AArch64ArithmeticOp.XOR); 76 77 shiftTypeMap = EconomicMap.create(Equivalence.IDENTITY, 3); 78 shiftTypeMap.put(LeftShiftNode.class, AArch64MacroAssembler.ShiftType.LSL); 79 shiftTypeMap.put(RightShiftNode.class, AArch64MacroAssembler.ShiftType.ASR); 80 shiftTypeMap.put(UnsignedRightShiftNode.class, AArch64MacroAssembler.ShiftType.LSR); 81 } 82 83 public AArch64NodeMatchRules(LIRGeneratorTool gen) { 84 super(gen); 85 } 86 87 protected LIRFrameState getState(Access access) { 88 if (access instanceof DeoptimizingNode) { 89 return state((DeoptimizingNode) access); 90 } 91 return null; 92 } 93 94 protected AArch64Kind getMemoryKind(Access access) { 95 return (AArch64Kind) gen.getLIRKind(access.asNode().stamp(NodeView.DEFAULT)).getPlatformKind(); 96 } 97 98 private AllocatableValue moveSp(AllocatableValue value) { 99 return getLIRGeneratorTool().moveSp(value); 100 } 101 102 private ComplexMatchResult emitBinaryShift(AArch64ArithmeticOp op, ValueNode value, BinaryNode shift, boolean isShiftNot) { 103 AArch64MacroAssembler.ShiftType shiftType = shiftTypeMap.get(shift.getClass()); 104 assert shiftType != null; 105 assert value.getStackKind().isNumericInteger(); 106 assert shift.getX().getStackKind().isNumericInteger(); 107 assert shift.getY() instanceof ConstantNode; 108 109 return builder -> { 110 Value a = operand(value); 111 Value b = operand(shift.getX()); 112 Variable result = gen.newVariable(LIRKind.combine(a, b)); 113 AllocatableValue x = moveSp(gen.asAllocatable(a)); 114 AllocatableValue y = moveSp(gen.asAllocatable(b)); 115 int shiftAmount = shift.getY().asJavaConstant().asInt(); 116 gen.append(new AArch64ArithmeticOp.BinaryShiftOp(op, result, x, y, shiftType, shiftAmount, isShiftNot)); 117 return result; 118 }; 119 } 120 121 @MatchRule("(Add=binary a (LeftShift=shift b Constant))") 122 @MatchRule("(Add=binary a (RightShift=shift b Constant))") 123 @MatchRule("(Add=binary a (UnsignedRightShift=shift b Constant))") 124 @MatchRule("(Sub=binary a (LeftShift=shift b Constant))") 125 @MatchRule("(Sub=binary a (RightShift=shift b Constant))") 126 @MatchRule("(Sub=binary a (UnsignedRightShift=shift b Constant))") 127 public ComplexMatchResult addSubShift(BinaryNode binary, ValueNode a, BinaryNode shift) { 128 AArch64ArithmeticOp op = nodeOpMap.get(binary.getClass()); 129 assert op != null; 130 return emitBinaryShift(op, a, shift, false); 131 } 132 133 @MatchRule("(And=binary a (LeftShift=shift b Constant))") 134 @MatchRule("(And=binary a (RightShift=shift b Constant))") 135 @MatchRule("(And=binary a (UnsignedRightShift=shift b Constant))") 136 @MatchRule("(Or=binary a (LeftShift=shift b Constant))") 137 @MatchRule("(Or=binary a (RightShift=shift b Constant))") 138 @MatchRule("(Or=binary a (UnsignedRightShift=shift b Constant))") 139 @MatchRule("(Xor=binary a (LeftShift=shift b Constant))") 140 @MatchRule("(Xor=binary a (RightShift=shift b Constant))") 141 @MatchRule("(Xor=binary a (UnsignedRightShift=shift b Constant))") 142 @MatchRule("(And=binary a (Not (LeftShift=shift b Constant)))") 143 @MatchRule("(And=binary a (Not (RightShift=shift b Constant)))") 144 @MatchRule("(And=binary a (Not (UnsignedRightShift=shift b Constant)))") 145 @MatchRule("(Or=binary a (Not (LeftShift=shift b Constant)))") 146 @MatchRule("(Or=binary a (Not (RightShift=shift b Constant)))") 147 @MatchRule("(Or=binary a (Not (UnsignedRightShift=shift b Constant)))") 148 @MatchRule("(Xor=binary a (Not (LeftShift=shift b Constant)))") 149 @MatchRule("(Xor=binary a (Not (RightShift=shift b Constant)))") 150 @MatchRule("(Xor=binary a (Not (UnsignedRightShift=shift b Constant)))") 151 public ComplexMatchResult logicShift(BinaryNode binary, ValueNode a, BinaryNode shift) { 152 AArch64ArithmeticOp op = nodeOpMap.get(binary.getClass()); 153 assert op != null; 154 ValueNode operand = binary.getX() == a ? binary.getY() : binary.getX(); 155 boolean isShiftNot = operand instanceof NotNode; 156 return emitBinaryShift(op, a, shift, isShiftNot); 157 } 158 159 @MatchRule("(Mul (Negate a) b)") 160 @MatchRule("(Negate (Mul a b))") 161 public ComplexMatchResult multiplyNegate(ValueNode a, ValueNode b) { 162 if (a.getStackKind().isNumericInteger() && b.getStackKind().isNumericInteger()) { 163 return builder -> getArithmeticLIRGenerator().emitMNeg(operand(a), operand(b)); 164 } 165 return null; 166 } 167 168 @MatchRule("(Add=binary (Mul a b) c)") 169 @MatchRule("(Sub=binary c (Mul a b))") 170 public ComplexMatchResult multiplyAddSub(BinaryNode binary, ValueNode a, ValueNode b, ValueNode c) { 171 JavaKind kindA = a.getStackKind(); 172 JavaKind kindB = b.getStackKind(); 173 JavaKind kindC = c.getStackKind(); 174 if (!kindA.isNumericInteger() || !kindB.isNumericInteger() || !kindC.isNumericInteger()) { 175 return null; 176 } 177 178 if (binary instanceof AddNode) { 179 return builder -> getArithmeticLIRGenerator().emitMAdd(operand(a), operand(b), operand(c)); 180 } 181 return builder -> getArithmeticLIRGenerator().emitMSub(operand(a), operand(b), operand(c)); 182 } 183 184 /** 185 * ((x & (1 << n)) == 0) -> tbz/tbnz n label. 186 */ 187 @MatchRule("(If (IntegerTest value Constant=a))") 188 public ComplexMatchResult testBitAndBranch(IfNode root, ValueNode value, ConstantNode a) { 189 if (value.getStackKind().isNumericInteger()) { 190 long constant = a.asJavaConstant().asLong(); 191 if (Long.bitCount(constant) == 1) { 192 int bitToTest = Long.numberOfTrailingZeros(constant); 193 return builder -> { 194 LabelRef trueDestination = getLIRBlock(root.trueSuccessor()); 195 LabelRef falseDestination = getLIRBlock(root.falseSuccessor()); 196 AllocatableValue src = moveSp(gen.asAllocatable(operand(value))); 197 double trueDestinationProbability = root.getTrueSuccessorProbability(); 198 gen.append(new AArch64ControlFlow.BitTestAndBranchOp(trueDestination, falseDestination, src, trueDestinationProbability, bitToTest)); 199 return null; 200 }; 201 } 202 } 203 return null; 204 } 205 206 @Override 207 public AArch64LIRGenerator getLIRGeneratorTool() { 208 return (AArch64LIRGenerator) gen; 209 } 210 211 protected AArch64ArithmeticLIRGenerator getArithmeticLIRGenerator() { 212 return (AArch64ArithmeticLIRGenerator) getLIRGeneratorTool().getArithmetic(); 213 } 214 }