Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM. |
| 6 #if defined(TARGET_ARCH_ARM) | 6 #if defined(TARGET_ARCH_ARM) |
| 7 | 7 |
| 8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
| 9 | 9 |
| 10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 102 | 102 |
| 103 // No need to generate NOP instructions so that the debugger can patch the | 103 // No need to generate NOP instructions so that the debugger can patch the |
| 104 // return pattern (3 instructions) with a call to the debug stub (also 3 | 104 // return pattern (3 instructions) with a call to the debug stub (also 3 |
| 105 // instructions). | 105 // instructions). |
| 106 compiler->AddCurrentDescriptor(PcDescriptors::kReturn, | 106 compiler->AddCurrentDescriptor(PcDescriptors::kReturn, |
| 107 Isolate::kNoDeoptId, | 107 Isolate::kNoDeoptId, |
| 108 token_pos()); | 108 token_pos()); |
| 109 } | 109 } |
| 110 | 110 |
| 111 | 111 |
| 112 static Condition NegateCondition(Condition condition) { | |
| 113 switch (condition) { | |
| 114 case EQ: return NE; | |
| 115 case NE: return EQ; | |
| 116 case LT: return GE; | |
| 117 case LE: return GT; | |
| 118 case GT: return LE; | |
| 119 case GE: return LT; | |
| 120 case CC: return CS; | |
| 121 case LS: return HI; | |
| 122 case HI: return LS; | |
| 123 case CS: return CC; | |
| 124 default: | |
| 125 UNREACHABLE(); | |
| 126 return EQ; | |
| 127 } | |
| 128 } | |
| 129 | |
| 130 | |
| 131 static bool BindsToSmiConstant(Value* val, intptr_t* smi_value) { | |
| 132 if (!val->BindsToConstant()) { | |
| 133 return false; | |
| 134 } | |
| 135 | |
| 136 const Object& bound_constant = val->BoundConstant(); | |
| 137 if (!bound_constant.IsSmi()) { | |
| 138 return false; | |
| 139 } | |
| 140 | |
| 141 *smi_value = Smi::Cast(bound_constant).Value(); | |
| 142 return true; | |
| 143 } | |
| 144 | |
| 145 | |
| 146 // Detect pattern when one value is zero and another is a power of 2. | |
| 147 static bool IsPowerOfTwoKind(intptr_t v1, intptr_t v2) { | |
| 148 return (Utils::IsPowerOfTwo(v1) && (v2 == 0)) || | |
| 149 (Utils::IsPowerOfTwo(v2) && (v1 == 0)); | |
| 150 } | |
| 151 | |
| 152 | |
| 112 bool IfThenElseInstr::IsSupported() { | 153 bool IfThenElseInstr::IsSupported() { |
|
Florian Schneider
2013/11/05 16:57:53
Now that IsSupported is true on all platform, you
zra
2013/11/05 18:32:13
Done.
| |
| 113 return false; | 154 return true; |
| 114 } | 155 } |
| 115 | 156 |
| 116 | 157 |
| 117 bool IfThenElseInstr::Supports(ComparisonInstr* comparison, | 158 bool IfThenElseInstr::Supports(ComparisonInstr* comparison, |
| 118 Value* v1, | 159 Value* v1, |
| 119 Value* v2) { | 160 Value* v2) { |
| 120 UNREACHABLE(); | 161 if (!(comparison->IsStrictCompare() && |
| 121 return false; | 162 !comparison->AsStrictCompare()->needs_number_check()) && |
| 163 !(comparison->IsEqualityCompare() && | |
| 164 (comparison->AsEqualityCompare()->operation_cid() == kSmiCid))) { | |
| 165 return false; | |
| 166 } | |
| 167 | |
| 168 intptr_t v1_value, v2_value; | |
| 169 | |
| 170 if (!BindsToSmiConstant(v1, &v1_value) || | |
| 171 !BindsToSmiConstant(v2, &v2_value)) { | |
| 172 return false; | |
| 173 } | |
| 174 | |
| 175 return true; | |
| 122 } | 176 } |
| 123 | 177 |
| 124 | 178 |
| 125 LocationSummary* IfThenElseInstr::MakeLocationSummary() const { | 179 LocationSummary* IfThenElseInstr::MakeLocationSummary() const { |
| 126 UNREACHABLE(); | 180 const intptr_t kNumInputs = 2; |
| 127 return NULL; | 181 const intptr_t kNumTemps = 0; |
| 182 LocationSummary* locs = | |
| 183 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | |
| 184 locs->set_in(0, Location::RegisterOrConstant(left())); | |
| 185 locs->set_in(1, Location::RegisterOrConstant(right())); | |
| 186 // TODO(vegorov): support byte register constraints in the register allocator. | |
|
Florian Schneider
2013/11/05 16:57:53
This TODO is not relevant here.
zra
2013/11/05 18:32:13
Done.
| |
| 187 locs->set_out(Location::RegisterLocation(R0)); | |
| 188 return locs; | |
| 128 } | 189 } |
| 129 | 190 |
| 130 | 191 |
| 131 void IfThenElseInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 192 void IfThenElseInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 132 UNREACHABLE(); | 193 const Register result = locs()->out().reg(); |
| 194 ASSERT(result == R0); | |
| 195 ASSERT(Token::IsEqualityOperator(kind())); | |
| 196 | |
| 197 Location left = locs()->in(0); | |
| 198 Location right = locs()->in(1); | |
| 199 if (left.IsConstant() && right.IsConstant()) { | |
| 200 // TODO(srdjan): Determine why this instruction was not eliminated. | |
| 201 bool res = (left.constant().raw() == right.constant().raw()); | |
| 202 if ((kind_ == Token::kNE_STRICT) || (kind_ == Token::kNE)) { | |
| 203 res = !res; | |
| 204 } | |
| 205 __ LoadImmediate(locs()->out().reg(), | |
| 206 reinterpret_cast<int32_t>(Smi::New(res ? if_true_ : if_false_))); | |
| 207 return; | |
| 208 } | |
| 209 | |
| 210 ASSERT(!left.IsConstant() || !right.IsConstant()); | |
| 211 | |
| 212 // Clear upper part of the out register. We are going to use setcc on it | |
|
Florian Schneider
2013/11/05 16:57:53
Update this comment for ARM.
zra
2013/11/05 18:32:13
Done.
| |
| 213 // which is a byte move. | |
| 214 __ eor(result, result, ShifterOperand(result)); | |
| 215 | |
| 216 // Compare left and right. For now only equality comparison is supported. | |
| 217 // TODO(vegorov): reuse code from the other comparison instructions instead of | |
| 218 // generating it inline here. | |
| 219 if (left.IsConstant()) { | |
| 220 __ CompareObject(right.reg(), left.constant()); | |
| 221 } else if (right.IsConstant()) { | |
| 222 __ CompareObject(left.reg(), right.constant()); | |
| 223 } else { | |
| 224 __ cmp(left.reg(), ShifterOperand(right.reg())); | |
| 225 } | |
| 226 | |
| 227 Condition true_condition = | |
| 228 ((kind_ == Token::kEQ_STRICT) || (kind_ == Token::kEQ)) ? EQ : NE; | |
| 229 | |
| 230 const bool is_power_of_two_kind = IsPowerOfTwoKind(if_true_, if_false_); | |
| 231 | |
| 232 intptr_t true_value = if_true_; | |
| 233 intptr_t false_value = if_false_; | |
| 234 | |
| 235 if (is_power_of_two_kind) { | |
| 236 if (true_value == 0) { | |
| 237 // We need to have zero in result on true_condition. | |
| 238 true_condition = NegateCondition(true_condition); | |
| 239 } | |
| 240 } else { | |
| 241 if (true_value == 0) { | |
| 242 // Swap values so that false_value is zero. | |
| 243 intptr_t temp = true_value; | |
| 244 true_value = false_value; | |
| 245 false_value = temp; | |
| 246 } else { | |
| 247 true_condition = NegateCondition(true_condition); | |
| 248 } | |
| 249 } | |
| 250 | |
| 251 __ mov(result, ShifterOperand(1), true_condition); | |
| 252 | |
| 253 if (is_power_of_two_kind) { | |
| 254 const intptr_t shift = | |
| 255 Utils::ShiftForPowerOfTwo(Utils::Maximum(true_value, false_value)); | |
| 256 __ Lsl(result, result, shift + kSmiTagSize); | |
| 257 } else { | |
| 258 __ sub(result, result, ShifterOperand(1)); | |
| 259 const int32_t val = | |
| 260 Smi::RawValue(true_value) - Smi::RawValue(false_value); | |
| 261 ShifterOperand op; | |
| 262 if (ShifterOperand::CanHold(val, &op)) { | |
|
Florian Schneider
2013/11/05 16:57:53
I'd add an AndImmediate macro-instruction for this
zra
2013/11/05 18:32:13
Done.
| |
| 263 __ and_(result, result, ShifterOperand(op)); | |
| 264 } else { | |
| 265 __ LoadImmediate(TMP, val); | |
| 266 __ and_(result, result, ShifterOperand(TMP)); | |
| 267 } | |
| 268 if (false_value != 0) { | |
| 269 __ AddImmediate(result, Smi::RawValue(false_value)); | |
| 270 } | |
| 271 } | |
| 133 } | 272 } |
| 134 | 273 |
| 135 | 274 |
| 136 LocationSummary* ClosureCallInstr::MakeLocationSummary() const { | 275 LocationSummary* ClosureCallInstr::MakeLocationSummary() const { |
| 137 const intptr_t kNumInputs = 0; | 276 const intptr_t kNumInputs = 0; |
| 138 const intptr_t kNumTemps = 1; | 277 const intptr_t kNumTemps = 1; |
| 139 LocationSummary* result = | 278 LocationSummary* result = |
| 140 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); | 279 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); |
| 141 result->set_out(Location::RegisterLocation(R0)); | 280 result->set_out(Location::RegisterLocation(R0)); |
| 142 result->set_temp(0, Location::RegisterLocation(R4)); // Arg. descriptor. | 281 result->set_temp(0, Location::RegisterLocation(R4)); // Arg. descriptor. |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 332 if (value_is_smi == NULL) { | 471 if (value_is_smi == NULL) { |
| 333 __ b(&done, EQ); | 472 __ b(&done, EQ); |
| 334 } else { | 473 } else { |
| 335 __ b(value_is_smi, EQ); | 474 __ b(value_is_smi, EQ); |
| 336 } | 475 } |
| 337 __ LoadClassId(value_cid_reg, value_reg); | 476 __ LoadClassId(value_cid_reg, value_reg); |
| 338 __ Bind(&done); | 477 __ Bind(&done); |
| 339 } | 478 } |
| 340 | 479 |
| 341 | 480 |
| 342 static Condition NegateCondition(Condition condition) { | |
| 343 switch (condition) { | |
| 344 case EQ: return NE; | |
| 345 case NE: return EQ; | |
| 346 case LT: return GE; | |
| 347 case LE: return GT; | |
| 348 case GT: return LE; | |
| 349 case GE: return LT; | |
| 350 case CC: return CS; | |
| 351 case LS: return HI; | |
| 352 case HI: return LS; | |
| 353 case CS: return CC; | |
| 354 default: | |
| 355 UNREACHABLE(); | |
| 356 return EQ; | |
| 357 } | |
| 358 } | |
| 359 | |
| 360 | |
| 361 static Condition FlipCondition(Condition condition) { | 481 static Condition FlipCondition(Condition condition) { |
| 362 switch (condition) { | 482 switch (condition) { |
| 363 case EQ: return EQ; | 483 case EQ: return EQ; |
| 364 case NE: return NE; | 484 case NE: return NE; |
| 365 case LT: return GT; | 485 case LT: return GT; |
| 366 case LE: return GE; | 486 case LE: return GE; |
| 367 case GT: return LT; | 487 case GT: return LT; |
| 368 case GE: return LE; | 488 case GE: return LE; |
| 369 case CC: return HI; | 489 case CC: return HI; |
| 370 case LS: return CS; | 490 case LS: return CS; |
| (...skipping 4065 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4436 compiler->GenerateCall(token_pos(), | 4556 compiler->GenerateCall(token_pos(), |
| 4437 &label, | 4557 &label, |
| 4438 PcDescriptors::kOther, | 4558 PcDescriptors::kOther, |
| 4439 locs()); | 4559 locs()); |
| 4440 __ Drop(2); // Discard type arguments and receiver. | 4560 __ Drop(2); // Discard type arguments and receiver. |
| 4441 } | 4561 } |
| 4442 | 4562 |
| 4443 } // namespace dart | 4563 } // namespace dart |
| 4444 | 4564 |
| 4445 #endif // defined TARGET_ARCH_ARM | 4565 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |