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