B3 should be able to compile a program with ChillDiv
[WebKit-https.git] / Source / JavaScriptCore / b3 / B3LowerMacros.cpp
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
40 namespace JSC { namespace B3 {
41
42 namespace {
43
44 class LowerMacros {
45 public:
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     
65 private:
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 = std::numeric_limits<int32_t>::min();
138                     break;
139                 case Int64:
140                     badNumeratorConst = std::numeric_limits<int64_t>::min();
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                 before->updatePredecessorsAfter();
170                 break;
171             }
172
173             // FIXME: Implement Switch.
174             // https://bugs.webkit.org/show_bug.cgi?id=151115
175
176             default:
177                 break;
178             }
179         }
180         m_insertionSet.execute(m_block);
181     }
182     
183     Procedure& m_proc;
184     BlockInsertionSet m_blockInsertionSet;
185     InsertionSet m_insertionSet;
186     BasicBlock* m_block;
187     unsigned m_index;
188     Value* m_value;
189     bool m_changed { false };
190 };
191
192 bool lowerMacrosImpl(Procedure& proc)
193 {
194     LowerMacros lowerMacros(proc);
195     return lowerMacros.run();
196 }
197
198 } // anonymous namespace
199
200 bool lowerMacros(Procedure& proc)
201 {
202     PhaseScope phaseScope(proc, "lowerMacros");
203     bool result = lowerMacrosImpl(proc);
204     if (shouldValidateIR())
205         RELEASE_ASSERT(!lowerMacrosImpl(proc));
206     return result;
207 }
208
209 } } // namespace JSC::B3
210
211 #endif // ENABLE(B3_JIT)
212