1 /*
   2  * Copyright (c) 2014, 2018, 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.spi.LoweringTool;
  48 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
  49 import org.graalvm.compiler.options.OptionValues;
  50 import org.graalvm.compiler.phases.util.Providers;
  51 import org.graalvm.compiler.replacements.SnippetTemplate;
  52 import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
  53 import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
  54 import org.graalvm.compiler.replacements.Snippets;
  55 
  56 import jdk.vm.ci.code.TargetDescription;
  57 import jdk.vm.ci.meta.DeoptimizationAction;
  58 import jdk.vm.ci.meta.DeoptimizationReason;
  59 import jdk.vm.ci.meta.JavaKind;
  60 
  61 /**
  62  * Division in AArch64 ISA does not generate a trap when dividing by zero, but instead sets the
  63  * result to 0. These snippets throw an ArithmethicException if the denominator is 0 and otherwise
  64  * forward to the LIRGenerator.
  65  */
  66 public class AArch64IntegerArithmeticSnippets extends AbstractTemplates implements Snippets {
  67 
  68     private final SnippetTemplate.SnippetInfo idiv;
  69     private final SnippetTemplate.SnippetInfo ldiv;
  70     private final SnippetTemplate.SnippetInfo irem;
  71     private final SnippetTemplate.SnippetInfo lrem;
  72 
  73     private final SnippetTemplate.SnippetInfo uidiv;
  74     private final SnippetTemplate.SnippetInfo uldiv;
  75     private final SnippetTemplate.SnippetInfo uirem;
  76     private final SnippetTemplate.SnippetInfo ulrem;
  77 
  78     public AArch64IntegerArithmeticSnippets(OptionValues options, Iterable<DebugHandlersFactory> factories, Providers providers, SnippetReflectionProvider snippetReflection,
  79                     TargetDescription target) {
  80         super(options, factories, providers, snippetReflection, target);
  81         idiv = snippet(AArch64IntegerArithmeticSnippets.class, "idivSnippet");
  82         ldiv = snippet(AArch64IntegerArithmeticSnippets.class, "ldivSnippet");
  83         irem = snippet(AArch64IntegerArithmeticSnippets.class, "iremSnippet");
  84         lrem = snippet(AArch64IntegerArithmeticSnippets.class, "lremSnippet");
  85 
  86         uidiv = snippet(AArch64IntegerArithmeticSnippets.class, "uidivSnippet");
  87         uldiv = snippet(AArch64IntegerArithmeticSnippets.class, "uldivSnippet");
  88         uirem = snippet(AArch64IntegerArithmeticSnippets.class, "uiremSnippet");
  89         ulrem = snippet(AArch64IntegerArithmeticSnippets.class, "ulremSnippet");
  90     }
  91 
  92     public void lower(IntegerDivRemNode node, LoweringTool tool) {
  93         JavaKind kind = node.stamp(NodeView.DEFAULT).getStackKind();
  94         assert kind == JavaKind.Int || kind == JavaKind.Long;
  95         SnippetTemplate.SnippetInfo snippet;
  96         if (node instanceof SafeNode) {
  97             // We already introduced the zero division check, nothing to do.
  98             return;
  99         } else if (node instanceof SignedDivNode) {
 100             snippet = kind == JavaKind.Int ? idiv : ldiv;
 101         } else if (node instanceof SignedRemNode) {
 102             snippet = kind == JavaKind.Int ? irem : lrem;
 103         } else if (node instanceof UnsignedDivNode) {
 104             snippet = kind == JavaKind.Int ? uidiv : uldiv;
 105         } else if (node instanceof UnsignedRemNode) {
 106             snippet = kind == JavaKind.Int ? uirem : ulrem;
 107         } else {
 108             throw GraalError.shouldNotReachHere();
 109         }
 110         StructuredGraph graph = node.graph();
 111         Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage());
 112         args.add("x", node.getX());
 113         args.add("y", node.getY());
 114 
 115         IntegerStamp yStamp = (IntegerStamp) node.getY().stamp(NodeView.DEFAULT);
 116         args.addConst("needsZeroCheck", node.getZeroCheck() == null && yStamp.contains(0));
 117 
 118         template(node, args).instantiate(providers.getMetaAccess(), node, SnippetTemplate.DEFAULT_REPLACER, args);
 119     }
 120 
 121     @Snippet
 122     public static int idivSnippet(int x, int y, @ConstantParameter boolean needsZeroCheck) {
 123         if (needsZeroCheck) {
 124             checkForZero(y);
 125         }
 126         return safeDiv(x, y);
 127     }
 128 
 129     @Snippet
 130     public static long ldivSnippet(long x, long y, @ConstantParameter boolean needsZeroCheck) {
 131         if (needsZeroCheck) {
 132             checkForZero(y);
 133         }
 134         return safeDiv(x, y);
 135     }
 136 
 137     @Snippet
 138     public static int iremSnippet(int x, int y, @ConstantParameter boolean needsZeroCheck) {
 139         if (needsZeroCheck) {
 140             checkForZero(y);
 141         }
 142         return safeRem(x, y);
 143     }
 144 
 145     @Snippet
 146     public static long lremSnippet(long x, long y, @ConstantParameter boolean needsZeroCheck) {
 147         if (needsZeroCheck) {
 148             checkForZero(y);
 149         }
 150         return safeRem(x, y);
 151     }
 152 
 153     @Snippet
 154     public static int uidivSnippet(int x, int y, @ConstantParameter boolean needsZeroCheck) {
 155         if (needsZeroCheck) {
 156             checkForZero(y);
 157         }
 158         return safeUDiv(x, y);
 159     }
 160 
 161     @Snippet
 162     public static long uldivSnippet(long x, long y, @ConstantParameter boolean needsZeroCheck) {
 163         if (needsZeroCheck) {
 164             checkForZero(y);
 165         }
 166         return safeUDiv(x, y);
 167     }
 168 
 169     @Snippet
 170     public static int uiremSnippet(int x, int y, @ConstantParameter boolean needsZeroCheck) {
 171         if (needsZeroCheck) {
 172             checkForZero(y);
 173         }
 174         return safeURem(x, y);
 175     }
 176 
 177     @Snippet
 178     public static long ulremSnippet(long x, long y, @ConstantParameter boolean needsZeroCheck) {
 179         if (needsZeroCheck) {
 180             checkForZero(y);
 181         }
 182         return safeURem(x, y);
 183     }
 184 
 185     private static void checkForZero(int y) {
 186         if (y == 0) {
 187             // "/ by zero"
 188             DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.ArithmeticException);
 189         }
 190     }
 191 
 192     private static void checkForZero(long y) {
 193         if (y == 0) {
 194             // "/ by zero"
 195             DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.ArithmeticException);
 196         }
 197     }
 198 
 199     @NodeIntrinsic(SafeSignedDivNode.class)
 200     private static native int safeDiv(int x, int y);
 201 
 202     @NodeIntrinsic(SafeSignedDivNode.class)
 203     private static native long safeDiv(long x, long y);
 204 
 205     @NodeIntrinsic(SafeSignedRemNode.class)
 206     private static native int safeRem(int x, int y);
 207 
 208     @NodeIntrinsic(SafeSignedRemNode.class)
 209     private static native long safeRem(long x, long y);
 210 
 211     @NodeIntrinsic(SafeUnsignedDivNode.class)
 212     private static native int safeUDiv(int x, int y);
 213 
 214     @NodeIntrinsic(SafeUnsignedDivNode.class)
 215     private static native long safeUDiv(long x, long y);
 216 
 217     @NodeIntrinsic(SafeUnsignedRemNode.class)
 218     private static native int safeURem(int x, int y);
 219 
 220     @NodeIntrinsic(SafeUnsignedRemNode.class)
 221     private static native long safeURem(long x, long y);
 222 
 223     /**
 224      * Marker interface to distinguish untreated nodes from ones where we have installed the
 225      * additional checks.
 226      */
 227     private interface SafeNode {
 228     }
 229 
 230     @NodeInfo
 231     static class SafeSignedDivNode extends SignedDivNode implements SafeNode {
 232         public static final NodeClass<SafeSignedDivNode> TYPE = NodeClass.create(SafeSignedDivNode.class);
 233 
 234         protected SafeSignedDivNode(ValueNode x, ValueNode y) {
 235             super(TYPE, x, y, null);
 236         }
 237 
 238         @Override
 239         public void generate(NodeLIRBuilderTool gen) {
 240             // override to ensure we always pass a null frame state
 241             // the parent method expects to create one from a non null before state
 242             gen.setResult(this, gen.getLIRGeneratorTool().getArithmetic().emitDiv(gen.operand(getX()), gen.operand(getY()), null));
 243         }
 244     }
 245 
 246     @NodeInfo
 247     static class SafeSignedRemNode extends SignedRemNode implements SafeNode {
 248         public static final NodeClass<SafeSignedRemNode> TYPE = NodeClass.create(SafeSignedRemNode.class);
 249 
 250         protected SafeSignedRemNode(ValueNode x, ValueNode y) {
 251             super(TYPE, x, y, null);
 252         }
 253 
 254         @Override
 255         public void generate(NodeLIRBuilderTool gen) {
 256             // override to ensure we always pass a null frame state
 257             // the parent method expects to create one from a non null before state
 258             gen.setResult(this, gen.getLIRGeneratorTool().getArithmetic().emitRem(gen.operand(getX()), gen.operand(getY()), null));
 259         }
 260     }
 261 
 262     @NodeInfo
 263     static class SafeUnsignedDivNode extends UnsignedDivNode implements SafeNode {
 264         public static final NodeClass<SafeUnsignedDivNode> TYPE = NodeClass.create(SafeUnsignedDivNode.class);
 265 
 266         protected SafeUnsignedDivNode(ValueNode x, ValueNode y) {
 267             super(TYPE, x, y, null);
 268         }
 269 
 270         @Override
 271         public void generate(NodeLIRBuilderTool gen) {
 272             // override to ensure we always pass a null frame state
 273             // the parent method expects to create one from a non null before state
 274             gen.setResult(this, gen.getLIRGeneratorTool().getArithmetic().emitUDiv(gen.operand(getX()), gen.operand(getY()), null));
 275         }
 276     }
 277 
 278     @NodeInfo
 279     static class SafeUnsignedRemNode extends UnsignedRemNode implements SafeNode {
 280         public static final NodeClass<SafeUnsignedRemNode> TYPE = NodeClass.create(SafeUnsignedRemNode.class);
 281 
 282         protected SafeUnsignedRemNode(ValueNode x, ValueNode y) {
 283             super(TYPE, x, y, null);
 284         }
 285 
 286         @Override
 287         public void generate(NodeLIRBuilderTool gen) {
 288             // override to ensure we always pass a null frame state
 289             // the parent method expects to create one from a non null before state
 290             gen.setResult(this, gen.getLIRGeneratorTool().getArithmetic().emitURem(gen.operand(getX()), gen.operand(getY()), null));
 291         }
 292     }
 293 
 294 }