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_MIPS. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_MIPS. |
| 6 #if defined(TARGET_ARCH_MIPS) | 6 #if defined(TARGET_ARCH_MIPS) |
| 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 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 104 // This sequence is patched by a debugger breakpoint. There is no need for | 104 // This sequence is patched by a debugger breakpoint. There is no need for |
| 105 // extra NOP instructions here because the sequence patched in for a | 105 // extra NOP instructions here because the sequence patched in for a |
| 106 // breakpoint is shorter than the sequence here. | 106 // breakpoint is shorter than the sequence here. |
| 107 __ LeaveDartFrameAndReturn(); | 107 __ LeaveDartFrameAndReturn(); |
| 108 compiler->AddCurrentDescriptor(PcDescriptors::kReturn, | 108 compiler->AddCurrentDescriptor(PcDescriptors::kReturn, |
| 109 Isolate::kNoDeoptId, | 109 Isolate::kNoDeoptId, |
| 110 token_pos()); | 110 token_pos()); |
| 111 } | 111 } |
| 112 | 112 |
| 113 | 113 |
| 114 static Condition NegateCondition(Condition condition) { | |
| 115 switch (condition) { | |
| 116 case EQ: return NE; | |
| 117 case NE: return EQ; | |
| 118 case LT: return GE; | |
| 119 case LE: return GT; | |
| 120 case GT: return LE; | |
| 121 case GE: return LT; | |
| 122 default: | |
| 123 OS::Print("Error: Condition not recognized: %d\n", condition); | |
| 124 UNIMPLEMENTED(); | |
| 125 return EQ; | |
| 126 } | |
| 127 } | |
| 128 | |
| 129 | |
| 130 static bool BindsToSmiConstant(Value* val, intptr_t* smi_value) { | |
| 131 if (!val->BindsToConstant()) { | |
| 132 return false; | |
| 133 } | |
| 134 | |
| 135 const Object& bound_constant = val->BoundConstant(); | |
| 136 if (!bound_constant.IsSmi()) { | |
| 137 return false; | |
| 138 } | |
| 139 | |
| 140 *smi_value = Smi::Cast(bound_constant).Value(); | |
| 141 return true; | |
| 142 } | |
| 143 | |
| 144 | |
| 145 // Detect pattern when one value is zero and another is a power of 2. | |
| 146 static bool IsPowerOfTwoKind(intptr_t v1, intptr_t v2) { | |
| 147 return (Utils::IsPowerOfTwo(v1) && (v2 == 0)) || | |
| 148 (Utils::IsPowerOfTwo(v2) && (v1 == 0)); | |
| 149 } | |
| 150 | |
| 151 | |
| 114 bool IfThenElseInstr::IsSupported() { | 152 bool IfThenElseInstr::IsSupported() { |
| 115 return false; | 153 return true; |
| 116 } | 154 } |
| 117 | 155 |
| 118 | 156 |
| 119 bool IfThenElseInstr::Supports(ComparisonInstr* comparison, | 157 bool IfThenElseInstr::Supports(ComparisonInstr* comparison, |
| 120 Value* v1, | 158 Value* v1, |
| 121 Value* v2) { | 159 Value* v2) { |
| 122 UNREACHABLE(); | 160 if (!(comparison->IsStrictCompare() && |
| 123 return false; | 161 !comparison->AsStrictCompare()->needs_number_check()) && |
| 162 !(comparison->IsEqualityCompare() && | |
| 163 (comparison->AsEqualityCompare()->operation_cid() == kSmiCid))) { | |
| 164 return false; | |
| 165 } | |
| 166 | |
| 167 intptr_t v1_value, v2_value; | |
| 168 | |
| 169 if (!BindsToSmiConstant(v1, &v1_value) || | |
| 170 !BindsToSmiConstant(v2, &v2_value)) { | |
| 171 return false; | |
| 172 } | |
| 173 | |
| 174 return true; | |
| 124 } | 175 } |
| 125 | 176 |
| 126 | 177 |
| 127 LocationSummary* IfThenElseInstr::MakeLocationSummary() const { | 178 LocationSummary* IfThenElseInstr::MakeLocationSummary() const { |
| 128 UNREACHABLE(); | 179 const intptr_t kNumInputs = 2; |
| 129 return NULL; | 180 const intptr_t kNumTemps = 0; |
| 181 LocationSummary* locs = | |
| 182 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | |
| 183 locs->set_in(0, Location::RegisterOrConstant(left())); | |
| 184 locs->set_in(1, Location::RegisterOrConstant(right())); | |
| 185 // TODO(vegorov): support byte register constraints in the register allocator. | |
|
Florian Schneider
2013/11/05 16:57:53
Comment not relevant here.
zra
2013/11/05 18:32:13
Done.
| |
| 186 locs->set_out(Location::RegisterLocation(V0)); | |
| 187 return locs; | |
| 130 } | 188 } |
| 131 | 189 |
| 132 | 190 |
| 133 void IfThenElseInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 191 void IfThenElseInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 134 UNREACHABLE(); | 192 const Register result = locs()->out().reg(); |
| 193 ASSERT(result == V0); | |
| 194 ASSERT(Token::IsEqualityOperator(kind())); | |
| 195 | |
| 196 Location left = locs()->in(0); | |
| 197 Location right = locs()->in(1); | |
| 198 if (left.IsConstant() && right.IsConstant()) { | |
| 199 // TODO(srdjan): Determine why this instruction was not eliminated. | |
| 200 bool res = (left.constant().raw() == right.constant().raw()); | |
| 201 if ((kind_ == Token::kNE_STRICT) || (kind_ == Token::kNE)) { | |
| 202 res = !res; | |
| 203 } | |
| 204 __ LoadImmediate(result, | |
| 205 reinterpret_cast<int32_t>(Smi::New(res ? if_true_ : if_false_))); | |
| 206 return; | |
| 207 } | |
| 208 | |
| 209 ASSERT(!left.IsConstant() || !right.IsConstant()); | |
| 210 | |
| 211 // Clear upper part of the out register. We are going to use setcc on it | |
| 212 // which is a byte move. | |
|
Florian Schneider
2013/11/05 16:57:53
Update comment.
zra
2013/11/05 18:32:13
Done.
| |
| 213 __ mov(result, ZR); | |
| 214 | |
| 215 // Compare left and right. For now only equality comparison is supported. | |
| 216 // TODO(vegorov): reuse code from the other comparison instructions instead of | |
| 217 // generating it inline here. | |
| 218 if (left.IsConstant()) { | |
| 219 __ CompareObject(CMPRES1, CMPRES2, right.reg(), left.constant()); | |
| 220 } else if (right.IsConstant()) { | |
| 221 __ CompareObject(CMPRES1, CMPRES2, left.reg(), right.constant()); | |
| 222 } else { | |
| 223 __ slt(CMPRES1, left.reg(), right.reg()); | |
| 224 __ slt(CMPRES2, right.reg(), left.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 switch (true_condition) { | |
|
Florian Schneider
2013/11/05 16:57:53
true_condition can only be EQ or NE here. The othe
zra
2013/11/05 18:32:13
Done.
| |
| 252 case EQ: | |
| 253 __ xor_(result, CMPRES1, CMPRES2); | |
| 254 __ xori(result, result, Immediate(1)); | |
| 255 break; | |
| 256 case NE: __ xor_(result, CMPRES1, CMPRES2); break; | |
| 257 case GT: __ mov(result, CMPRES2); break; | |
| 258 case GE: __ xori(result, CMPRES1, Immediate(1)); break; | |
| 259 case LT: __ mov(result, CMPRES1); break; | |
| 260 case LE: __ xori(result, CMPRES2, Immediate(1)); break; | |
| 261 default: | |
| 262 UNREACHABLE(); | |
| 263 break; | |
| 264 } | |
| 265 | |
| 266 if (is_power_of_two_kind) { | |
| 267 const intptr_t shift = | |
| 268 Utils::ShiftForPowerOfTwo(Utils::Maximum(true_value, false_value)); | |
| 269 __ sll(result, result, shift + kSmiTagSize); | |
| 270 } else { | |
| 271 __ AddImmediate(result, result, -1); | |
| 272 const int32_t val = | |
| 273 Smi::RawValue(true_value) - Smi::RawValue(false_value); | |
| 274 if (Utils::IsUint(kImmBits, val)) { | |
|
Florian Schneider
2013/11/05 16:57:53
AndImmediate
zra
2013/11/05 18:32:13
Done.
| |
| 275 __ andi(result, result, Immediate(val)); | |
| 276 } else { | |
| 277 __ LoadImmediate(TMP, val); | |
| 278 __ and_(result, result, TMP); | |
| 279 } | |
| 280 if (false_value != 0) { | |
| 281 __ AddImmediate(result, result, Smi::RawValue(false_value)); | |
| 282 } | |
| 283 } | |
| 135 } | 284 } |
| 136 | 285 |
| 137 | 286 |
| 138 LocationSummary* ClosureCallInstr::MakeLocationSummary() const { | 287 LocationSummary* ClosureCallInstr::MakeLocationSummary() const { |
| 139 const intptr_t kNumInputs = 0; | 288 const intptr_t kNumInputs = 0; |
| 140 const intptr_t kNumTemps = 1; | 289 const intptr_t kNumTemps = 1; |
| 141 LocationSummary* result = | 290 LocationSummary* result = |
| 142 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); | 291 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); |
| 143 result->set_out(Location::RegisterLocation(V0)); | 292 result->set_out(Location::RegisterLocation(V0)); |
| 144 result->set_temp(0, Location::RegisterLocation(S4)); // Arg. descriptor. | 293 result->set_temp(0, Location::RegisterLocation(S4)); // Arg. descriptor. |
| (...skipping 3395 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3540 } | 3689 } |
| 3541 | 3690 |
| 3542 // We can fall through if the successor is the next block in the list. | 3691 // We can fall through if the successor is the next block in the list. |
| 3543 // Otherwise, we need a jump. | 3692 // Otherwise, we need a jump. |
| 3544 if (!compiler->CanFallThroughTo(successor())) { | 3693 if (!compiler->CanFallThroughTo(successor())) { |
| 3545 __ b(compiler->GetJumpLabel(successor())); | 3694 __ b(compiler->GetJumpLabel(successor())); |
| 3546 } | 3695 } |
| 3547 } | 3696 } |
| 3548 | 3697 |
| 3549 | 3698 |
| 3550 static Condition NegateCondition(Condition condition) { | |
| 3551 switch (condition) { | |
| 3552 case EQ: return NE; | |
| 3553 case NE: return EQ; | |
| 3554 case LT: return GE; | |
| 3555 case LE: return GT; | |
| 3556 case GT: return LE; | |
| 3557 case GE: return LT; | |
| 3558 default: | |
| 3559 OS::Print("Error: Condition not recognized: %d\n", condition); | |
| 3560 UNIMPLEMENTED(); | |
| 3561 return EQ; | |
| 3562 } | |
| 3563 } | |
| 3564 | |
| 3565 | |
| 3566 void ControlInstruction::EmitBranchOnValue(FlowGraphCompiler* compiler, | 3699 void ControlInstruction::EmitBranchOnValue(FlowGraphCompiler* compiler, |
| 3567 bool value) { | 3700 bool value) { |
| 3568 __ TraceSimMsg("ControlInstruction::EmitBranchOnValue"); | 3701 __ TraceSimMsg("ControlInstruction::EmitBranchOnValue"); |
| 3569 if (value && !compiler->CanFallThroughTo(true_successor())) { | 3702 if (value && !compiler->CanFallThroughTo(true_successor())) { |
| 3570 __ b(compiler->GetJumpLabel(true_successor())); | 3703 __ b(compiler->GetJumpLabel(true_successor())); |
| 3571 } else if (!value && !compiler->CanFallThroughTo(false_successor())) { | 3704 } else if (!value && !compiler->CanFallThroughTo(false_successor())) { |
| 3572 __ b(compiler->GetJumpLabel(false_successor())); | 3705 __ b(compiler->GetJumpLabel(false_successor())); |
| 3573 } | 3706 } |
| 3574 } | 3707 } |
| 3575 | 3708 |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3780 compiler->GenerateCall(token_pos(), | 3913 compiler->GenerateCall(token_pos(), |
| 3781 &label, | 3914 &label, |
| 3782 PcDescriptors::kOther, | 3915 PcDescriptors::kOther, |
| 3783 locs()); | 3916 locs()); |
| 3784 __ Drop(2); // Discard type arguments and receiver. | 3917 __ Drop(2); // Discard type arguments and receiver. |
| 3785 } | 3918 } |
| 3786 | 3919 |
| 3787 } // namespace dart | 3920 } // namespace dart |
| 3788 | 3921 |
| 3789 #endif // defined TARGET_ARCH_MIPS | 3922 #endif // defined TARGET_ARCH_MIPS |
| OLD | NEW |