FTL should lower its abstract heaps to B3 heap ranges
[WebKit-https.git] / Source / JavaScriptCore / ftl / FTLOutput.cpp
1 /*
2  * Copyright (C) 2013-2016 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 "FTLOutput.h"
28
29 #if ENABLE(FTL_JIT)
30
31 #include "B3MathExtras.h"
32 #include "B3StackmapGenerationParams.h"
33
34 namespace JSC { namespace FTL {
35
36 using namespace B3;
37
38 Output::Output(State& state)
39     : m_proc(*state.proc)
40 {
41 }
42
43 Output::~Output()
44 {
45 }
46
47 void Output::initialize(AbstractHeapRepository& heaps)
48 {
49     m_heaps = &heaps;
50 }
51
52 LBasicBlock Output::newBlock(const char*)
53 {
54     LBasicBlock result = m_proc.addBlock(m_frequency);
55
56     if (!m_nextBlock)
57         m_blockOrder.append(result);
58     else
59         m_blockOrder.insertBefore(m_nextBlock, result);
60
61     return result;
62 }
63
64 void Output::applyBlockOrder()
65 {
66     m_proc.setBlockOrder(m_blockOrder);
67 }
68
69 LBasicBlock Output::appendTo(LBasicBlock block, LBasicBlock nextBlock)
70 {
71     appendTo(block);
72     return insertNewBlocksBefore(nextBlock);
73 }
74
75 void Output::appendTo(LBasicBlock block)
76 {
77     m_block = block;
78 }
79
80 SlotBaseValue* Output::lockedStackSlot(size_t bytes)
81 {
82     return m_block->appendNew<SlotBaseValue>(m_proc, origin(), m_proc.addStackSlot(bytes));
83 }
84
85 LValue Output::neg(LValue value)
86 {
87     return m_block->appendNew<Value>(m_proc, B3::Neg, origin(), value);
88 }
89
90 LValue Output::bitNot(LValue value)
91 {
92     return m_block->appendNew<B3::Value>(m_proc, B3::BitXor, origin(),
93         value,
94         m_block->appendIntConstant(m_proc, origin(), value->type(), -1));
95 }
96
97 LValue Output::logicalNot(LValue value)
98 {
99     return m_block->appendNew<B3::Value>(m_proc, B3::Equal, origin(), value, int32Zero);
100 }
101
102 LValue Output::load(TypedPointer pointer, LType type)
103 {
104     LValue load = m_block->appendNew<MemoryValue>(m_proc, Load, type, origin(), pointer.value());
105     m_heaps->decorateMemory(pointer.heap(), load);
106     return load;
107 }
108
109 LValue Output::doublePowi(LValue x, LValue y)
110 {
111     // FIXME: powDoubleInt32() should be inlined here since Output knows about block layout and
112     // should be involved in any operation that creates blocks.
113     // https://bugs.webkit.org/show_bug.cgi?id=152223
114     auto result = powDoubleInt32(m_proc, m_block, origin(), x, y);
115     m_block = result.first;
116     return result.second;
117 }
118
119 bool Output::hasSensibleDoubleToInt()
120 {
121     return optimizeForX86();
122 }
123
124 LValue Output::doubleToInt(LValue value)
125 {
126     PatchpointValue* result = patchpoint(Int32);
127     result->append(value, ValueRep::SomeRegister);
128     result->setGenerator(
129         [] (CCallHelpers& jit, const StackmapGenerationParams& params) {
130             jit.truncateDoubleToInt32(params[1].fpr(), params[0].gpr());
131         });
132     result->effects = Effects::none();
133     return result;
134 }
135
136 LValue Output::doubleToUInt(LValue value)
137 {
138     PatchpointValue* result = patchpoint(Int32);
139     result->append(value, ValueRep::SomeRegister);
140     result->setGenerator(
141         [] (CCallHelpers& jit, const StackmapGenerationParams& params) {
142             jit.truncateDoubleToUint32(params[1].fpr(), params[0].gpr());
143         });
144     result->effects = Effects::none();
145     return result;
146 }
147
148 LValue Output::unsignedToDouble(LValue value)
149 {
150     return intToDouble(zeroExt(value, Int64));
151 }
152
153 LValue Output::load8SignExt32(TypedPointer pointer)
154 {
155     LValue load = m_block->appendNew<MemoryValue>(m_proc, Load8S, Int32, origin(), pointer.value());
156     m_heaps->decorateMemory(pointer.heap(), load);
157     return load;
158 }
159
160 LValue Output::load8ZeroExt32(TypedPointer pointer)
161 {
162     LValue load = m_block->appendNew<MemoryValue>(m_proc, Load8Z, Int32, origin(), pointer.value());
163     m_heaps->decorateMemory(pointer.heap(), load);
164     return load;
165 }
166
167 LValue Output::load16SignExt32(TypedPointer pointer)
168 {
169     LValue load = m_block->appendNew<MemoryValue>(m_proc, Load16S, Int32, origin(), pointer.value());
170     m_heaps->decorateMemory(pointer.heap(), load);
171     return load;
172 }
173
174 LValue Output::load16ZeroExt32(TypedPointer pointer)
175 {
176     LValue load = m_block->appendNew<MemoryValue>(m_proc, Load16Z, Int32, origin(), pointer.value());
177     m_heaps->decorateMemory(pointer.heap(), load);
178     return load;
179 }
180
181 void Output::store(LValue value, TypedPointer pointer)
182 {
183     LValue store = m_block->appendNew<MemoryValue>(m_proc, Store, origin(), value, pointer.value());
184     m_heaps->decorateMemory(pointer.heap(), store);
185 }
186
187 void Output::store32As8(LValue value, TypedPointer pointer)
188 {
189     LValue store = m_block->appendNew<MemoryValue>(m_proc, Store8, origin(), value, pointer.value());
190     m_heaps->decorateMemory(pointer.heap(), store);
191 }
192
193 void Output::store32As16(LValue value, TypedPointer pointer)
194 {
195     LValue store = m_block->appendNew<MemoryValue>(m_proc, Store16, origin(), value, pointer.value());
196     m_heaps->decorateMemory(pointer.heap(), store);
197 }
198
199 LValue Output::baseIndex(LValue base, LValue index, Scale scale, ptrdiff_t offset)
200 {
201     LValue accumulatedOffset;
202         
203     switch (scale) {
204     case ScaleOne:
205         accumulatedOffset = index;
206         break;
207     case ScaleTwo:
208         accumulatedOffset = shl(index, intPtrOne);
209         break;
210     case ScaleFour:
211         accumulatedOffset = shl(index, intPtrTwo);
212         break;
213     case ScaleEight:
214     case ScalePtr:
215         accumulatedOffset = shl(index, intPtrThree);
216         break;
217     }
218         
219     if (offset)
220         accumulatedOffset = add(accumulatedOffset, constIntPtr(offset));
221         
222     return add(base, accumulatedOffset);
223 }
224
225 void Output::branch(LValue condition, LBasicBlock taken, Weight takenWeight, LBasicBlock notTaken, Weight notTakenWeight)
226 {
227     m_block->appendNew<ControlValue>(
228         m_proc, B3::Branch, origin(), condition,
229         FrequentedBlock(taken, takenWeight.frequencyClass()),
230         FrequentedBlock(notTaken, notTakenWeight.frequencyClass()));
231 }
232
233 void Output::check(LValue condition, WeightedTarget taken, Weight notTakenWeight)
234 {
235     LBasicBlock continuation = FTL_NEW_BLOCK(*this, ("Output::check continuation"));
236     branch(condition, taken, WeightedTarget(continuation, notTakenWeight));
237     appendTo(continuation);
238 }
239
240 void Output::check(LValue condition, WeightedTarget taken)
241 {
242     check(condition, taken, taken.weight().inverse());
243 }
244
245 LValue Output::load(TypedPointer pointer, LoadType type)
246 {
247     switch (type) {
248     case Load8SignExt32:
249         return load8SignExt32(pointer);
250     case Load8ZeroExt32:
251         return load8ZeroExt32(pointer);
252     case Load16SignExt32:
253         return load8SignExt32(pointer);
254     case Load16ZeroExt32:
255         return load8ZeroExt32(pointer);
256     case Load32:
257         return load32(pointer);
258     case Load64:
259         return load64(pointer);
260     case LoadPtr:
261         return loadPtr(pointer);
262     case LoadFloat:
263         return loadFloat(pointer);
264     case LoadDouble:
265         return loadDouble(pointer);
266     }
267     RELEASE_ASSERT_NOT_REACHED();
268     return nullptr;
269 }
270
271 void Output::store(LValue value, TypedPointer pointer, StoreType type)
272 {
273     switch (type) {
274     case Store32As8:
275         store32As8(value, pointer);
276         return;
277     case Store32As16:
278         store32As16(value, pointer);
279         return;
280     case Store32:
281         store32(value, pointer);
282         return;
283     case Store64:
284         store64(value, pointer);
285         return;
286     case StorePtr:
287         storePtr(value, pointer);
288         return;
289     case StoreFloat:
290         storeFloat(value, pointer);
291         return;
292     case StoreDouble:
293         storeDouble(value, pointer);
294         return;
295     }
296     RELEASE_ASSERT_NOT_REACHED();
297 }
298
299 } } // namespace JSC::FTL
300
301 #endif // ENABLE(FTL_JIT)
302