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 | #pragma once |
27 | |
28 | #if ENABLE(B3_JIT) |
29 | |
30 | #include "AirBasicBlock.h" |
31 | #include "AirCFG.h" |
32 | #include "AirCode.h" |
33 | #include "AirInstInlines.h" |
34 | #include "AirStackSlot.h" |
35 | #include "AirTmpInlines.h" |
36 | #include <wtf/IndexMap.h> |
37 | |
38 | namespace JSC { namespace B3 { namespace Air { |
39 | |
40 | template<typename Adapter> |
41 | struct LivenessAdapter { |
42 | typedef Air::CFG CFG; |
43 | |
44 | typedef Vector<unsigned, 4> ActionsList; |
45 | |
46 | struct Actions { |
47 | Actions() { } |
48 | |
49 | ActionsList use; |
50 | ActionsList def; |
51 | }; |
52 | |
53 | typedef Vector<Actions, 0, UnsafeVectorOverflow> ActionsForBoundary; |
54 | |
55 | LivenessAdapter(Code& code) |
56 | : code(code) |
57 | , actions(code.size()) |
58 | { |
59 | } |
60 | |
61 | Adapter& adapter() |
62 | { |
63 | return *static_cast<Adapter*>(this); |
64 | } |
65 | |
66 | void prepareToCompute() |
67 | { |
68 | for (BasicBlock* block : code) { |
69 | ActionsForBoundary& actionsForBoundary = actions[block]; |
70 | actionsForBoundary.resize(block->size() + 1); |
71 | |
72 | for (size_t instIndex = block->size(); instIndex--;) { |
73 | Inst& inst = block->at(instIndex); |
74 | inst.forEach<typename Adapter::Thing>( |
75 | [&] (typename Adapter::Thing& thing, Arg::Role role, Bank bank, Width) { |
76 | if (!Adapter::acceptsBank(bank) || !Adapter::acceptsRole(role)) |
77 | return; |
78 | |
79 | unsigned index = adapter().valueToIndex(thing); |
80 | |
81 | if (Arg::isEarlyUse(role)) |
82 | actionsForBoundary[instIndex].use.appendIfNotContains(index); |
83 | if (Arg::isEarlyDef(role)) |
84 | actionsForBoundary[instIndex].def.appendIfNotContains(index); |
85 | if (Arg::isLateUse(role)) |
86 | actionsForBoundary[instIndex + 1].use.appendIfNotContains(index); |
87 | if (Arg::isLateDef(role)) |
88 | actionsForBoundary[instIndex + 1].def.appendIfNotContains(index); |
89 | }); |
90 | } |
91 | } |
92 | } |
93 | |
94 | Actions& actionsAt(BasicBlock* block, unsigned instBoundaryIndex) |
95 | { |
96 | return actions[block][instBoundaryIndex]; |
97 | } |
98 | |
99 | unsigned blockSize(BasicBlock* block) |
100 | { |
101 | return block->size(); |
102 | } |
103 | |
104 | template<typename Func> |
105 | void forEachUse(BasicBlock* block, size_t instBoundaryIndex, const Func& func) |
106 | { |
107 | for (unsigned index : actionsAt(block, instBoundaryIndex).use) |
108 | func(index); |
109 | } |
110 | |
111 | template<typename Func> |
112 | void forEachDef(BasicBlock* block, size_t instBoundaryIndex, const Func& func) |
113 | { |
114 | for (unsigned index : actionsAt(block, instBoundaryIndex).def) |
115 | func(index); |
116 | } |
117 | |
118 | Code& code; |
119 | IndexMap<BasicBlock*, ActionsForBoundary> actions; |
120 | }; |
121 | |
122 | template<Bank adapterBank, Arg::Temperature minimumTemperature = Arg::Cold> |
123 | struct TmpLivenessAdapter : LivenessAdapter<TmpLivenessAdapter<adapterBank, minimumTemperature>> { |
124 | typedef LivenessAdapter<TmpLivenessAdapter<adapterBank, minimumTemperature>> Base; |
125 | |
126 | static constexpr const char* name = "TmpLiveness" ; |
127 | typedef Tmp Thing; |
128 | |
129 | TmpLivenessAdapter(Code& code) |
130 | : Base(code) |
131 | { |
132 | } |
133 | |
134 | unsigned numIndices() |
135 | { |
136 | return Tmp::absoluteIndexEnd(Base::code, adapterBank); |
137 | } |
138 | static bool acceptsBank(Bank bank) { return bank == adapterBank; } |
139 | static bool acceptsRole(Arg::Role role) { return Arg::temperature(role) >= minimumTemperature; } |
140 | static unsigned valueToIndex(Tmp tmp) { return AbsoluteTmpMapper<adapterBank>::absoluteIndex(tmp); } |
141 | static Tmp indexToValue(unsigned index) { return AbsoluteTmpMapper<adapterBank>::tmpFromAbsoluteIndex(index); } |
142 | }; |
143 | |
144 | struct UnifiedTmpLivenessAdapter : LivenessAdapter<UnifiedTmpLivenessAdapter> { |
145 | typedef LivenessAdapter<UnifiedTmpLivenessAdapter> Base; |
146 | |
147 | static constexpr const char* name = "UnifiedTmpLiveness" ; |
148 | |
149 | typedef Tmp Thing; |
150 | |
151 | UnifiedTmpLivenessAdapter(Code& code) |
152 | : Base(code) |
153 | { |
154 | } |
155 | |
156 | unsigned numIndices() |
157 | { |
158 | return Tmp::linearIndexEnd(code); |
159 | } |
160 | |
161 | static bool acceptsBank(Bank) { return true; } |
162 | static bool acceptsRole(Arg::Role) { return true; } |
163 | unsigned valueToIndex(Tmp tmp) { return tmp.linearlyIndexed(code).index(); } |
164 | Tmp indexToValue(unsigned index) { return Tmp::tmpForLinearIndex(code, index); } |
165 | }; |
166 | |
167 | struct StackSlotLivenessAdapter : LivenessAdapter<StackSlotLivenessAdapter> { |
168 | static constexpr const char* name = "StackSlotLiveness" ; |
169 | typedef StackSlot* Thing; |
170 | |
171 | StackSlotLivenessAdapter(Code& code) |
172 | : LivenessAdapter(code) |
173 | { |
174 | } |
175 | |
176 | unsigned numIndices() |
177 | { |
178 | return code.stackSlots().size(); |
179 | } |
180 | static bool acceptsBank(Bank) { return true; } |
181 | static bool acceptsRole(Arg::Role) { return true; } |
182 | static unsigned valueToIndex(StackSlot* stackSlot) { return stackSlot->index(); } |
183 | StackSlot* indexToValue(unsigned index) { return code.stackSlots()[index]; } |
184 | }; |
185 | |
186 | } } } // namespace JSC::B3::Air |
187 | |
188 | #endif // ENABLE(B3_JIT) |
189 | |
190 | |