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 }