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