1 /* 2 * Copyright (c) 2013, 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 package org.graalvm.compiler.replacements.amd64; 24 25 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.SLOW_PATH_PROBABILITY; 26 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability; 27 import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER; 28 29 import org.graalvm.compiler.api.replacements.Snippet; 30 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; 31 import org.graalvm.compiler.debug.Debug; 32 import org.graalvm.compiler.nodes.StructuredGraph; 33 import org.graalvm.compiler.nodes.calc.FloatConvertNode; 34 import org.graalvm.compiler.nodes.spi.LoweringTool; 35 import org.graalvm.compiler.phases.util.Providers; 36 import org.graalvm.compiler.replacements.SnippetTemplate; 37 import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates; 38 import org.graalvm.compiler.replacements.SnippetTemplate.Arguments; 39 import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo; 40 import org.graalvm.compiler.replacements.Snippets; 41 42 import jdk.vm.ci.code.TargetDescription; 43 44 /** 45 * Snippets used for conversion operations on AMD64 where the AMD64 instruction used does not match 46 * the semantics of the JVM specification. 47 */ 48 public class AMD64ConvertSnippets implements Snippets { 49 50 /** 51 * Converts a float to an int. 52 * <p> 53 * This snippet accounts for the semantics of the x64 CVTTSS2SI instruction used to do the 54 * conversion. If the float value is a NaN, infinity or if the result of the conversion is 55 * larger than {@link Integer#MAX_VALUE} then CVTTSS2SI returns {@link Integer#MIN_VALUE} and 56 * extra tests are required on the float value to return the correct int value. 57 * 58 * @param input the float being converted 59 * @param result the result produced by the CVTTSS2SI instruction 60 */ 61 @Snippet 62 public static int f2i(float input, int result) { 63 if (probability(SLOW_PATH_PROBABILITY, result == Integer.MIN_VALUE)) { 64 if (Float.isNaN(input)) { 65 // input is NaN -> return 0 66 return 0; 67 } else if (input > 0.0f) { 68 // input is > 0 -> return max int 69 return Integer.MAX_VALUE; 70 } 71 } 72 return result; 73 } 74 75 /** 76 * Converts a float to a long. 77 * <p> 78 * This snippet accounts for the semantics of the x64 CVTTSS2SI instruction used to do the 79 * conversion. If the float value is a NaN or infinity then CVTTSS2SI returns 80 * {@link Long#MIN_VALUE} and extra tests are required on the float value to return the correct 81 * long value. 82 * 83 * @param input the float being converted 84 * @param result the result produced by the CVTTSS2SI instruction 85 */ 86 @Snippet 87 public static long f2l(float input, long result) { 88 if (probability(SLOW_PATH_PROBABILITY, result == Long.MIN_VALUE)) { 89 if (Float.isNaN(input)) { 90 // input is NaN -> return 0 91 return 0; 92 } else if (input > 0.0f) { 93 // input is > 0 -> return max int 94 return Long.MAX_VALUE; 95 } 96 } 97 return result; 98 } 99 100 /** 101 * Converts a double to an int. 102 * <p> 103 * This snippet accounts for the semantics of the x64 CVTTSD2SI instruction used to do the 104 * conversion. If the double value is a NaN, infinity or if the result of the conversion is 105 * larger than {@link Integer#MAX_VALUE} then CVTTSD2SI returns {@link Integer#MIN_VALUE} and 106 * extra tests are required on the double value to return the correct int value. 107 * 108 * @param input the double being converted 109 * @param result the result produced by the CVTTSS2SI instruction 110 */ 111 @Snippet 112 public static int d2i(double input, int result) { 113 if (probability(SLOW_PATH_PROBABILITY, result == Integer.MIN_VALUE)) { 114 if (Double.isNaN(input)) { 115 // input is NaN -> return 0 116 return 0; 117 } else if (input > 0.0d) { 118 // input is positive -> return maxInt 119 return Integer.MAX_VALUE; 120 } 121 } 122 return result; 123 } 124 125 /** 126 * Converts a double to a long. 127 * <p> 128 * This snippet accounts for the semantics of the x64 CVTTSD2SI instruction used to do the 129 * conversion. If the double value is a NaN, infinity or if the result of the conversion is 130 * larger than {@link Long#MAX_VALUE} then CVTTSD2SI returns {@link Long#MIN_VALUE} and extra 131 * tests are required on the double value to return the correct long value. 132 * 133 * @param input the double being converted 134 * @param result the result produced by the CVTTSS2SI instruction 135 */ 136 @Snippet 137 public static long d2l(double input, long result) { 138 if (probability(SLOW_PATH_PROBABILITY, result == Long.MIN_VALUE)) { 139 if (Double.isNaN(input)) { 140 // input is NaN -> return 0 141 return 0; 142 } else if (input > 0.0d) { 143 // input is positive -> return maxInt 144 return Long.MAX_VALUE; 145 } 146 } 147 return result; 148 } 149 150 public static class Templates extends AbstractTemplates { 151 152 private final SnippetInfo f2i; 153 private final SnippetInfo f2l; 154 private final SnippetInfo d2i; 155 private final SnippetInfo d2l; 156 157 public Templates(Providers providers, SnippetReflectionProvider snippetReflection, TargetDescription target) { 158 super(providers, snippetReflection, target); 159 160 f2i = snippet(AMD64ConvertSnippets.class, "f2i"); 161 f2l = snippet(AMD64ConvertSnippets.class, "f2l"); 162 d2i = snippet(AMD64ConvertSnippets.class, "d2i"); 163 d2l = snippet(AMD64ConvertSnippets.class, "d2l"); 164 } 165 166 public void lower(FloatConvertNode convert, LoweringTool tool) { 167 SnippetInfo key; 168 switch (convert.getFloatConvert()) { 169 case F2I: 170 key = f2i; 171 break; 172 case F2L: 173 key = f2l; 174 break; 175 case D2I: 176 key = d2i; 177 break; 178 case D2L: 179 key = d2l; 180 break; 181 default: 182 return; 183 } 184 185 StructuredGraph graph = convert.graph(); 186 187 Arguments args = new Arguments(key, graph.getGuardsStage(), tool.getLoweringStage()); 188 args.add("input", convert.getValue()); 189 args.add("result", graph.unique(new AMD64FloatConvertNode(convert.getFloatConvert(), convert.getValue()))); 190 191 SnippetTemplate template = template(args); 192 Debug.log("Lowering %s in %s: node=%s, template=%s, arguments=%s", convert.getFloatConvert(), graph, convert, template, args); 193 template.instantiate(providers.getMetaAccess(), convert, DEFAULT_REPLACER, tool, args); 194 convert.safeDelete(); 195 } 196 } 197 }