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 |