1 /*
   2  * Copyright (c) 2014, 2016, 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 package org.graalvm.compiler.replacements.aarch64;
  25 
  26 import org.graalvm.compiler.api.replacements.Snippet;
  27 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
  28 import org.graalvm.compiler.debug.GraalError;
  29 import org.graalvm.compiler.graph.Node.NodeIntrinsic;
  30 import org.graalvm.compiler.graph.NodeClass;
  31 import org.graalvm.compiler.nodeinfo.NodeInfo;
  32 import org.graalvm.compiler.nodes.DeoptimizeNode;
  33 import org.graalvm.compiler.nodes.StructuredGraph;
  34 import org.graalvm.compiler.nodes.ValueNode;
  35 import org.graalvm.compiler.nodes.calc.FixedBinaryNode;
  36 import org.graalvm.compiler.nodes.calc.SignedDivNode;
  37 import org.graalvm.compiler.nodes.calc.SignedRemNode;
  38 import org.graalvm.compiler.nodes.calc.UnsignedDivNode;
  39 import org.graalvm.compiler.nodes.calc.UnsignedRemNode;
  40 import org.graalvm.compiler.nodes.spi.LoweringTool;
  41 import org.graalvm.compiler.phases.util.Providers;
  42 import org.graalvm.compiler.replacements.SnippetTemplate;
  43 import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
  44 import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
  45 import org.graalvm.compiler.replacements.Snippets;
  46 
  47 import jdk.vm.ci.code.TargetDescription;
  48 import jdk.vm.ci.meta.DeoptimizationAction;
  49 import jdk.vm.ci.meta.DeoptimizationReason;
  50 import jdk.vm.ci.meta.JavaKind;
  51 
  52 /**
  53  * Division in AArch64 ISA does not generate a trap when dividing by zero, but instead sets the
  54  * result to 0. These snippets throw an ArithmethicException if the denominator is 0 and otherwise
  55  * forward to the LIRGenerator.
  56  */
  57 public class AArch64IntegerArithmeticSnippets extends AbstractTemplates implements Snippets {
  58 
  59     private final SnippetTemplate.SnippetInfo idiv;
  60     private final SnippetTemplate.SnippetInfo ldiv;
  61     private final SnippetTemplate.SnippetInfo irem;
  62     private final SnippetTemplate.SnippetInfo lrem;
  63 
  64     private final SnippetTemplate.SnippetInfo uidiv;
  65     private final SnippetTemplate.SnippetInfo uldiv;
  66     private final SnippetTemplate.SnippetInfo uirem;
  67     private final SnippetTemplate.SnippetInfo ulrem;
  68 
  69     public AArch64IntegerArithmeticSnippets(Providers providers, SnippetReflectionProvider snippetReflection, TargetDescription target) {
  70         super(providers, snippetReflection, target);
  71         idiv = snippet(AArch64IntegerArithmeticSnippets.class, "idivSnippet");
  72         ldiv = snippet(AArch64IntegerArithmeticSnippets.class, "ldivSnippet");
  73         irem = snippet(AArch64IntegerArithmeticSnippets.class, "iremSnippet");
  74         lrem = snippet(AArch64IntegerArithmeticSnippets.class, "lremSnippet");
  75 
  76         uidiv = snippet(AArch64IntegerArithmeticSnippets.class, "uidivSnippet");
  77         uldiv = snippet(AArch64IntegerArithmeticSnippets.class, "uldivSnippet");
  78         uirem = snippet(AArch64IntegerArithmeticSnippets.class, "uiremSnippet");
  79         ulrem = snippet(AArch64IntegerArithmeticSnippets.class, "ulremSnippet");
  80     }
  81 
  82     public void lower(FixedBinaryNode node, LoweringTool tool) {
  83         JavaKind kind = node.stamp().getStackKind();
  84         assert kind == JavaKind.Int || kind == JavaKind.Long;
  85         SnippetTemplate.SnippetInfo snippet;
  86         if (node instanceof SafeNode) {
  87             // We already introduced the zero division check, nothing to do.
  88             return;
  89         } else if (node instanceof SignedDivNode) {
  90             snippet = kind == JavaKind.Int ? idiv : ldiv;
  91         } else if (node instanceof SignedRemNode) {
  92             snippet = kind == JavaKind.Int ? irem : lrem;
  93         } else if (node instanceof UnsignedDivNode) {
  94             snippet = kind == JavaKind.Int ? uidiv : uldiv;
  95         } else if (node instanceof UnsignedRemNode) {
  96             snippet = kind == JavaKind.Int ? uirem : ulrem;
  97         } else {
  98             throw GraalError.shouldNotReachHere();
  99         }
 100         StructuredGraph graph = node.graph();
 101         Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage());
 102         args.add("x", node.getX());
 103         args.add("y", node.getY());
 104         template(args).instantiate(providers.getMetaAccess(), node, SnippetTemplate.DEFAULT_REPLACER, args);
 105     }
 106 
 107     @Snippet
 108     public static int idivSnippet(int x, int y) {
 109         checkForZero(y);
 110         return safeDiv(x, y);
 111     }
 112 
 113     @Snippet
 114     public static long ldivSnippet(long x, long y) {
 115         checkForZero(y);
 116         return safeDiv(x, y);
 117     }
 118 
 119     @Snippet
 120     public static int iremSnippet(int x, int y) {
 121         checkForZero(y);
 122         return safeRem(x, y);
 123     }
 124 
 125     @Snippet
 126     public static long lremSnippet(long x, long y) {
 127         checkForZero(y);
 128         return safeRem(x, y);
 129     }
 130 
 131     @Snippet
 132     public static int uidivSnippet(int x, int y) {
 133         checkForZero(y);
 134         return safeUDiv(x, y);
 135     }
 136 
 137     @Snippet
 138     public static long uldivSnippet(long x, long y) {
 139         checkForZero(y);
 140         return safeUDiv(x, y);
 141     }
 142 
 143     @Snippet
 144     public static int uiremSnippet(int x, int y) {
 145         checkForZero(y);
 146         return safeURem(x, y);
 147     }
 148 
 149     @Snippet
 150     public static long ulremSnippet(long x, long y) {
 151         checkForZero(y);
 152         return safeURem(x, y);
 153     }
 154 
 155     private static void checkForZero(int y) {
 156         if (y == 0) {
 157             // "/ by zero"
 158             DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.ArithmeticException);
 159         }
 160     }
 161 
 162     private static void checkForZero(long y) {
 163         if (y == 0) {
 164             // "/ by zero"
 165             DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.ArithmeticException);
 166         }
 167     }
 168 
 169     @NodeIntrinsic(SafeSignedDivNode.class)
 170     private static native int safeDiv(int x, int y);
 171 
 172     @NodeIntrinsic(SafeSignedDivNode.class)
 173     private static native long safeDiv(long x, long y);
 174 
 175     @NodeIntrinsic(SafeSignedRemNode.class)
 176     private static native int safeRem(int x, int y);
 177 
 178     @NodeIntrinsic(SafeSignedRemNode.class)
 179     private static native long safeRem(long x, long y);
 180 
 181     @NodeIntrinsic(SafeUnsignedDivNode.class)
 182     private static native int safeUDiv(int x, int y);
 183 
 184     @NodeIntrinsic(SafeUnsignedDivNode.class)
 185     private static native long safeUDiv(long x, long y);
 186 
 187     @NodeIntrinsic(SafeUnsignedRemNode.class)
 188     private static native int safeURem(int x, int y);
 189 
 190     @NodeIntrinsic(SafeUnsignedRemNode.class)
 191     private static native long safeURem(long x, long y);
 192 
 193     /**
 194      * Marker interface to distinguish untreated nodes from ones where we have installed the
 195      * additional checks.
 196      */
 197     private interface SafeNode {
 198     }
 199 
 200     @NodeInfo
 201     static class SafeSignedDivNode extends SignedDivNode implements SafeNode {
 202         public static final NodeClass<SafeSignedDivNode> TYPE = NodeClass.create(SafeSignedDivNode.class);
 203 
 204         protected SafeSignedDivNode(ValueNode x, ValueNode y) {
 205             super(TYPE, x, y);
 206         }
 207     }
 208 
 209     @NodeInfo
 210     static class SafeSignedRemNode extends SignedRemNode implements SafeNode {
 211         public static final NodeClass<SafeSignedRemNode> TYPE = NodeClass.create(SafeSignedRemNode.class);
 212 
 213         protected SafeSignedRemNode(ValueNode x, ValueNode y) {
 214             super(TYPE, x, y);
 215         }
 216     }
 217 
 218     @NodeInfo
 219     static class SafeUnsignedDivNode extends UnsignedDivNode implements SafeNode {
 220         public static final NodeClass<SafeUnsignedDivNode> TYPE = NodeClass.create(SafeUnsignedDivNode.class);
 221 
 222         protected SafeUnsignedDivNode(ValueNode x, ValueNode y) {
 223             super(TYPE, x, y);
 224         }
 225     }
 226 
 227     @NodeInfo
 228     static class SafeUnsignedRemNode extends UnsignedRemNode implements SafeNode {
 229         public static final NodeClass<SafeUnsignedRemNode> TYPE = NodeClass.create(SafeUnsignedRemNode.class);
 230 
 231         protected SafeUnsignedRemNode(ValueNode x, ValueNode y) {
 232             super(TYPE, x, y);
 233         }
 234     }
 235 
 236 }