1 /*
   2  * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright (c) 2018, Red Hat Inc. All rights reserved.
   4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5  *
   6  * This code is free software; you can redistribute it and/or modify it
   7  * under the terms of the GNU General Public License version 2 only, as
   8  * published by the Free Software Foundation.
   9  *
  10  * This code is distributed in the hope that it will be useful, but WITHOUT
  11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13  * version 2 for more details (a copy is included in the LICENSE file that
  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  */
  24 
  25 
  26 
  27 package org.graalvm.compiler.replacements.aarch64;
  28 
  29 import org.graalvm.compiler.api.replacements.Snippet;
  30 import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
  31 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
  32 import org.graalvm.compiler.core.common.type.IntegerStamp;
  33 import org.graalvm.compiler.debug.DebugHandlersFactory;
  34 import org.graalvm.compiler.debug.GraalError;
  35 import org.graalvm.compiler.graph.Node.NodeIntrinsic;
  36 import org.graalvm.compiler.graph.NodeClass;
  37 import org.graalvm.compiler.nodeinfo.NodeInfo;
  38 import org.graalvm.compiler.nodes.DeoptimizeNode;
  39 import org.graalvm.compiler.nodes.NodeView;
  40 import org.graalvm.compiler.nodes.StructuredGraph;
  41 import org.graalvm.compiler.nodes.ValueNode;
  42 import org.graalvm.compiler.nodes.calc.IntegerDivRemNode;
  43 import org.graalvm.compiler.nodes.calc.SignedDivNode;
  44 import org.graalvm.compiler.nodes.calc.SignedRemNode;
  45 import org.graalvm.compiler.nodes.calc.UnsignedDivNode;
  46 import org.graalvm.compiler.nodes.calc.UnsignedRemNode;
  47 import org.graalvm.compiler.nodes.extended.BranchProbabilityNode;
  48 import org.graalvm.compiler.nodes.spi.LoweringTool;
  49 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
  50 import org.graalvm.compiler.options.OptionValues;
  51 import org.graalvm.compiler.phases.util.Providers;
  52 import org.graalvm.compiler.replacements.SnippetTemplate;
  53 import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
  54 import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
  55 import org.graalvm.compiler.replacements.Snippets;
  56 
  57 import jdk.vm.ci.code.TargetDescription;
  58 import jdk.vm.ci.meta.DeoptimizationAction;
  59 import jdk.vm.ci.meta.DeoptimizationReason;
  60 import jdk.vm.ci.meta.JavaKind;
  61 
  62 /**
  63  * Division in AArch64 ISA does not generate a trap when dividing by zero, but instead sets the
  64  * result to 0. These snippets throw an ArithmethicException if the denominator is 0 and otherwise
  65  * forward to the LIRGenerator.
  66  */
  67 public class AArch64IntegerArithmeticSnippets extends AbstractTemplates implements Snippets {
  68 
  69     private final SnippetTemplate.SnippetInfo idiv;
  70     private final SnippetTemplate.SnippetInfo ldiv;
  71     private final SnippetTemplate.SnippetInfo irem;
  72     private final SnippetTemplate.SnippetInfo lrem;
  73 
  74     private final SnippetTemplate.SnippetInfo uidiv;
  75     private final SnippetTemplate.SnippetInfo uldiv;
  76     private final SnippetTemplate.SnippetInfo uirem;
  77     private final SnippetTemplate.SnippetInfo ulrem;
  78 
  79     public AArch64IntegerArithmeticSnippets(OptionValues options, Iterable<DebugHandlersFactory> factories, Providers providers, SnippetReflectionProvider snippetReflection,
  80                     TargetDescription target) {
  81         super(options, factories, providers, snippetReflection, target);
  82         idiv = snippet(AArch64IntegerArithmeticSnippets.class, "idivSnippet");
  83         ldiv = snippet(AArch64IntegerArithmeticSnippets.class, "ldivSnippet");
  84         irem = snippet(AArch64IntegerArithmeticSnippets.class, "iremSnippet");
  85         lrem = snippet(AArch64IntegerArithmeticSnippets.class, "lremSnippet");
  86 
  87         uidiv = snippet(AArch64IntegerArithmeticSnippets.class, "uidivSnippet");
  88         uldiv = snippet(AArch64IntegerArithmeticSnippets.class, "uldivSnippet");
  89         uirem = snippet(AArch64IntegerArithmeticSnippets.class, "uiremSnippet");
  90         ulrem = snippet(AArch64IntegerArithmeticSnippets.class, "ulremSnippet");
  91     }
  92 
  93     public void lower(IntegerDivRemNode node, LoweringTool tool) {
  94         JavaKind kind = node.stamp(NodeView.DEFAULT).getStackKind();
  95         assert kind == JavaKind.Int || kind == JavaKind.Long;
  96         SnippetTemplate.SnippetInfo snippet;
  97         if (node instanceof SafeNode) {
  98             // We already introduced the zero division check, nothing to do.
  99             return;
 100         } else if (node instanceof SignedDivNode) {
 101             snippet = kind == JavaKind.Int ? idiv : ldiv;
 102         } else if (node instanceof SignedRemNode) {
 103             snippet = kind == JavaKind.Int ? irem : lrem;
 104         } else if (node instanceof UnsignedDivNode) {
 105             snippet = kind == JavaKind.Int ? uidiv : uldiv;
 106         } else if (node instanceof UnsignedRemNode) {
 107             snippet = kind == JavaKind.Int ? uirem : ulrem;
 108         } else {
 109             throw GraalError.shouldNotReachHere();
 110         }
 111         StructuredGraph graph = node.graph();
 112         Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage());
 113         args.add("x", node.getX());
 114         args.add("y", node.getY());
 115 
 116         IntegerStamp yStamp = (IntegerStamp) node.getY().stamp(NodeView.DEFAULT);
 117         args.addConst("needsZeroCheck", node.getZeroCheck() == null && yStamp.contains(0));
 118 
 119         template(node, args).instantiate(providers.getMetaAccess(), node, SnippetTemplate.DEFAULT_REPLACER, args);
 120     }
 121 
 122     @Snippet
 123     public static int idivSnippet(int x, int y, @ConstantParameter boolean needsZeroCheck) {
 124         if (needsZeroCheck) {
 125             checkForZero(y);
 126         }
 127         return safeDiv(x, y);
 128     }
 129 
 130     @Snippet
 131     public static long ldivSnippet(long x, long y, @ConstantParameter boolean needsZeroCheck) {
 132         if (needsZeroCheck) {
 133             checkForZero(y);
 134         }
 135         return safeDiv(x, y);
 136     }
 137 
 138     @Snippet
 139     public static int iremSnippet(int x, int y, @ConstantParameter boolean needsZeroCheck) {
 140         if (needsZeroCheck) {
 141             checkForZero(y);
 142         }
 143         return safeRem(x, y);
 144     }
 145 
 146     @Snippet
 147     public static long lremSnippet(long x, long y, @ConstantParameter boolean needsZeroCheck) {
 148         if (needsZeroCheck) {
 149             checkForZero(y);
 150         }
 151         return safeRem(x, y);
 152     }
 153 
 154     @Snippet
 155     public static int uidivSnippet(int x, int y, @ConstantParameter boolean needsZeroCheck) {
 156         if (needsZeroCheck) {
 157             checkForZero(y);
 158         }
 159         return safeUDiv(x, y);
 160     }
 161 
 162     @Snippet
 163     public static long uldivSnippet(long x, long y, @ConstantParameter boolean needsZeroCheck) {
 164         if (needsZeroCheck) {
 165             checkForZero(y);
 166         }
 167         return safeUDiv(x, y);
 168     }
 169 
 170     @Snippet
 171     public static int uiremSnippet(int x, int y, @ConstantParameter boolean needsZeroCheck) {
 172         if (needsZeroCheck) {
 173             checkForZero(y);
 174         }
 175         return safeURem(x, y);
 176     }
 177 
 178     @Snippet
 179     public static long ulremSnippet(long x, long y, @ConstantParameter boolean needsZeroCheck) {
 180         if (needsZeroCheck) {
 181             checkForZero(y);
 182         }
 183         return safeURem(x, y);
 184     }
 185 
 186     private static void checkForZero(int y) {
 187         if (BranchProbabilityNode.probability(BranchProbabilityNode.DEOPT_PROBABILITY, y == 0)) {
 188             // "/ by zero"
 189             DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.ArithmeticException);
 190         }
 191     }
 192 
 193     private static void checkForZero(long y) {
 194         if (BranchProbabilityNode.probability(BranchProbabilityNode.DEOPT_PROBABILITY, y == 0)) {
 195             // "/ by zero"
 196             DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.ArithmeticException);
 197         }
 198     }
 199 
 200     @NodeIntrinsic(SafeSignedDivNode.class)
 201     private static native int safeDiv(int x, int y);
 202 
 203     @NodeIntrinsic(SafeSignedDivNode.class)
 204     private static native long safeDiv(long x, long y);
 205 
 206     @NodeIntrinsic(SafeSignedRemNode.class)
 207     private static native int safeRem(int x, int y);
 208 
 209     @NodeIntrinsic(SafeSignedRemNode.class)
 210     private static native long safeRem(long x, long y);
 211 
 212     @NodeIntrinsic(SafeUnsignedDivNode.class)
 213     private static native int safeUDiv(int x, int y);
 214 
 215     @NodeIntrinsic(SafeUnsignedDivNode.class)
 216     private static native long safeUDiv(long x, long y);
 217 
 218     @NodeIntrinsic(SafeUnsignedRemNode.class)
 219     private static native int safeURem(int x, int y);
 220 
 221     @NodeIntrinsic(SafeUnsignedRemNode.class)
 222     private static native long safeURem(long x, long y);
 223 
 224     /**
 225      * Marker interface to distinguish untreated nodes from ones where we have installed the
 226      * additional checks.
 227      */
 228     private interface SafeNode {
 229     }
 230 
 231     @NodeInfo
 232     static class SafeSignedDivNode extends SignedDivNode implements SafeNode {
 233         public static final NodeClass<SafeSignedDivNode> TYPE = NodeClass.create(SafeSignedDivNode.class);
 234 
 235         protected SafeSignedDivNode(ValueNode x, ValueNode y) {
 236             super(TYPE, x, y, null);
 237         }
 238 
 239         @Override
 240         public void generate(NodeLIRBuilderTool gen) {
 241             // override to ensure we always pass a null frame state
 242             // the parent method expects to create one from a non null before state
 243             gen.setResult(this, gen.getLIRGeneratorTool().getArithmetic().emitDiv(gen.operand(getX()), gen.operand(getY()), null));
 244         }
 245     }
 246 
 247     @NodeInfo
 248     static class SafeSignedRemNode extends SignedRemNode implements SafeNode {
 249         public static final NodeClass<SafeSignedRemNode> TYPE = NodeClass.create(SafeSignedRemNode.class);
 250 
 251         protected SafeSignedRemNode(ValueNode x, ValueNode y) {
 252             super(TYPE, x, y, null);
 253         }
 254 
 255         @Override
 256         public void generate(NodeLIRBuilderTool gen) {
 257             // override to ensure we always pass a null frame state
 258             // the parent method expects to create one from a non null before state
 259             gen.setResult(this, gen.getLIRGeneratorTool().getArithmetic().emitRem(gen.operand(getX()), gen.operand(getY()), null));
 260         }
 261     }
 262 
 263     @NodeInfo
 264     static class SafeUnsignedDivNode extends UnsignedDivNode implements SafeNode {
 265         public static final NodeClass<SafeUnsignedDivNode> TYPE = NodeClass.create(SafeUnsignedDivNode.class);
 266 
 267         protected SafeUnsignedDivNode(ValueNode x, ValueNode y) {
 268             super(TYPE, x, y, null);
 269         }
 270 
 271         @Override
 272         public void generate(NodeLIRBuilderTool gen) {
 273             // override to ensure we always pass a null frame state
 274             // the parent method expects to create one from a non null before state
 275             gen.setResult(this, gen.getLIRGeneratorTool().getArithmetic().emitUDiv(gen.operand(getX()), gen.operand(getY()), null));
 276         }
 277     }
 278 
 279     @NodeInfo
 280     static class SafeUnsignedRemNode extends UnsignedRemNode implements SafeNode {
 281         public static final NodeClass<SafeUnsignedRemNode> TYPE = NodeClass.create(SafeUnsignedRemNode.class);
 282 
 283         protected SafeUnsignedRemNode(ValueNode x, ValueNode y) {
 284             super(TYPE, x, y, null);
 285         }
 286 
 287         @Override
 288         public void generate(NodeLIRBuilderTool gen) {
 289             // override to ensure we always pass a null frame state
 290             // the parent method expects to create one from a non null before state
 291             gen.setResult(this, gen.getLIRGeneratorTool().getArithmetic().emitURem(gen.operand(getX()), gen.operand(getY()), null));
 292         }
 293     }
 294 
 295 }