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 }