1/*
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 "B3LowerMacros.h"
28
29#if ENABLE(B3_JIT)
30
31#include "B3BasicBlockInlines.h"
32#include "B3BlockInsertionSet.h"
33#include "B3ControlValue.h"
34#include "B3InsertionSetInlines.h"
35#include "B3PhaseScope.h"
36#include "B3ProcedureInlines.h"
37#include "B3UpsilonValue.h"
38#include "B3ValueInlines.h"
39
40namespace JSC { namespace B3 {
41
42namespace {
43
44class LowerMacros {
45public:
46 LowerMacros(Procedure& proc)
47 : m_proc(proc)
48 , m_blockInsertionSet(proc)
49 , m_insertionSet(proc)
50 {
51 }
52
53 bool run()
54 {
55 for (BasicBlock* block : m_proc) {
56 m_block = block;
57 processCurrentBlock();
58 }
59 m_changed |= m_blockInsertionSet.execute();
60 if (m_changed)
61 m_proc.resetReachability();
62 return m_changed;
63 }
64
65private:
66 void processCurrentBlock()
67 {
68 for (m_index = 0; m_index < m_block->size(); ++m_index) {
69 m_value = m_block->at(m_index);
70 switch (m_value->opcode()) {
71 case ChillDiv: {
72 // ARM supports this instruction natively.
73 if (isARM64())
74 break;
75
76 m_changed = true;
77
78 // We implement "res = ChillDiv(num, den)" as follows:
79 //
80 // if (den + 1 <=_unsigned 1) {
81 // if (!den) {
82 // res = 0;
83 // goto done;
84 // }
85 // if (num == -2147483648) {
86 // res = num;
87 // goto done;
88 // }
89 // }
90 // res = num / dev;
91 // done:
92
93 Value* num = m_value->child(0);
94 Value* den = m_value->child(1);
95
96 Value* one =
97 m_insertionSet.insertIntConstant(m_index, m_value, 1);
98 Value* isDenOK = m_insertionSet.insert<Value>(
99 m_index, Above, m_value->origin(),
100 m_insertionSet.insert<Value>(m_index, Add, m_value->origin(), den, one),
101 one);
102
103 BasicBlock* before =
104 m_blockInsertionSet.splitForward(m_block, m_index, &m_insertionSet);
105
106 BasicBlock* normalDivCase = m_blockInsertionSet.insertBefore(m_block);
107 BasicBlock* shadyDenCase = m_blockInsertionSet.insertBefore(m_block);
108 BasicBlock* zeroDenCase = m_blockInsertionSet.insertBefore(m_block);
109 BasicBlock* neg1DenCase = m_blockInsertionSet.insertBefore(m_block);
110 BasicBlock* intMinCase = m_blockInsertionSet.insertBefore(m_block);
111
112 before->replaceLastWithNew<ControlValue>(
113 m_proc, Branch, m_value->origin(), isDenOK,
114 FrequentedBlock(normalDivCase, FrequencyClass::Normal),
115 FrequentedBlock(shadyDenCase, FrequencyClass::Rare));
116
117 UpsilonValue* normalResult = normalDivCase->appendNew<UpsilonValue>(
118 m_proc, m_value->origin(),
119 normalDivCase->appendNew<Value>(m_proc, Div, m_value->origin(), num, den));
120 normalDivCase->appendNew<ControlValue>(
121 m_proc, Jump, m_value->origin(), FrequentedBlock(m_block));
122
123 shadyDenCase->appendNew<ControlValue>(
124 m_proc, Branch, m_value->origin(), den,
125 FrequentedBlock(neg1DenCase, FrequencyClass::Normal),
126 FrequentedBlock(zeroDenCase, FrequencyClass::Rare));
127
128 UpsilonValue* zeroResult = zeroDenCase->appendNew<UpsilonValue>(
129 m_proc, m_value->origin(),
130 zeroDenCase->appendIntConstant(m_proc, m_value, 0));
131 zeroDenCase->appendNew<ControlValue>(
132 m_proc, Jump, m_value->origin(), FrequentedBlock(m_block));
133
134 int64_t badNumeratorConst;
135 switch (m_value->type()) {
136 case Int32:
137 badNumeratorConst = -2147483647 - 1;
138 break;
139 case Int64:
140 badNumeratorConst = -9223372036854775807ll - 1;
141 break;
142 default:
143 ASSERT_NOT_REACHED();
144 badNumeratorConst = 0;
145 }
146
147 Value* badNumerator =
148 neg1DenCase->appendIntConstant(m_proc, m_value, badNumeratorConst);
149
150 neg1DenCase->appendNew<ControlValue>(
151 m_proc, Branch, m_value->origin(),
152 neg1DenCase->appendNew<Value>(
153 m_proc, Equal, m_value->origin(), num, badNumerator),
154 FrequentedBlock(intMinCase, FrequencyClass::Rare),
155 FrequentedBlock(normalDivCase, FrequencyClass::Normal));
156
157 UpsilonValue* intMinResult = intMinCase->appendNew<UpsilonValue>(
158 m_proc, m_value->origin(), badNumerator);
159 intMinCase->appendNew<ControlValue>(
160 m_proc, Jump, m_value->origin(), FrequentedBlock(m_block));
161
162 Value* phi = m_insertionSet.insert<Value>(
163 m_index, Phi, m_value->type(), m_value->origin());
164 normalResult->setPhi(phi);
165 zeroResult->setPhi(phi);
166 intMinResult->setPhi(phi);
167
168 m_value->replaceWithIdentity(phi);
169 break;
170 }
171
172 // FIXME: Implement Switch.
173 // https://bugs.webkit.org/show_bug.cgi?id=151115
174
175 default:
176 break;
177 }
178 }
179 m_insertionSet.execute(m_block);
180 }
181
182 Procedure& m_proc;
183 BlockInsertionSet m_blockInsertionSet;
184 InsertionSet m_insertionSet;
185 BasicBlock* m_block;
186 unsigned m_index;
187 Value* m_value;
188 bool m_changed { false };
189};
190
191} // anonymous namespace
192
193bool lowerMacros(Procedure& proc)
194{
195 PhaseScope phaseScope(proc, "lowerMacros");
196 LowerMacros lowerMacros(proc);
197 return lowerMacros.run();
198}
199
200} } // namespace JSC::B3
201
202#endif // ENABLE(B3_JIT)
203