1/*
2 * Copyright (C) 2015-2017 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 "B3Procedure.h"
28
29#if ENABLE(B3_JIT)
30
31#include "AirCode.h"
32#include "B3BackwardsCFG.h"
33#include "B3BackwardsDominators.h"
34#include "B3BasicBlockInlines.h"
35#include "B3BasicBlockUtils.h"
36#include "B3BlockWorklist.h"
37#include "B3CFG.h"
38#include "B3DataSection.h"
39#include "B3Dominators.h"
40#include "B3NaturalLoops.h"
41#include "B3OpaqueByproducts.h"
42#include "B3PhiChildren.h"
43#include "B3StackSlot.h"
44#include "B3ValueInlines.h"
45#include "B3Variable.h"
46
47namespace JSC { namespace B3 {
48
49Procedure::Procedure()
50 : m_cfg(new CFG(*this))
51 , m_lastPhaseName("initial")
52 , m_byproducts(std::make_unique<OpaqueByproducts>())
53 , m_code(new Air::Code(*this))
54{
55 m_code->setNumEntrypoints(m_numEntrypoints);
56}
57
58Procedure::~Procedure()
59{
60}
61
62void Procedure::printOrigin(PrintStream& out, Origin origin) const
63{
64 if (m_originPrinter)
65 m_originPrinter->run(out, origin);
66 else
67 out.print(origin);
68}
69
70BasicBlock* Procedure::addBlock(double frequency)
71{
72 std::unique_ptr<BasicBlock> block(new BasicBlock(m_blocks.size(), frequency));
73 BasicBlock* result = block.get();
74 m_blocks.append(WTFMove(block));
75 return result;
76}
77
78StackSlot* Procedure::addStackSlot(unsigned byteSize)
79{
80 return m_stackSlots.addNew(byteSize);
81}
82
83Variable* Procedure::addVariable(Type type)
84{
85 return m_variables.addNew(type);
86}
87
88Value* Procedure::clone(Value* value)
89{
90 std::unique_ptr<Value> clone(value->cloneImpl());
91 clone->m_index = UINT_MAX;
92 clone->owner = nullptr;
93 return m_values.add(WTFMove(clone));
94}
95
96
97Value* Procedure::addIntConstant(Origin origin, Type type, int64_t value)
98{
99 switch (type) {
100 case Int32:
101 return add<Const32Value>(origin, static_cast<int32_t>(value));
102 case Int64:
103 return add<Const64Value>(origin, value);
104 case Double:
105 return add<ConstDoubleValue>(origin, static_cast<double>(value));
106 case Float:
107 return add<ConstFloatValue>(origin, static_cast<float>(value));
108 default:
109 RELEASE_ASSERT_NOT_REACHED();
110 return nullptr;
111 }
112}
113
114Value* Procedure::addIntConstant(Value* likeValue, int64_t value)
115{
116 return addIntConstant(likeValue->origin(), likeValue->type(), value);
117}
118
119Value* Procedure::addConstant(Origin origin, Type type, uint64_t bits)
120{
121 switch (type) {
122 case Int32:
123 return add<Const32Value>(origin, static_cast<int32_t>(bits));
124 case Int64:
125 return add<Const64Value>(origin, bits);
126 case Float:
127 return add<ConstFloatValue>(origin, bitwise_cast<float>(static_cast<int32_t>(bits)));
128 case Double:
129 return add<ConstDoubleValue>(origin, bitwise_cast<double>(bits));
130 default:
131 RELEASE_ASSERT_NOT_REACHED();
132 return nullptr;
133 }
134}
135
136Value* Procedure::addBottom(Origin origin, Type type)
137{
138 return addIntConstant(origin, type, 0);
139}
140
141Value* Procedure::addBottom(Value* value)
142{
143 return addBottom(value->origin(), value->type());
144}
145
146Value* Procedure::addBoolConstant(Origin origin, TriState triState)
147{
148 int32_t value = 0;
149 switch (triState) {
150 case FalseTriState:
151 value = 0;
152 break;
153 case TrueTriState:
154 value = 1;
155 break;
156 case MixedTriState:
157 return nullptr;
158 }
159
160 return addIntConstant(origin, Int32, value);
161}
162
163void Procedure::resetValueOwners()
164{
165 for (BasicBlock* block : *this) {
166 for (Value* value : *block)
167 value->owner = block;
168 }
169}
170
171void Procedure::resetReachability()
172{
173 recomputePredecessors(m_blocks);
174
175 // The common case is that this does not find any dead blocks.
176 bool foundDead = false;
177 for (auto& block : m_blocks) {
178 if (isBlockDead(block.get())) {
179 foundDead = true;
180 break;
181 }
182 }
183 if (!foundDead)
184 return;
185
186 resetValueOwners();
187
188 for (Value* value : values()) {
189 if (UpsilonValue* upsilon = value->as<UpsilonValue>()) {
190 if (isBlockDead(upsilon->phi()->owner))
191 upsilon->replaceWithNop();
192 }
193 }
194
195 for (auto& block : m_blocks) {
196 if (isBlockDead(block.get())) {
197 for (Value* value : *block)
198 deleteValue(value);
199 block = nullptr;
200 }
201 }
202}
203
204void Procedure::invalidateCFG()
205{
206 m_dominators = nullptr;
207 m_naturalLoops = nullptr;
208 m_backwardsCFG = nullptr;
209 m_backwardsDominators = nullptr;
210}
211
212void Procedure::dump(PrintStream& out) const
213{
214 IndexSet<Value*> valuesInBlocks;
215 for (BasicBlock* block : *this) {
216 out.print(deepDump(*this, block));
217 valuesInBlocks.addAll(*block);
218 }
219 bool didPrint = false;
220 for (Value* value : values()) {
221 if (valuesInBlocks.contains(value))
222 continue;
223
224 if (!didPrint) {
225 dataLog("Orphaned values:\n");
226 didPrint = true;
227 }
228 dataLog(" ", deepDump(*this, value), "\n");
229 }
230 if (hasQuirks())
231 out.print("Has Quirks: True\n");
232 if (variables().size()) {
233 out.print("Variables:\n");
234 for (Variable* variable : variables())
235 out.print(" ", deepDump(variable), "\n");
236 }
237 if (stackSlots().size()) {
238 out.print("Stack slots:\n");
239 for (StackSlot* slot : stackSlots())
240 out.print(" ", pointerDump(slot), ": ", deepDump(slot), "\n");
241 }
242 if (m_byproducts->count())
243 out.print(*m_byproducts);
244}
245
246Vector<BasicBlock*> Procedure::blocksInPreOrder()
247{
248 return B3::blocksInPreOrder(at(0));
249}
250
251Vector<BasicBlock*> Procedure::blocksInPostOrder()
252{
253 return B3::blocksInPostOrder(at(0));
254}
255
256void Procedure::deleteStackSlot(StackSlot* stackSlot)
257{
258 m_stackSlots.remove(stackSlot);
259}
260
261void Procedure::deleteVariable(Variable* variable)
262{
263 m_variables.remove(variable);
264}
265
266void Procedure::deleteValue(Value* value)
267{
268 m_values.remove(value);
269}
270
271void Procedure::deleteOrphans()
272{
273 IndexSet<Value*> valuesInBlocks;
274 for (BasicBlock* block : *this)
275 valuesInBlocks.addAll(*block);
276
277 // Since this method is not on any hot path, we do it conservatively: first a pass to
278 // identify the values to be removed, and then a second pass to remove them. This avoids any
279 // risk of the value iteration being broken by removals.
280 Vector<Value*, 16> toRemove;
281 for (Value* value : values()) {
282 if (!valuesInBlocks.contains(value))
283 toRemove.append(value);
284 else if (UpsilonValue* upsilon = value->as<UpsilonValue>()) {
285 if (!valuesInBlocks.contains(upsilon->phi()))
286 upsilon->replaceWithNop();
287 }
288 }
289
290 for (Value* value : toRemove)
291 deleteValue(value);
292}
293
294Dominators& Procedure::dominators()
295{
296 if (!m_dominators)
297 m_dominators = std::make_unique<Dominators>(*this);
298 return *m_dominators;
299}
300
301NaturalLoops& Procedure::naturalLoops()
302{
303 if (!m_naturalLoops)
304 m_naturalLoops = std::make_unique<NaturalLoops>(*this);
305 return *m_naturalLoops;
306}
307
308BackwardsCFG& Procedure::backwardsCFG()
309{
310 if (!m_backwardsCFG)
311 m_backwardsCFG = std::make_unique<BackwardsCFG>(*this);
312 return *m_backwardsCFG;
313}
314
315BackwardsDominators& Procedure::backwardsDominators()
316{
317 if (!m_backwardsDominators)
318 m_backwardsDominators = std::make_unique<BackwardsDominators>(*this);
319 return *m_backwardsDominators;
320}
321
322void Procedure::addFastConstant(const ValueKey& constant)
323{
324 RELEASE_ASSERT(constant.isConstant());
325 m_fastConstants.add(constant);
326}
327
328bool Procedure::isFastConstant(const ValueKey& constant)
329{
330 if (!constant)
331 return false;
332 return m_fastConstants.contains(constant);
333}
334
335CCallHelpers::Label Procedure::entrypointLabel(unsigned index) const
336{
337 return m_code->entrypointLabel(index);
338}
339
340void* Procedure::addDataSection(size_t size)
341{
342 if (!size)
343 return nullptr;
344 std::unique_ptr<DataSection> dataSection = std::make_unique<DataSection>(size);
345 void* result = dataSection->data();
346 m_byproducts->add(WTFMove(dataSection));
347 return result;
348}
349
350unsigned Procedure::callArgAreaSizeInBytes() const
351{
352 return code().callArgAreaSizeInBytes();
353}
354
355void Procedure::requestCallArgAreaSizeInBytes(unsigned size)
356{
357 code().requestCallArgAreaSizeInBytes(size);
358}
359
360void Procedure::pinRegister(Reg reg)
361{
362 code().pinRegister(reg);
363}
364
365void Procedure::setOptLevel(unsigned optLevel)
366{
367 m_optLevel = optLevel;
368 code().setOptLevel(optLevel);
369}
370
371unsigned Procedure::frameSize() const
372{
373 return code().frameSize();
374}
375
376RegisterAtOffsetList Procedure::calleeSaveRegisterAtOffsetList() const
377{
378 return code().calleeSaveRegisterAtOffsetList();
379}
380
381Value* Procedure::addValueImpl(Value* value)
382{
383 return m_values.add(std::unique_ptr<Value>(value));
384}
385
386void Procedure::setBlockOrderImpl(Vector<BasicBlock*>& blocks)
387{
388 IndexSet<BasicBlock*> blocksSet;
389 blocksSet.addAll(blocks);
390
391 for (BasicBlock* block : *this) {
392 if (!blocksSet.contains(block))
393 blocks.append(block);
394 }
395
396 // Place blocks into this's block list by first leaking all of the blocks and then readopting
397 // them.
398 for (auto& entry : m_blocks)
399 entry.release();
400
401 m_blocks.resize(blocks.size());
402 for (unsigned i = 0; i < blocks.size(); ++i) {
403 BasicBlock* block = blocks[i];
404 block->m_index = i;
405 m_blocks[i] = std::unique_ptr<BasicBlock>(block);
406 }
407}
408
409void Procedure::setWasmBoundsCheckGenerator(RefPtr<WasmBoundsCheckGenerator> generator)
410{
411 code().setWasmBoundsCheckGenerator(generator);
412}
413
414RegisterSet Procedure::mutableGPRs()
415{
416 return code().mutableGPRs();
417}
418
419RegisterSet Procedure::mutableFPRs()
420{
421 return code().mutableFPRs();
422}
423
424void Procedure::setNumEntrypoints(unsigned numEntrypoints)
425{
426 m_numEntrypoints = numEntrypoints;
427 m_code->setNumEntrypoints(numEntrypoints);
428}
429
430} } // namespace JSC::B3
431
432#endif // ENABLE(B3_JIT)
433