1 /* 2 * Copyright (c) 2014, 2015, 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 static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED; 27 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED; 28 29 import org.graalvm.compiler.api.replacements.Snippet; 30 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; 31 import org.graalvm.compiler.graph.Node.NodeIntrinsic; 32 import org.graalvm.compiler.graph.NodeClass; 33 import org.graalvm.compiler.nodeinfo.NodeInfo; 34 import org.graalvm.compiler.nodes.StructuredGraph; 35 import org.graalvm.compiler.nodes.ValueNode; 36 import org.graalvm.compiler.nodes.calc.RemNode; 37 import org.graalvm.compiler.nodes.spi.LoweringTool; 38 import org.graalvm.compiler.options.OptionValues; 39 import org.graalvm.compiler.phases.util.Providers; 40 import org.graalvm.compiler.replacements.SnippetTemplate; 41 import org.graalvm.compiler.replacements.SnippetTemplate.Arguments; 42 import org.graalvm.compiler.replacements.Snippets; 43 44 import jdk.vm.ci.code.TargetDescription; 45 import jdk.vm.ci.meta.JavaKind; 46 47 /** 48 * AArch64 does not have a remainder operation. We use <code>n % d == n - Truncate(n / d) * d</code> 49 * for it instead. This is not correct for some edge cases, so we have to fix it up using these 50 * snippets. 51 */ 52 public class AArch64FloatArithmeticSnippets extends SnippetTemplate.AbstractTemplates implements Snippets { 53 54 private final SnippetTemplate.SnippetInfo drem; 55 private final SnippetTemplate.SnippetInfo frem; 56 57 public AArch64FloatArithmeticSnippets(OptionValues options, Providers providers, SnippetReflectionProvider snippetReflection, TargetDescription target) { 58 super(options, providers, snippetReflection, target); 59 drem = snippet(AArch64FloatArithmeticSnippets.class, "dremSnippet"); 60 frem = snippet(AArch64FloatArithmeticSnippets.class, "fremSnippet"); 61 } 62 63 public void lower(RemNode node, LoweringTool tool) { 64 JavaKind kind = node.stamp().getStackKind(); 65 assert kind == JavaKind.Float || kind == JavaKind.Double; 66 if (node instanceof SafeNode) { 67 // We already introduced the necessary checks, nothing to do. 68 return; 69 } 70 SnippetTemplate.SnippetInfo snippet = kind == JavaKind.Float ? frem : drem; 71 StructuredGraph graph = node.graph(); 72 Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage()); 73 args.add("x", node.getX()); 74 args.add("y", node.getY()); 75 template(args).instantiate(providers.getMetaAccess(), node, SnippetTemplate.DEFAULT_REPLACER, tool, args); 76 } 77 78 @Snippet 79 public static float fremSnippet(float x, float y) { 80 // JVMS: If either value1' or value2' is NaN, the result is NaN. 81 // JVMS: If the dividend is an infinity or the divisor is a zero or both, the result is NaN. 82 if (Float.isInfinite(x) || y == 0.0f || Float.isNaN(y)) { 83 return Float.NaN; 84 } 85 // JVMS: If the dividend is finite and the divisor is an infinity, the result equals the 86 // dividend. 87 // JVMS: If the dividend is a zero and the divisor is finite, the result equals the 88 // dividend. 89 if (x == 0.0f || Float.isInfinite(y)) { 90 return x; 91 } 92 93 float result = safeRem(x, y); 94 95 // JVMS: If neither value1' nor value2' is NaN, the sign of the result equals the sign of 96 // the dividend. 97 if (result == 0.0f && x < 0.0f) { 98 return -result; 99 } 100 return result; 101 } 102 103 @Snippet 104 public static double dremSnippet(double x, double y) { 105 // JVMS: If either value1' or value2' is NaN, the result is NaN. 106 // JVMS: If the dividend is an infinity or the divisor is a zero or both, the result is NaN. 107 if (Double.isInfinite(x) || y == 0.0 || Double.isNaN(y)) { 108 return Double.NaN; 109 } 110 // JVMS: If the dividend is finite and the divisor is an infinity, the result equals the 111 // dividend. 112 // JVMS: If the dividend is a zero and the divisor is finite, the result equals the 113 // dividend. 114 if (x == 0.0 || Double.isInfinite(y)) { 115 return x; 116 } 117 118 double result = safeRem(x, y); 119 120 // JVMS: If neither value1' nor value2' is NaN, the sign of the result equals the sign of 121 // the dividend. 122 if (result == 0.0 && x < 0.0) { 123 return -result; 124 } 125 return result; 126 } 127 128 @NodeIntrinsic(SafeFloatRemNode.class) 129 private static native float safeRem(float x, float y); 130 131 @NodeIntrinsic(SafeFloatRemNode.class) 132 private static native double safeRem(double x, double y); 133 134 /** 135 * Marker interface to distinguish untreated nodes from ones where we have installed the 136 * additional checks. 137 */ 138 private interface SafeNode { 139 } 140 141 @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED) 142 // static class SafeFloatRemNode extends FloatRemNode implements SafeNode { 143 static class SafeFloatRemNode extends RemNode implements SafeNode { 144 public static final NodeClass<SafeFloatRemNode> TYPE = NodeClass.create(SafeFloatRemNode.class); 145 146 protected SafeFloatRemNode(ValueNode x, ValueNode y) { 147 super(TYPE, x, y); 148 } 149 } 150 151 }