001/* 002 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.replacements.amd64; 024 025import jdk.internal.jvmci.code.*; 026import com.oracle.graal.debug.*; 027import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*; 028import static com.oracle.graal.replacements.SnippetTemplate.*; 029 030import com.oracle.graal.api.replacements.*; 031import com.oracle.graal.nodes.*; 032import com.oracle.graal.nodes.calc.*; 033import com.oracle.graal.nodes.spi.*; 034import com.oracle.graal.phases.util.*; 035import com.oracle.graal.replacements.*; 036import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates; 037import com.oracle.graal.replacements.SnippetTemplate.Arguments; 038import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo; 039 040/** 041 * Snippets used for conversion operations on AMD64 where the AMD64 instruction used does not match 042 * the semantics of the JVM specification. 043 */ 044public class AMD64ConvertSnippets implements Snippets { 045 046 /** 047 * Converts a float to an int. 048 * <p> 049 * This snippet accounts for the semantics of the x64 CVTTSS2SI instruction used to do the 050 * conversion. If the float value is a NaN, infinity or if the result of the conversion is 051 * larger than {@link Integer#MAX_VALUE} then CVTTSS2SI returns {@link Integer#MIN_VALUE} and 052 * extra tests are required on the float value to return the correct int value. 053 * 054 * @param input the float being converted 055 * @param result the result produced by the CVTTSS2SI instruction 056 */ 057 @Snippet 058 public static int f2i(float input, int result) { 059 if (probability(SLOW_PATH_PROBABILITY, result == Integer.MIN_VALUE)) { 060 if (Float.isNaN(input)) { 061 // input is NaN -> return 0 062 return 0; 063 } else if (input > 0.0f) { 064 // input is > 0 -> return max int 065 return Integer.MAX_VALUE; 066 } 067 } 068 return result; 069 } 070 071 /** 072 * Converts a float to a long. 073 * <p> 074 * This snippet accounts for the semantics of the x64 CVTTSS2SI instruction used to do the 075 * conversion. If the float value is a NaN or infinity then CVTTSS2SI returns 076 * {@link Long#MIN_VALUE} and extra tests are required on the float value to return the correct 077 * long value. 078 * 079 * @param input the float being converted 080 * @param result the result produced by the CVTTSS2SI instruction 081 */ 082 @Snippet 083 public static long f2l(float input, long result) { 084 if (probability(SLOW_PATH_PROBABILITY, result == Long.MIN_VALUE)) { 085 if (Float.isNaN(input)) { 086 // input is NaN -> return 0 087 return 0; 088 } else if (input > 0.0f) { 089 // input is > 0 -> return max int 090 return Long.MAX_VALUE; 091 } 092 } 093 return result; 094 } 095 096 /** 097 * Converts a double to an int. 098 * <p> 099 * This snippet accounts for the semantics of the x64 CVTTSD2SI instruction used to do the 100 * conversion. If the double value is a NaN, infinity or if the result of the conversion is 101 * larger than {@link Integer#MAX_VALUE} then CVTTSD2SI returns {@link Integer#MIN_VALUE} and 102 * extra tests are required on the double value to return the correct int value. 103 * 104 * @param input the double being converted 105 * @param result the result produced by the CVTTSS2SI instruction 106 */ 107 @Snippet 108 public static int d2i(double input, int result) { 109 if (probability(SLOW_PATH_PROBABILITY, result == Integer.MIN_VALUE)) { 110 if (Double.isNaN(input)) { 111 // input is NaN -> return 0 112 return 0; 113 } else if (input > 0.0d) { 114 // input is positive -> return maxInt 115 return Integer.MAX_VALUE; 116 } 117 } 118 return result; 119 } 120 121 /** 122 * Converts a double to a long. 123 * <p> 124 * This snippet accounts for the semantics of the x64 CVTTSD2SI instruction used to do the 125 * conversion. If the double value is a NaN, infinity or if the result of the conversion is 126 * larger than {@link Long#MAX_VALUE} then CVTTSD2SI returns {@link Long#MIN_VALUE} and extra 127 * tests are required on the double value to return the correct long value. 128 * 129 * @param input the double being converted 130 * @param result the result produced by the CVTTSS2SI instruction 131 */ 132 @Snippet 133 public static long d2l(double input, long result) { 134 if (probability(SLOW_PATH_PROBABILITY, result == Long.MIN_VALUE)) { 135 if (Double.isNaN(input)) { 136 // input is NaN -> return 0 137 return 0; 138 } else if (input > 0.0d) { 139 // input is positive -> return maxInt 140 return Long.MAX_VALUE; 141 } 142 } 143 return result; 144 } 145 146 public static class Templates extends AbstractTemplates { 147 148 private final SnippetInfo f2i; 149 private final SnippetInfo f2l; 150 private final SnippetInfo d2i; 151 private final SnippetInfo d2l; 152 153 public Templates(Providers providers, SnippetReflectionProvider snippetReflection, TargetDescription target) { 154 super(providers, snippetReflection, target); 155 156 f2i = snippet(AMD64ConvertSnippets.class, "f2i"); 157 f2l = snippet(AMD64ConvertSnippets.class, "f2l"); 158 d2i = snippet(AMD64ConvertSnippets.class, "d2i"); 159 d2l = snippet(AMD64ConvertSnippets.class, "d2l"); 160 } 161 162 public void lower(FloatConvertNode convert, LoweringTool tool) { 163 SnippetInfo key; 164 switch (convert.getFloatConvert()) { 165 case F2I: 166 key = f2i; 167 break; 168 case F2L: 169 key = f2l; 170 break; 171 case D2I: 172 key = d2i; 173 break; 174 case D2L: 175 key = d2l; 176 break; 177 default: 178 return; 179 } 180 181 StructuredGraph graph = convert.graph(); 182 183 Arguments args = new Arguments(key, graph.getGuardsStage(), tool.getLoweringStage()); 184 args.add("input", convert.getValue()); 185 args.add("result", graph.unique(new AMD64FloatConvertNode(convert.getFloatConvert(), convert.getValue()))); 186 187 SnippetTemplate template = template(args); 188 Debug.log("Lowering %s in %s: node=%s, template=%s, arguments=%s", convert.getFloatConvert(), graph, convert, template, args); 189 template.instantiate(providers.getMetaAccess(), convert, DEFAULT_REPLACER, tool, args); 190 graph.removeFloating(convert); 191 } 192 } 193}