B3 -O1 should not allocateStackByGraphColoring
[WebKit-https.git] / Source / JavaScriptCore / b3 / air / AirCode.cpp
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 "AirCode.h"
28
29 #if ENABLE(B3_JIT)
30
31 #include "AirCCallSpecial.h"
32 #include "AirCFG.h"
33 #include "B3BasicBlockUtils.h"
34 #include "B3Procedure.h"
35 #include "B3StackSlot.h"
36 #include <wtf/ListDump.h>
37
38 namespace JSC { namespace B3 { namespace Air {
39
40 Code::Code(Procedure& proc)
41     : m_proc(proc)
42     , m_cfg(new CFG(*this))
43     , m_lastPhaseName("initial")
44 {
45     // Come up with initial orderings of registers. The user may replace this with something else.
46     forEachBank(
47         [&] (Bank bank) {
48             Vector<Reg> result;
49             RegisterSet all = bank == GP ? RegisterSet::allGPRs() : RegisterSet::allFPRs();
50             all.exclude(RegisterSet::stackRegisters());
51             all.exclude(RegisterSet::reservedHardwareRegisters());
52             RegisterSet calleeSave = RegisterSet::calleeSaveRegisters();
53             all.forEach(
54                 [&] (Reg reg) {
55                     if (!calleeSave.get(reg))
56                         result.append(reg);
57                 });
58             all.forEach(
59                 [&] (Reg reg) {
60                     if (calleeSave.get(reg))
61                         result.append(reg);
62                 });
63             setRegsInPriorityOrder(bank, result);
64         });
65 }
66
67 Code::~Code()
68 {
69 }
70
71 void Code::setRegsInPriorityOrder(Bank bank, const Vector<Reg>& regs)
72 {
73     regsInPriorityOrderImpl(bank) = regs;
74     m_mutableRegs = RegisterSet();
75     forEachBank(
76         [&] (Bank bank) {
77             for (Reg reg : regsInPriorityOrder(bank))
78                 m_mutableRegs.set(reg);
79         });
80 }
81
82 void Code::pinRegister(Reg reg)
83 {
84     Vector<Reg>& regs = regsInPriorityOrderImpl(Arg(Tmp(reg)).bank());
85     regs.removeFirst(reg);
86     m_mutableRegs.clear(reg);
87     ASSERT(!regs.contains(reg));
88 }
89
90 bool Code::needsUsedRegisters() const
91 {
92     return m_proc.needsUsedRegisters();
93 }
94
95 BasicBlock* Code::addBlock(double frequency)
96 {
97     std::unique_ptr<BasicBlock> block(new BasicBlock(m_blocks.size(), frequency));
98     BasicBlock* result = block.get();
99     m_blocks.append(WTFMove(block));
100     return result;
101 }
102
103 StackSlot* Code::addStackSlot(unsigned byteSize, StackSlotKind kind, B3::StackSlot* b3Slot)
104 {
105     StackSlot* result = m_stackSlots.addNew(byteSize, kind, b3Slot);
106     if (m_stackIsAllocated) {
107         // FIXME: This is unnecessarily awful. Fortunately, it doesn't run often.
108         unsigned extent = WTF::roundUpToMultipleOf(result->alignment(), frameSize() + byteSize);
109         result->setOffsetFromFP(-static_cast<ptrdiff_t>(extent));
110         setFrameSize(WTF::roundUpToMultipleOf(stackAlignmentBytes(), extent));
111     }
112     return result;
113 }
114
115 StackSlot* Code::addStackSlot(B3::StackSlot* b3Slot)
116 {
117     return addStackSlot(b3Slot->byteSize(), StackSlotKind::Locked, b3Slot);
118 }
119
120 Special* Code::addSpecial(std::unique_ptr<Special> special)
121 {
122     special->m_code = this;
123     return m_specials.add(WTFMove(special));
124 }
125
126 CCallSpecial* Code::cCallSpecial()
127 {
128     if (!m_cCallSpecial) {
129         m_cCallSpecial = static_cast<CCallSpecial*>(
130             addSpecial(std::make_unique<CCallSpecial>()));
131     }
132
133     return m_cCallSpecial;
134 }
135
136 bool Code::isEntrypoint(BasicBlock* block) const
137 {
138     if (m_entrypoints.isEmpty())
139         return !block->index();
140     
141     for (const FrequentedBlock& entrypoint : m_entrypoints) {
142         if (entrypoint.block() == block)
143             return true;
144     }
145     return false;
146 }
147
148 void Code::setCalleeSaveRegisterAtOffsetList(RegisterAtOffsetList&& registerAtOffsetList, StackSlot* slot)
149 {
150     m_uncorrectedCalleeSaveRegisterAtOffsetList = WTFMove(registerAtOffsetList);
151     for (const RegisterAtOffset& registerAtOffset : m_uncorrectedCalleeSaveRegisterAtOffsetList)
152         m_calleeSaveRegisters.set(registerAtOffset.reg());
153     m_calleeSaveStackSlot = slot;
154 }
155
156 RegisterAtOffsetList Code::calleeSaveRegisterAtOffsetList() const
157 {
158     RegisterAtOffsetList result = m_uncorrectedCalleeSaveRegisterAtOffsetList;
159     if (StackSlot* slot = m_calleeSaveStackSlot) {
160         ptrdiff_t offset = slot->byteSize() + slot->offsetFromFP();
161         for (size_t i = result.size(); i--;) {
162             result.at(i) = RegisterAtOffset(
163                 result.at(i).reg(),
164                 result.at(i).offset() + offset);
165         }
166     }
167     return result;
168 }
169
170 void Code::resetReachability()
171 {
172     clearPredecessors(m_blocks);
173     if (m_entrypoints.isEmpty())
174         updatePredecessorsAfter(m_blocks[0].get());
175     else {
176         for (const FrequentedBlock& entrypoint : m_entrypoints)
177             updatePredecessorsAfter(entrypoint.block());
178     }
179     
180     for (auto& block : m_blocks) {
181         if (isBlockDead(block.get()) && !isEntrypoint(block.get()))
182             block = nullptr;
183     }
184 }
185
186 void Code::dump(PrintStream& out) const
187 {
188     if (!m_entrypoints.isEmpty())
189         out.print("Entrypoints: ", listDump(m_entrypoints), "\n");
190     for (BasicBlock* block : *this)
191         out.print(deepDump(block));
192     if (stackSlots().size()) {
193         out.print("Stack slots:\n");
194         for (StackSlot* slot : stackSlots())
195             out.print("    ", pointerDump(slot), ": ", deepDump(slot), "\n");
196     }
197     if (specials().size()) {
198         out.print("Specials:\n");
199         for (Special* special : specials())
200             out.print("    ", deepDump(special), "\n");
201     }
202     if (m_frameSize || m_stackIsAllocated)
203         out.print("Frame size: ", m_frameSize, m_stackIsAllocated ? " (Allocated)" : "", "\n");
204     if (m_callArgAreaSize)
205         out.print("Call arg area size: ", m_callArgAreaSize, "\n");
206     RegisterAtOffsetList calleeSaveRegisters = this->calleeSaveRegisterAtOffsetList();
207     if (calleeSaveRegisters.size())
208         out.print("Callee saves: ", calleeSaveRegisters, "\n");
209 }
210
211 unsigned Code::findFirstBlockIndex(unsigned index) const
212 {
213     while (index < size() && !at(index))
214         index++;
215     return index;
216 }
217
218 unsigned Code::findNextBlockIndex(unsigned index) const
219 {
220     return findFirstBlockIndex(index + 1);
221 }
222
223 BasicBlock* Code::findNextBlock(BasicBlock* block) const
224 {
225     unsigned index = findNextBlockIndex(block->index());
226     if (index < size())
227         return at(index);
228     return nullptr;
229 }
230
231 void Code::addFastTmp(Tmp tmp)
232 {
233     m_fastTmps.add(tmp);
234 }
235
236 void* Code::addDataSection(size_t size)
237 {
238     return m_proc.addDataSection(size);
239 }
240
241 unsigned Code::jsHash() const
242 {
243     unsigned result = 0;
244     
245     for (BasicBlock* block : *this) {
246         result *= 1000001;
247         for (Inst& inst : *block) {
248             result *= 97;
249             result += inst.jsHash();
250         }
251         for (BasicBlock* successor : block->successorBlocks()) {
252             result *= 7;
253             result += successor->index();
254         }
255     }
256     for (StackSlot* slot : stackSlots()) {
257         result *= 101;
258         result += slot->jsHash();
259     }
260     
261     return result;
262 }
263
264 } } } // namespace JSC::B3::Air
265
266 #endif // ENABLE(B3_JIT)