blob: cb41f74ba1c3773ddcd3bd3fae0d90efe7b0ecda [file] [log] [blame]
benjamin@webkit.org02dd0142015-12-08 02:56:16 +00001/*
2 * Copyright (C) 2015 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "B3ReduceDoubleToFloat.h"
28
29#if ENABLE(B3_JIT)
30
31#include "B3BasicBlock.h"
32#include "B3PhaseScope.h"
33#include "B3ValueInlines.h"
34
35namespace JSC { namespace B3 {
36
37namespace {
38void attemptSimplification(Value* candidate)
39{
40 switch (candidate->opcode()) {
41 case Add:
42 case Sub:
43 case Mul:
44 case Div:
45 if (candidate->child(0)->opcode() == FloatToDouble && candidate->child(1)->opcode() == FloatToDouble) {
46 candidate->child(0) = candidate->child(0)->child(0);
47 candidate->child(1) = candidate->child(1)->child(0);
48 candidate->setType(Float);
49 }
50 break;
commit-queue@webkit.org9fad4952015-12-12 06:10:07 +000051 case Abs:
commit-queue@webkit.org868c9732015-12-14 22:44:22 +000052 case Ceil:
benjamin@webkit.org02dd0142015-12-08 02:56:16 +000053 case Sqrt:
54 if (candidate->child(0)->opcode() == FloatToDouble) {
55 candidate->child(0) = candidate->child(0)->child(0);
56 candidate->setType(Float);
57 }
58 break;
59 default:
60 break;
61 }
62}
63
64} // namespace
65
66// The goal of this phase is to transform Double operations
67// into float if the Double result is never used as Double.
68//
69// In C, that would be something like:
70// float add(float a, float b) {
71// return (double)a + (double)b;
72// }
73//
74// Such operation arise in JS because there are is no Float type
75// and float operations are generated by adding double-to-float rounding.
76//
77// The operations can be done entirely without Double conversion.
78// Using float in place remove the useless conversion, and the float
79// ops is sometime massively cheaper (SQRT for example).
80//
81// If the Double value is used as Double, we do not do the conversion.
82// It is cheaper to do a conversion than repeat any floating-point operation.
83void reduceDoubleToFloat(Procedure& procedure)
84{
85 // FIXME: We should tune this phase for performance and make it part of ReduceStrength.
86 // ReduceStrength can eliminate nodes that prevents us from simplifying operations.
87 PhaseScope phaseScope(procedure, "reduceDoubleToFloat");
88
89 HashSet<Value*> candidates;
90
91 // First, we find any value that is converted to float
92 // and only used as float.
93 // We also simplify comparisons since that's always safe and we
94 // don't want them to appear in the next loop.
95 for (BasicBlock* block : procedure) {
96 for (Value* value : *block) {
97 value->performSubstitution();
98
99 switch (value->opcode()) {
100 case DoubleToFloat:
101 candidates.add(value->child(0));
102 break;
103 case Equal:
104 case NotEqual:
105 case LessThan:
106 case GreaterThan:
107 case LessEqual:
108 case GreaterEqual:
commit-queue@webkit.orgbd1d1d32015-12-19 16:52:11 +0000109 case EqualOrUnordered:
benjamin@webkit.org02dd0142015-12-08 02:56:16 +0000110 if (value->child(0)->opcode() == FloatToDouble && value->child(1)->opcode() == FloatToDouble) {
111 value->child(0) = value->child(0)->child(0);
112 value->child(1) = value->child(1)->child(0);
113 }
114 break;
115 default:
116 break;
117 }
118 }
119 }
120
121 for (BasicBlock* block : procedure) {
122 for (Value* value : *block) {
123 if (value->opcode() == DoubleToFloat)
124 continue;
125
126 for (Value* child : value->children()) {
127 if (child->type() == Double)
128 candidates.remove(child);
129 }
130 }
131 }
132
133 if (candidates.isEmpty())
134 return;
135
136 // Second, we go over the candidates and attempt to simplify them.
137 // This leaves the graph in an invalid state where Float Values are
138 // used by DoubleToFloat Values. This is only temporary.
139 for (Value* candidate : candidates)
140 attemptSimplification(candidate);
141
142 // Finally, remove the DoubleToFloat made useless by the simplifications.
143 for (BasicBlock* block : procedure) {
144 for (Value* value : *block) {
145 if (value->opcode() == DoubleToFloat && value->child(0)->type() == Float)
146 value->replaceWithIdentity(value->child(0));
147 }
148 }
149
150 // We do not clean all the useless nodes and conversions. ReduceStrength does that better.
151}
152
153} } // namespace JSC::B3
154
155#endif // ENABLE(B3_JIT)
156