AMD64ConvertSnippets.java revision 13264:48566d838608
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 */
23package org.graalvm.compiler.replacements.amd64;
24
25import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.SLOW_PATH_PROBABILITY;
26import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;
27import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;
28
29import org.graalvm.compiler.api.replacements.Snippet;
30import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
31import org.graalvm.compiler.debug.DebugHandlersFactory;
32import org.graalvm.compiler.nodes.StructuredGraph;
33import org.graalvm.compiler.nodes.calc.FloatConvertNode;
34import org.graalvm.compiler.nodes.spi.LoweringTool;
35import org.graalvm.compiler.options.OptionValues;
36import org.graalvm.compiler.phases.util.Providers;
37import org.graalvm.compiler.replacements.SnippetTemplate;
38import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
39import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
40import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
41import org.graalvm.compiler.replacements.Snippets;
42
43import 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 */
49public 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, Iterable<DebugHandlersFactory> factories, Providers providers, SnippetReflectionProvider snippetReflection, TargetDescription target) {
159            super(options, factories, 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(convert.getDebug(), args);
193            convert.getDebug().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}
199