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() || use->IsShl() || use->IsSar() || use->IsShr()) { 37 return true; 38 } else if (use->IsSimulate()) { 39 // Deoptimization has special support for uint32. 40 return true; 41 } else if (use->IsChange()) { 42 // Conversions have special support for uint32. 43 // This ASSERT guards that the conversion in question is actually 44 // implemented. Do not extend the whitelist without adding 45 // support to LChunkBuilder::DoChange(). 46 ASSERT(HChange::cast(use)->to().IsDouble() || 47 HChange::cast(use)->to().IsSmi() || 48 HChange::cast(use)->to().IsTagged()); 49 return true; 50 } else if (use->IsStoreKeyed()) { 51 HStoreKeyed* store = HStoreKeyed::cast(use); 52 if (store->is_external()) { 53 // Storing a value into an external integer array is a bit level 54 // operation. 55 if (store->value() == val) { 56 // Clamping or a conversion to double should have beed inserted. 57 ASSERT(store->elements_kind() != EXTERNAL_PIXEL_ELEMENTS); 58 ASSERT(store->elements_kind() != EXTERNAL_FLOAT_ELEMENTS); 59 ASSERT(store->elements_kind() != EXTERNAL_DOUBLE_ELEMENTS); 60 return true; 61 } 62 } 63 } 64 65 return false; 66 } 67 68 69 // Iterate over all uses and verify that they are uint32 safe: either don't 70 // distinguish between int32 and uint32 due to their bitwise nature or 71 // have special support for uint32 values. 72 // Encountered phis are optimistically treated as safe uint32 uses, 73 // marked with kUint32 flag and collected in the phis_ list. A separate 74 // pass will be performed later by UnmarkUnsafePhis to clear kUint32 from 75 // phis that are not actually uint32-safe (it requires fix point iteration). 76 bool HUint32AnalysisPhase::Uint32UsesAreSafe(HValue* uint32val) { 77 bool collect_phi_uses = false; 78 for (HUseIterator it(uint32val->uses()); !it.Done(); it.Advance()) { 79 HValue* use = it.value(); 80 81 if (use->IsPhi()) { 82 if (!use->CheckFlag(HInstruction::kUint32)) { 83 // There is a phi use of this value from a phi that is not yet 84 // collected in phis_ array. Separate pass is required. 85 collect_phi_uses = true; 86 } 87 88 // Optimistically treat phis as uint32 safe. 89 continue; 90 } 91 92 if (!IsSafeUint32Use(uint32val, use)) { 93 return false; 94 } 95 } 96 97 if (collect_phi_uses) { 98 for (HUseIterator it(uint32val->uses()); !it.Done(); it.Advance()) { 99 HValue* use = it.value(); 100 101 // There is a phi use of this value from a phi that is not yet 102 // collected in phis_ array. Separate pass is required. 103 if (use->IsPhi() && !use->CheckFlag(HInstruction::kUint32)) { 104 use->SetFlag(HInstruction::kUint32); 105 phis_.Add(HPhi::cast(use), zone()); 106 } 107 } 108 } 109 110 return true; 111 } 112 113 114 // Check if all operands to the given phi are marked with kUint32 flag. 115 bool HUint32AnalysisPhase::CheckPhiOperands(HPhi* phi) { 116 if (!phi->CheckFlag(HInstruction::kUint32)) { 117 // This phi is not uint32 safe. No need to check operands. 118 return false; 119 } 120 121 for (int j = 0; j < phi->OperandCount(); j++) { 122 HValue* operand = phi->OperandAt(j); 123 if (!operand->CheckFlag(HInstruction::kUint32)) { 124 // Lazily mark constants that fit into uint32 range with kUint32 flag. 125 if (operand->IsInteger32Constant() && 126 operand->GetInteger32Constant() >= 0) { 127 operand->SetFlag(HInstruction::kUint32); 128 continue; 129 } 130 131 // This phi is not safe, some operands are not uint32 values. 132 return false; 133 } 134 } 135 136 return true; 137 } 138 139 140 // Remove kUint32 flag from the phi itself and its operands. If any operand 141 // was a phi marked with kUint32 place it into a worklist for 142 // transitive clearing of kUint32 flag. 143 void HUint32AnalysisPhase::UnmarkPhi(HPhi* phi, ZoneList<HPhi*>* worklist) { 144 phi->ClearFlag(HInstruction::kUint32); 145 for (int j = 0; j < phi->OperandCount(); j++) { 146 HValue* operand = phi->OperandAt(j); 147 if (operand->CheckFlag(HInstruction::kUint32)) { 148 operand->ClearFlag(HInstruction::kUint32); 149 if (operand->IsPhi()) { 150 worklist->Add(HPhi::cast(operand), zone()); 151 } 152 } 153 } 154 } 155 156 157 void HUint32AnalysisPhase::UnmarkUnsafePhis() { 158 // No phis were collected. Nothing to do. 159 if (phis_.length() == 0) return; 160 161 // Worklist used to transitively clear kUint32 from phis that 162 // are used as arguments to other phis. 163 ZoneList<HPhi*> worklist(phis_.length(), zone()); 164 165 // Phi can be used as a uint32 value if and only if 166 // all its operands are uint32 values and all its 167 // uses are uint32 safe. 168 169 // Iterate over collected phis and unmark those that 170 // are unsafe. When unmarking phi unmark its operands 171 // and add it to the worklist if it is a phi as well. 172 // Phis that are still marked as safe are shifted down 173 // so that all safe phis form a prefix of the phis_ array. 174 int phi_count = 0; 175 for (int i = 0; i < phis_.length(); i++) { 176 HPhi* phi = phis_[i]; 177 178 if (CheckPhiOperands(phi) && Uint32UsesAreSafe(phi)) { 179 phis_[phi_count++] = phi; 180 } else { 181 UnmarkPhi(phi, &worklist); 182 } 183 } 184 185 // Now phis array contains only those phis that have safe 186 // non-phi uses. Start transitively clearing kUint32 flag 187 // from phi operands of discovered non-safe phis until 188 // only safe phis are left. 189 while (!worklist.is_empty()) { 190 while (!worklist.is_empty()) { 191 HPhi* phi = worklist.RemoveLast(); 192 UnmarkPhi(phi, &worklist); 193 } 194 195 // Check if any operands to safe phis were unmarked 196 // turning a safe phi into unsafe. The same value 197 // can flow into several phis. 198 int new_phi_count = 0; 199 for (int i = 0; i < phi_count; i++) { 200 HPhi* phi = phis_[i]; 201 202 if (CheckPhiOperands(phi)) { 203 phis_[new_phi_count++] = phi; 204 } else { 205 UnmarkPhi(phi, &worklist); 206 } 207 } 208 phi_count = new_phi_count; 209 } 210 } 211 212 213 void HUint32AnalysisPhase::Run() { 214 if (!graph()->has_uint32_instructions()) return; 215 216 ZoneList<HInstruction*>* uint32_instructions = graph()->uint32_instructions(); 217 for (int i = 0; i < uint32_instructions->length(); ++i) { 218 // Analyze instruction and mark it with kUint32 if all 219 // its uses are uint32 safe. 220 HInstruction* current = uint32_instructions->at(i); 221 if (current->IsLinked() && 222 current->representation().IsInteger32() && 223 Uint32UsesAreSafe(current)) { 224 current->SetFlag(HInstruction::kUint32); 225 } 226 } 227 228 // Some phis might have been optimistically marked with kUint32 flag. 229 // Remove this flag from those phis that are unsafe and propagate 230 // this information transitively potentially clearing kUint32 flag 231 // from some non-phi operations that are used as operands to unsafe phis. 232 UnmarkUnsafePhis(); 233 } 234 235 236 } } // namespace v8::internal 237