OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2013 the V8 project authors. All rights reserved. | |
2 // Redistribution and use in source and binary forms, with or without | |
3 // modification, are permitted provided that the following conditions are | |
4 // met: | |
5 // | |
6 // * Redistributions of source code must retain the above copyright | |
7 // notice, this list of conditions and the following disclaimer. | |
8 // * Redistributions in binary form must reproduce the above | |
9 // copyright notice, this list of conditions and the following | |
10 // disclaimer in the documentation and/or other materials provided | |
11 // with the distribution. | |
12 // * Neither the name of Google Inc. nor the names of its | |
13 // contributors may be used to endorse or promote products derived | |
14 // from this software without specific prior written permission. | |
15 // | |
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
27 | |
28 #include "hydrogen-uint32-analysis.h" | |
29 | |
30 namespace v8 { | |
31 namespace internal { | |
32 | |
33 | |
34 bool HUint32AnalysisPhase::IsSafeUint32Use(HValue* val, HValue* use) { | |
35 // Operations that operate on bits are safe. | |
36 if (use->IsBitwise() || | |
37 use->IsShl() || | |
38 use->IsSar() || | |
39 use->IsShr() || | |
40 use->IsBitNot()) { | |
41 return true; | |
42 } else if (use->IsChange() || use->IsSimulate()) { | |
43 // Conversions and deoptimization have special support for unt32. | |
44 return true; | |
45 } else if (use->IsStoreKeyed()) { | |
46 HStoreKeyed* store = HStoreKeyed::cast(use); | |
47 if (store->is_external()) { | |
48 // Storing a value into an external integer array is a bit level | |
49 // operation. | |
50 if (store->value() == val) { | |
51 // Clamping or a conversion to double should have beed inserted. | |
52 ASSERT(store->elements_kind() != EXTERNAL_PIXEL_ELEMENTS); | |
53 ASSERT(store->elements_kind() != EXTERNAL_FLOAT_ELEMENTS); | |
54 ASSERT(store->elements_kind() != EXTERNAL_DOUBLE_ELEMENTS); | |
55 return true; | |
56 } | |
57 } | |
58 } | |
59 | |
60 return false; | |
61 } | |
62 | |
63 | |
64 // Iterate over all uses and verify that they are uint32 safe: either don't | |
65 // distinguish between int32 and uint32 due to their bitwise nature or | |
66 // have special support for uint32 values. | |
67 // Encountered phis are optimisitically treated as safe uint32 uses, | |
Jakob Kummerow
2013/07/02 09:16:40
nit: optimistically
| |
68 // marked with kUint32 flag and collected in the phis_ list. A separate | |
69 // path will be performed later by UnmarkUnsafePhis to clear kUint32 from | |
Jakob Kummerow
2013/07/02 09:16:40
nit: s/path/pass/
| |
70 // phis that are not actually uint32-safe (it requries fix point iteration). | |
Jakob Kummerow
2013/07/02 09:16:40
nit: requires
| |
71 bool HUint32AnalysisPhase::Uint32UsesAreSafe(HValue* uint32val) { | |
72 bool collect_phi_uses = false; | |
73 for (HUseIterator it(uint32val->uses()); !it.Done(); it.Advance()) { | |
74 HValue* use = it.value(); | |
75 | |
76 if (use->IsPhi()) { | |
77 if (!use->CheckFlag(HInstruction::kUint32)) { | |
78 // There is a phi use of this value from a phis that is not yet | |
Jakob Kummerow
2013/07/02 09:16:40
nit: "from a phi that..."
| |
79 // collected in phis_ array. Separate pass is required. | |
80 collect_phi_uses = true; | |
81 } | |
82 | |
83 // Optimistically treat phis as uint32 safe. | |
84 continue; | |
85 } | |
86 | |
87 if (!IsSafeUint32Use(uint32val, use)) { | |
88 return false; | |
89 } | |
90 } | |
91 | |
92 if (collect_phi_uses) { | |
93 for (HUseIterator it(uint32val->uses()); !it.Done(); it.Advance()) { | |
94 HValue* use = it.value(); | |
95 | |
96 // There is a phi use of this value from a phis that is not yet | |
Jakob Kummerow
2013/07/02 09:16:40
nit: "from a phi that..."
| |
97 // collected in phis_ array. Separate pass is required. | |
98 if (use->IsPhi() && !use->CheckFlag(HInstruction::kUint32)) { | |
99 use->SetFlag(HInstruction::kUint32); | |
100 phis_.Add(HPhi::cast(use), zone()); | |
101 } | |
102 } | |
103 } | |
104 | |
105 return true; | |
106 } | |
107 | |
108 | |
109 // Check if all operands to the given phi are marked with kUint32 flag. | |
110 bool HUint32AnalysisPhase::CheckPhiOperands(HPhi* phi) { | |
111 if (!phi->CheckFlag(HInstruction::kUint32)) { | |
112 // This phi is not uint32 safe. No need to check operands. | |
113 return false; | |
114 } | |
115 | |
116 for (int j = 0; j < phi->OperandCount(); j++) { | |
117 HValue* operand = phi->OperandAt(j); | |
118 if (!operand->CheckFlag(HInstruction::kUint32)) { | |
119 // Lazyly mark constants that fit into uint32 range with kUint32 flag. | |
Jakob Kummerow
2013/07/02 09:16:40
nit: Lazily
| |
120 if (operand->IsInteger32Constant() && | |
121 operand->GetInteger32Constant() >= 0) { | |
122 operand->SetFlag(HInstruction::kUint32); | |
123 continue; | |
124 } | |
125 | |
126 // This phi is not safe, some operands are not uint32 values. | |
127 return false; | |
128 } | |
129 } | |
130 | |
131 return true; | |
132 } | |
133 | |
134 | |
135 // Remove kUint32 flag from the phi itself and its operands. If any operand | |
136 // was a phi marked with kUint32 place it into a worklist for | |
137 // transitive clearing of kUint32 flag. | |
138 void HUint32AnalysisPhase::UnmarkPhi(HPhi* phi, ZoneList<HPhi*>* worklist) { | |
139 phi->ClearFlag(HInstruction::kUint32); | |
140 for (int j = 0; j < phi->OperandCount(); j++) { | |
141 HValue* operand = phi->OperandAt(j); | |
142 if (operand->CheckFlag(HInstruction::kUint32)) { | |
143 operand->ClearFlag(HInstruction::kUint32); | |
144 if (operand->IsPhi()) { | |
145 worklist->Add(HPhi::cast(operand), zone()); | |
146 } | |
147 } | |
148 } | |
149 } | |
150 | |
151 | |
152 void HUint32AnalysisPhase::UnmarkUnsafePhis() { | |
153 // No phis were collected. Nothing to do. | |
154 if (phis_.length() == 0) return; | |
155 | |
156 // Worklist used to transitively clear kUint32 from phis that | |
157 // are used as arguments to other phis. | |
158 ZoneList<HPhi*> worklist(phis_.length(), zone()); | |
159 | |
160 // Phi can be used as a uint32 value if and only if | |
161 // all its operands are uint32 values and all its | |
162 // uses are uint32 safe. | |
163 | |
164 // Iterate over collected phis and unmark those that | |
165 // are unsafe. When unmarking phi unmark its operands | |
166 // and add it to the worklist if it is a phi as well. | |
167 // Phis that are still marked as safe are shifted down | |
168 // so that all safe phis form a prefix of the phis_ array. | |
169 int phi_count = 0; | |
170 for (int i = 0; i < phis_.length(); i++) { | |
171 HPhi* phi = phis_[i]; | |
172 | |
173 if (CheckPhiOperands(phi) && Uint32UsesAreSafe(phi)) { | |
174 phis_[phi_count++] = phi; | |
175 } else { | |
176 UnmarkPhi(phi, &worklist); | |
177 } | |
178 } | |
179 | |
180 // Now phis array contains only those phis that have safe | |
181 // non-phi uses. Start transitively clearing kUint32 flag | |
182 // from phi operands of discovered non-safe phies until | |
183 // only safe phies are left. | |
184 while (!worklist.is_empty()) { | |
185 while (!worklist.is_empty()) { | |
186 HPhi* phi = worklist.RemoveLast(); | |
187 UnmarkPhi(phi, &worklist); | |
188 } | |
189 | |
190 // Check if any operands to safe phies were unmarked | |
Jakob Kummerow
2013/07/02 09:16:40
nit: s/phies/phis/
| |
191 // turning a safe phi into unsafe. The same value | |
192 // can flow into several phis. | |
193 int new_phi_count = 0; | |
194 for (int i = 0; i < phi_count; i++) { | |
195 HPhi* phi = phis_[i]; | |
196 | |
197 if (CheckPhiOperands(phi)) { | |
198 phis_[new_phi_count++] = phi; | |
199 } else { | |
200 UnmarkPhi(phi, &worklist); | |
201 } | |
202 } | |
203 phi_count = new_phi_count; | |
204 } | |
205 } | |
206 | |
207 | |
208 void HUint32AnalysisPhase::Run() { | |
209 if (!graph()->has_uint32_instructions()) return; | |
210 | |
211 ZoneList<HInstruction*>* uint32_instructions = graph()->uint32_instructions(); | |
212 for (int i = 0; i < uint32_instructions->length(); ++i) { | |
213 // Analyze instruction and mark it with kUint32 if all | |
214 // its uses are uint32 safe. | |
215 HInstruction* current = uint32_instructions->at(i); | |
216 if (Uint32UsesAreSafe(current)) current->SetFlag(HInstruction::kUint32); | |
217 } | |
218 | |
219 // Some phis might have been optimistically marked with kUint32 flag. | |
220 // Remove this flag from those phis that are unsafe and propagate | |
221 // this information transitively potentially clearing kUint32 flag | |
222 // from some non-phi operations that are used as operands to unsafe phis. | |
223 UnmarkUnsafePhis(); | |
224 } | |
225 | |
226 | |
227 } } // namespace v8::internal | |
OLD | NEW |