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 }