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