1/*
2 * Copyright (C) 2015-2018 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 "B3LowerMacrosAfterOptimizations.h"
28
29#if ENABLE(B3_JIT)
30
31#include "AirArg.h"
32#include "B3BasicBlockInlines.h"
33#include "B3BlockInsertionSet.h"
34#include "B3CCallValue.h"
35#include "B3ConstDoubleValue.h"
36#include "B3ConstFloatValue.h"
37#include "B3ConstPtrValue.h"
38#include "B3InsertionSetInlines.h"
39#include "B3PhaseScope.h"
40
41namespace JSC { namespace B3 {
42
43using Arg = Air::Arg;
44using Code = Air::Code;
45using Tmp = Air::Tmp;
46
47namespace {
48
49class LowerMacrosAfterOptimizations {
50public:
51 LowerMacrosAfterOptimizations(Procedure& proc)
52 : m_proc(proc)
53 , m_blockInsertionSet(proc)
54 , m_insertionSet(proc)
55 {
56 }
57
58 bool run()
59 {
60 for (BasicBlock* block : m_proc) {
61 m_block = block;
62 processCurrentBlock();
63 }
64 m_changed |= m_blockInsertionSet.execute();
65 if (m_changed) {
66 m_proc.resetReachability();
67 m_proc.invalidateCFG();
68 }
69 return m_changed;
70 }
71
72private:
73 void processCurrentBlock()
74 {
75 for (m_index = 0; m_index < m_block->size(); ++m_index) {
76 m_value = m_block->at(m_index);
77 m_origin = m_value->origin();
78 switch (m_value->opcode()) {
79 case Abs: {
80 // ARM supports this instruction natively.
81 if (isARM64())
82 break;
83
84 Value* mask = nullptr;
85 if (m_value->type() == Double)
86 mask = m_insertionSet.insert<ConstDoubleValue>(m_index, m_origin, bitwise_cast<double>(~(1ll << 63)));
87 else if (m_value->type() == Float)
88 mask = m_insertionSet.insert<ConstFloatValue>(m_index, m_origin, bitwise_cast<float>(~(1 << 31)));
89 else
90 RELEASE_ASSERT_NOT_REACHED();
91 Value* result = m_insertionSet.insert<Value>(m_index, BitAnd, m_origin, m_value->child(0), mask);
92 m_value->replaceWithIdentity(result);
93 break;
94 }
95 case Ceil: {
96 if (MacroAssembler::supportsFloatingPointRounding())
97 break;
98
99 Value* functionAddress = nullptr;
100 if (m_value->type() == Double) {
101 double (*ceilDouble)(double) = ceil;
102 functionAddress = m_insertionSet.insert<ConstPtrValue>(m_index, m_origin, tagCFunctionPtr(ceilDouble, B3CCallPtrTag));
103 } else if (m_value->type() == Float)
104 functionAddress = m_insertionSet.insert<ConstPtrValue>(m_index, m_origin, tagCFunctionPtr(ceilf, B3CCallPtrTag));
105 else
106 RELEASE_ASSERT_NOT_REACHED();
107
108 Value* result = m_insertionSet.insert<CCallValue>(m_index,
109 m_value->type(),
110 m_origin,
111 Effects::none(),
112 functionAddress,
113 m_value->child(0));
114 m_value->replaceWithIdentity(result);
115 break;
116 }
117 case Floor: {
118 if (MacroAssembler::supportsFloatingPointRounding())
119 break;
120
121 Value* functionAddress = nullptr;
122 if (m_value->type() == Double) {
123 double (*floorDouble)(double) = floor;
124 functionAddress = m_insertionSet.insert<ConstPtrValue>(m_index, m_origin, tagCFunctionPtr(floorDouble, B3CCallPtrTag));
125 } else if (m_value->type() == Float)
126 functionAddress = m_insertionSet.insert<ConstPtrValue>(m_index, m_origin, tagCFunctionPtr(floorf, B3CCallPtrTag));
127 else
128 RELEASE_ASSERT_NOT_REACHED();
129
130 Value* result = m_insertionSet.insert<CCallValue>(m_index,
131 m_value->type(),
132 m_origin,
133 Effects::none(),
134 functionAddress,
135 m_value->child(0));
136 m_value->replaceWithIdentity(result);
137 break;
138 }
139 case Neg: {
140 if (!isFloat(m_value->type()))
141 break;
142
143 // X86 is odd in that it requires this.
144 if (!isX86())
145 break;
146
147 Value* mask = nullptr;
148 if (m_value->type() == Double)
149 mask = m_insertionSet.insert<ConstDoubleValue>(m_index, m_origin, -0.0);
150 else {
151 RELEASE_ASSERT(m_value->type() == Float);
152 mask = m_insertionSet.insert<ConstFloatValue>(m_index, m_origin, -0.0f);
153 }
154
155 Value* result = m_insertionSet.insert<Value>(
156 m_index, BitXor, m_origin, m_value->child(0), mask);
157 m_value->replaceWithIdentity(result);
158 break;
159 }
160
161 case RotL: {
162 // ARM64 doesn't have a rotate left.
163 if (isARM64()) {
164 Value* newShift = m_insertionSet.insert<Value>(m_index, Neg, m_value->origin(), m_value->child(1));
165 Value* rotate = m_insertionSet.insert<Value>(m_index, RotR, m_value->origin(), m_value->child(0), newShift);
166 m_value->replaceWithIdentity(rotate);
167 break;
168 }
169 break;
170 }
171
172 default:
173 break;
174 }
175 }
176 m_insertionSet.execute(m_block);
177 }
178
179 Procedure& m_proc;
180 BlockInsertionSet m_blockInsertionSet;
181 InsertionSet m_insertionSet;
182 BasicBlock* m_block;
183 unsigned m_index;
184 Value* m_value;
185 Origin m_origin;
186 bool m_changed { false };
187};
188
189bool lowerMacrosImpl(Procedure& proc)
190{
191 LowerMacrosAfterOptimizations lowerMacros(proc);
192 return lowerMacros.run();
193}
194
195} // anonymous namespace
196
197bool lowerMacrosAfterOptimizations(Procedure& proc)
198{
199 PhaseScope phaseScope(proc, "lowerMacrosAfterOptimizations");
200 bool result = lowerMacrosImpl(proc);
201 if (shouldValidateIR())
202 RELEASE_ASSERT(!lowerMacrosImpl(proc));
203 return result;
204}
205
206} } // namespace JSC::B3
207
208#endif // ENABLE(B3_JIT)
209
210