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 }