| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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_IA32. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. |
| 6 #if defined(TARGET_ARCH_IA32) | 6 #if defined(TARGET_ARCH_IA32) |
| 7 | 7 |
| 8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
| 9 | 9 |
| 10 #include "lib/error.h" | 10 #include "lib/error.h" |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 // on the stack and return the result in a fixed register EAX. | 24 // on the stack and return the result in a fixed register EAX. |
| 25 LocationSummary* Computation::MakeCallSummary() { | 25 LocationSummary* Computation::MakeCallSummary() { |
| 26 LocationSummary* result = new LocationSummary(0, 0); | 26 LocationSummary* result = new LocationSummary(0, 0); |
| 27 result->set_out(Location::RegisterLocation(EAX)); | 27 result->set_out(Location::RegisterLocation(EAX)); |
| 28 return result; | 28 return result; |
| 29 } | 29 } |
| 30 | 30 |
| 31 | 31 |
| 32 void BindInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 32 void BindInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 33 computation()->EmitNativeCode(compiler); | 33 computation()->EmitNativeCode(compiler); |
| 34 __ pushl(locs()->out().reg()); | 34 if (locs()->out().kind() == Location::kRegister) { |
| 35 // TODO(vegorov): this should really happen only for comparisons fused |
| 36 // with branches. Currrently IR does not provide an easy way to remove |
| 37 // instructions from the graph so we just leave fused comparison in it |
| 38 // but change its result location to be NoLocation. |
| 39 __ pushl(locs()->out().reg()); |
| 40 } |
| 35 } | 41 } |
| 36 | 42 |
| 37 | 43 |
| 38 LocationSummary* ReturnInstr::MakeLocationSummary() const { | 44 LocationSummary* ReturnInstr::MakeLocationSummary() const { |
| 39 const intptr_t kNumInputs = 1; | 45 const intptr_t kNumInputs = 1; |
| 40 const intptr_t kNumTemps = 1; | 46 const intptr_t kNumTemps = 1; |
| 41 LocationSummary* locs = new LocationSummary(kNumInputs, kNumTemps); | 47 LocationSummary* locs = new LocationSummary(kNumInputs, kNumTemps); |
| 42 locs->set_in(0, Location::RegisterLocation(EAX)); | 48 locs->set_in(0, Location::RegisterLocation(EAX)); |
| 43 locs->set_temp(0, Location::RequiresRegister()); | 49 locs->set_temp(0, Location::RequiresRegister()); |
| 44 return locs; | 50 return locs; |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 156 } | 162 } |
| 157 | 163 |
| 158 | 164 |
| 159 void AssertBooleanComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 165 void AssertBooleanComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 160 Register obj = locs()->in(0).reg(); | 166 Register obj = locs()->in(0).reg(); |
| 161 Register result = locs()->out().reg(); | 167 Register result = locs()->out().reg(); |
| 162 | 168 |
| 163 // Check that the type of the value is allowed in conditional context. | 169 // Check that the type of the value is allowed in conditional context. |
| 164 // Call the runtime if the object is not bool::true or bool::false. | 170 // Call the runtime if the object is not bool::true or bool::false. |
| 165 Label done; | 171 Label done; |
| 166 __ CompareObject(obj, Bool::ZoneHandle(Bool::True())); | 172 __ CompareObject(obj, compiler->true_value()); |
| 167 __ j(EQUAL, &done, Assembler::kNearJump); | 173 __ j(EQUAL, &done, Assembler::kNearJump); |
| 168 __ CompareObject(obj, Bool::ZoneHandle(Bool::False())); | 174 __ CompareObject(obj, compiler->false_value()); |
| 169 __ j(EQUAL, &done, Assembler::kNearJump); | 175 __ j(EQUAL, &done, Assembler::kNearJump); |
| 170 | 176 |
| 171 __ pushl(Immediate(Smi::RawValue(token_index()))); // Source location. | 177 __ pushl(Immediate(Smi::RawValue(token_index()))); // Source location. |
| 172 __ pushl(obj); // Push the source object. | 178 __ pushl(obj); // Push the source object. |
| 173 compiler->GenerateCallRuntime(cid(), | 179 compiler->GenerateCallRuntime(cid(), |
| 174 token_index(), | 180 token_index(), |
| 175 try_index(), | 181 try_index(), |
| 176 kConditionTypeErrorRuntimeEntry); | 182 kConditionTypeErrorRuntimeEntry); |
| 177 // We should never return here. | 183 // We should never return here. |
| 178 __ int3(); | 184 __ int3(); |
| 179 | 185 |
| 180 __ Bind(&done); | 186 __ Bind(&done); |
| 181 ASSERT(obj == result); | 187 ASSERT(obj == result); |
| 182 } | 188 } |
| 183 | 189 |
| 184 | 190 |
| 185 LocationSummary* EqualityCompareComp::MakeLocationSummary() const { | 191 LocationSummary* EqualityCompareComp::MakeLocationSummary() const { |
| 186 LocationSummary* locs = new LocationSummary(2, 0); | 192 LocationSummary* locs = new LocationSummary(2, 0); |
| 187 locs->set_in(0, Location::RequiresRegister()); | 193 locs->set_in(0, Location::RequiresRegister()); |
| 188 locs->set_in(1, Location::RequiresRegister()); | 194 locs->set_in(1, Location::RequiresRegister()); |
| 189 locs->set_out(Location::RegisterLocation(EAX)); | 195 if (fused_with_branch() == NULL) { |
| 196 locs->set_out(Location::RegisterLocation(EAX)); |
| 197 } |
| 190 return locs; | 198 return locs; |
| 191 } | 199 } |
| 192 | 200 |
| 193 | 201 |
| 194 void EqualityCompareComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 202 void EqualityCompareComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 195 Register left = locs()->in(0).reg(); | 203 Register left = locs()->in(0).reg(); |
| 196 Register right = locs()->in(1).reg(); | 204 Register right = locs()->in(1).reg(); |
| 197 Register result = locs()->out().reg(); | |
| 198 ASSERT(locs()->out().reg() == EAX); | |
| 199 | 205 |
| 200 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | |
| 201 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); | |
| 202 const Immediate raw_null = | 206 const Immediate raw_null = |
| 203 Immediate(reinterpret_cast<intptr_t>(Object::null())); | 207 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 204 Label done, load_true, non_null_compare; | 208 Label done, non_null_compare; |
| 205 __ cmpl(left, raw_null); | 209 __ cmpl(left, raw_null); |
| 206 __ j(NOT_EQUAL, &non_null_compare, Assembler::kNearJump); | 210 __ j(NOT_EQUAL, &non_null_compare, Assembler::kNearJump); |
| 207 // Comparison with NULL is "===". | 211 // Comparison with NULL is "===". |
| 208 __ cmpl(left, right); | 212 __ cmpl(left, right); |
| 209 __ j(EQUAL, &load_true, Assembler::kNearJump); | 213 if (fused_with_branch() == NULL) { |
| 210 __ LoadObject(result, bool_false); | 214 Register result = locs()->out().reg(); |
| 211 __ jmp(&done, Assembler::kNearJump); | 215 Label load_true; |
| 212 __ Bind(&load_true); | 216 __ j(EQUAL, &load_true, Assembler::kNearJump); |
| 213 __ LoadObject(result, bool_true); | 217 __ LoadObject(result, compiler->false_value()); |
| 218 __ jmp(&done, Assembler::kNearJump); |
| 219 __ Bind(&load_true); |
| 220 __ LoadObject(result, compiler->true_value()); |
| 221 } else { |
| 222 fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL); |
| 223 } |
| 214 __ jmp(&done); | 224 __ jmp(&done); |
| 215 | 225 |
| 216 __ Bind(&non_null_compare); | 226 __ Bind(&non_null_compare); |
| 217 __ pushl(left); | 227 __ pushl(left); |
| 218 __ pushl(right); | 228 __ pushl(right); |
| 219 const String& operator_name = String::ZoneHandle(String::NewSymbol("==")); | 229 const String& operator_name = String::ZoneHandle(String::NewSymbol("==")); |
| 220 const int kNumberOfArguments = 2; | 230 const int kNumberOfArguments = 2; |
| 221 const Array& kNoArgumentNames = Array::Handle(); | 231 const Array& kNoArgumentNames = Array::Handle(); |
| 222 const int kNumArgumentsChecked = 1; | 232 const int kNumArgumentsChecked = 1; |
| 223 | 233 |
| 224 compiler->GenerateInstanceCall(cid(), | 234 compiler->GenerateInstanceCall(cid(), |
| 225 token_index(), | 235 token_index(), |
| 226 try_index(), | 236 try_index(), |
| 227 operator_name, | 237 operator_name, |
| 228 kNumberOfArguments, | 238 kNumberOfArguments, |
| 229 kNoArgumentNames, | 239 kNoArgumentNames, |
| 230 kNumArgumentsChecked); | 240 kNumArgumentsChecked); |
| 241 ASSERT(fused_with_branch() != NULL || locs()->out().reg() == EAX); |
| 242 |
| 243 if (fused_with_branch() != NULL) { |
| 244 __ CompareObject(EAX, compiler->true_value()); |
| 245 fused_with_branch()->EmitBranchOnCondition(compiler, EQUAL); |
| 246 } |
| 247 |
| 231 __ Bind(&done); | 248 __ Bind(&done); |
| 232 } | 249 } |
| 233 | 250 |
| 234 | 251 |
| 235 LocationSummary* RelationalOpComp::MakeLocationSummary() const { | 252 LocationSummary* RelationalOpComp::MakeLocationSummary() const { |
| 236 if ((operands_class_id() == kSmi) || (operands_class_id() == kDouble)) { | 253 if ((operands_class_id() == kSmi) || (operands_class_id() == kDouble)) { |
| 237 const intptr_t kNumInputs = 2; | 254 const intptr_t kNumInputs = 2; |
| 238 const intptr_t kNumTemps = 1; | 255 const intptr_t kNumTemps = 1; |
| 239 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps); | 256 LocationSummary* summary = new LocationSummary(kNumInputs, kNumTemps); |
| 240 summary->set_in(0, Location::RequiresRegister()); | 257 summary->set_in(0, Location::RequiresRegister()); |
| 241 summary->set_in(1, Location::RequiresRegister()); | 258 summary->set_in(1, Location::RequiresRegister()); |
| 242 summary->set_out(Location::RequiresRegister()); | 259 if (fused_with_branch() == NULL) { |
| 260 summary->set_out(Location::RequiresRegister()); |
| 261 } |
| 243 summary->set_temp(0, Location::RequiresRegister()); | 262 summary->set_temp(0, Location::RequiresRegister()); |
| 244 return summary; | 263 return summary; |
| 245 } | 264 } |
| 246 ASSERT(operands_class_id() == kObject); | 265 ASSERT(operands_class_id() == kObject); |
| 247 return MakeCallSummary(); | 266 return MakeCallSummary(); |
| 248 } | 267 } |
| 249 | 268 |
| 250 | 269 |
| 251 static Condition TokenKindToSmiCondition(Token::Kind kind) { | 270 static Condition TokenKindToSmiCondition(Token::Kind kind) { |
| 252 switch (kind) { | 271 switch (kind) { |
| 253 case Token::kEQ: return EQUAL; | 272 case Token::kEQ: return EQUAL; |
| 254 case Token::kNE: return NOT_EQUAL; | 273 case Token::kNE: return NOT_EQUAL; |
| 255 case Token::kLT: return LESS; | 274 case Token::kLT: return LESS; |
| 256 case Token::kGT: return GREATER; | 275 case Token::kGT: return GREATER; |
| 257 case Token::kLTE: return LESS_EQUAL; | 276 case Token::kLTE: return LESS_EQUAL; |
| 258 case Token::kGTE: return GREATER_EQUAL; | 277 case Token::kGTE: return GREATER_EQUAL; |
| 259 default: | 278 default: |
| 260 UNREACHABLE(); | 279 UNREACHABLE(); |
| 261 return OVERFLOW; | 280 return OVERFLOW; |
| 262 } | 281 } |
| 263 } | 282 } |
| 264 | 283 |
| 265 | 284 |
| 266 static void EmitSmiRelationalOp(FlowGraphCompiler* compiler, | 285 static void EmitSmiRelationalOp(FlowGraphCompiler* compiler, |
| 267 RelationalOpComp* comp) { | 286 RelationalOpComp* comp) { |
| 268 Register left = comp->locs()->in(0).reg(); | 287 Register left = comp->locs()->in(0).reg(); |
| 269 Register right = comp->locs()->in(1).reg(); | 288 Register right = comp->locs()->in(1).reg(); |
| 270 Register result = comp->locs()->out().reg(); | |
| 271 Register temp = comp->locs()->temp(0).reg(); | 289 Register temp = comp->locs()->temp(0).reg(); |
| 272 Label* deopt = compiler->AddDeoptStub(comp->cid(), | 290 Label* deopt = compiler->AddDeoptStub(comp->cid(), |
| 273 comp->token_index(), | 291 comp->token_index(), |
| 274 comp->try_index(), | 292 comp->try_index(), |
| 275 kDeoptSmiCompareSmis, | 293 kDeoptSmiCompareSmis, |
| 276 left, | 294 left, |
| 277 right); | 295 right); |
| 278 __ movl(temp, left); | 296 __ movl(temp, left); |
| 279 __ orl(temp, right); | 297 __ orl(temp, right); |
| 280 __ testl(temp, Immediate(kSmiTagMask)); | 298 __ testl(temp, Immediate(kSmiTagMask)); |
| 281 __ j(NOT_ZERO, deopt); | 299 __ j(NOT_ZERO, deopt); |
| 282 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | |
| 283 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); | |
| 284 Condition condition = TokenKindToSmiCondition(comp->kind()); | |
| 285 | 300 |
| 286 Label done, is_true; | 301 Condition true_condition = TokenKindToSmiCondition(comp->kind()); |
| 287 __ cmpl(left, right); | 302 __ cmpl(left, right); |
| 288 __ j(condition, &is_true); | 303 |
| 289 __ LoadObject(result, bool_false); | 304 if (comp->fused_with_branch() == NULL) { |
| 290 __ jmp(&done); | 305 Register result = comp->locs()->out().reg(); |
| 291 __ Bind(&is_true); | 306 Label done, is_true; |
| 292 __ LoadObject(result, bool_true); | 307 |
| 293 __ Bind(&done); | 308 __ j(true_condition, &is_true); |
| 309 __ LoadObject(result, compiler->false_value()); |
| 310 __ jmp(&done); |
| 311 __ Bind(&is_true); |
| 312 __ LoadObject(result, compiler->true_value()); |
| 313 __ Bind(&done); |
| 314 } else { |
| 315 comp->fused_with_branch()->EmitBranchOnCondition(compiler, true_condition); |
| 316 } |
| 294 } | 317 } |
| 295 | 318 |
| 296 | 319 |
| 297 static Condition TokenKindToDoubleCondition(Token::Kind kind) { | 320 static Condition TokenKindToDoubleCondition(Token::Kind kind) { |
| 298 switch (kind) { | 321 switch (kind) { |
| 299 case Token::kEQ: return EQUAL; | 322 case Token::kEQ: return EQUAL; |
| 300 case Token::kLT: return BELOW; | 323 case Token::kLT: return BELOW; |
| 301 case Token::kGT: return ABOVE; | 324 case Token::kGT: return ABOVE; |
| 302 case Token::kLTE: return BELOW_EQUAL; | 325 case Token::kLTE: return BELOW_EQUAL; |
| 303 case Token::kGTE: return ABOVE_EQUAL; | 326 case Token::kGTE: return ABOVE_EQUAL; |
| 304 default: | 327 default: |
| 305 UNREACHABLE(); | 328 UNREACHABLE(); |
| 306 return OVERFLOW; | 329 return OVERFLOW; |
| 307 } | 330 } |
| 308 } | 331 } |
| 309 | 332 |
| 310 | 333 |
| 311 static void EmitDoubleRelationalOp(FlowGraphCompiler* compiler, | 334 static void EmitDoubleRelationalOp(FlowGraphCompiler* compiler, |
| 312 RelationalOpComp* comp) { | 335 RelationalOpComp* comp) { |
| 313 Register left = comp->locs()->in(0).reg(); | 336 Register left = comp->locs()->in(0).reg(); |
| 314 Register right = comp->locs()->in(1).reg(); | 337 Register right = comp->locs()->in(1).reg(); |
| 315 Register result = comp->locs()->out().reg(); | |
| 316 // TODO(srdjan): temp is only needed if a conversion Smi->Double occurs. | 338 // TODO(srdjan): temp is only needed if a conversion Smi->Double occurs. |
| 317 Register temp = comp->locs()->temp(0).reg(); | 339 Register temp = comp->locs()->temp(0).reg(); |
| 318 Label* deopt = compiler->AddDeoptStub(comp->cid(), | 340 Label* deopt = compiler->AddDeoptStub(comp->cid(), |
| 319 comp->token_index(), | 341 comp->token_index(), |
| 320 comp->try_index(), | 342 comp->try_index(), |
| 321 kDeoptDoubleComparison, | 343 kDeoptDoubleComparison, |
| 322 left, | 344 left, |
| 323 right); | 345 right); |
| 324 compiler->LoadDoubleOrSmiToXmm(XMM0, left, temp, deopt); | 346 compiler->LoadDoubleOrSmiToXmm(XMM0, left, temp, deopt); |
| 325 compiler->LoadDoubleOrSmiToXmm(XMM1, right, temp, deopt); | 347 compiler->LoadDoubleOrSmiToXmm(XMM1, right, temp, deopt); |
| 326 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 348 |
| 327 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); | |
| 328 Condition true_condition = TokenKindToDoubleCondition(comp->kind()); | 349 Condition true_condition = TokenKindToDoubleCondition(comp->kind()); |
| 329 Label is_false, is_true, done; | |
| 330 __ comisd(XMM0, XMM1); | 350 __ comisd(XMM0, XMM1); |
| 331 __ j(PARITY_EVEN, &is_false, Assembler::kNearJump); // NaN -> false; | 351 |
| 332 __ j(true_condition, &is_true, Assembler::kNearJump); | 352 if (comp->fused_with_branch() == NULL) { |
| 333 __ Bind(&is_false); | 353 Register result = comp->locs()->out().reg(); |
| 334 __ LoadObject(result, bool_false); | 354 Label is_false, is_true, done; |
| 335 __ jmp(&done); | 355 __ j(PARITY_EVEN, &is_false, Assembler::kNearJump); // NaN -> false; |
| 336 __ Bind(&is_true); | 356 __ j(true_condition, &is_true, Assembler::kNearJump); |
| 337 __ LoadObject(result, bool_true); | 357 __ Bind(&is_false); |
| 338 __ Bind(&done); | 358 __ LoadObject(result, compiler->false_value()); |
| 359 __ jmp(&done); |
| 360 __ Bind(&is_true); |
| 361 __ LoadObject(result, compiler->true_value()); |
| 362 __ Bind(&done); |
| 363 } else { |
| 364 BranchInstr* branch = comp->fused_with_branch(); |
| 365 __ j(PARITY_EVEN, compiler->GetBlockLabel(branch->false_successor())); |
| 366 branch->EmitBranchOnCondition(compiler, true_condition); |
| 367 } |
| 339 } | 368 } |
| 340 | 369 |
| 341 | 370 |
| 342 | 371 |
| 343 void RelationalOpComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 372 void RelationalOpComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 344 if (operands_class_id() == kSmi) { | 373 if (operands_class_id() == kSmi) { |
| 345 EmitSmiRelationalOp(compiler, this); | 374 EmitSmiRelationalOp(compiler, this); |
| 346 return; | 375 return; |
| 347 } | 376 } |
| 348 if (operands_class_id() == kDouble) { | 377 if (operands_class_id() == kDouble) { |
| (...skipping 1070 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1419 __ DoubleNegate(XMM0); | 1448 __ DoubleNegate(XMM0); |
| 1420 __ movsd(FieldAddress(result, Double::value_offset()), XMM0); | 1449 __ movsd(FieldAddress(result, Double::value_offset()), XMM0); |
| 1421 } else { | 1450 } else { |
| 1422 UNREACHABLE(); | 1451 UNREACHABLE(); |
| 1423 } | 1452 } |
| 1424 } | 1453 } |
| 1425 | 1454 |
| 1426 | 1455 |
| 1427 LocationSummary* ToDoubleComp::MakeLocationSummary() const { | 1456 LocationSummary* ToDoubleComp::MakeLocationSummary() const { |
| 1428 const intptr_t kNumInputs = 1; | 1457 const intptr_t kNumInputs = 1; |
| 1429 const intptr_t kNumTemps = 1; | |
| 1430 if (from() == kDouble) { | 1458 if (from() == kDouble) { |
| 1459 const intptr_t kNumTemps = 1; |
| 1431 LocationSummary* locs = new LocationSummary(kNumInputs, kNumTemps); | 1460 LocationSummary* locs = new LocationSummary(kNumInputs, kNumTemps); |
| 1432 locs->set_in(0, Location::RequiresRegister()); | 1461 locs->set_in(0, Location::RequiresRegister()); |
| 1462 locs->set_temp(0, Location::RequiresRegister()); |
| 1433 locs->set_out(Location::SameAsFirstInput()); | 1463 locs->set_out(Location::SameAsFirstInput()); |
| 1434 return locs; | 1464 return locs; |
| 1435 } else { | 1465 } else { |
| 1436 ASSERT(from() == kSmi); | 1466 ASSERT(from() == kSmi); |
| 1437 return LocationSummary::Make(kNumInputs, Location::RegisterLocation(EAX)); | 1467 return LocationSummary::Make(kNumInputs, Location::RegisterLocation(EAX)); |
| 1438 } | 1468 } |
| 1439 } | 1469 } |
| 1440 | 1470 |
| 1441 | 1471 |
| 1442 void ToDoubleComp::EmitNativeCode(FlowGraphCompiler* compiler) { | 1472 void ToDoubleComp::EmitNativeCode(FlowGraphCompiler* compiler) { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1488 __ cvtsi2sd(XMM0, value); | 1518 __ cvtsi2sd(XMM0, value); |
| 1489 __ movsd(FieldAddress(result, Double::value_offset()), XMM0); | 1519 __ movsd(FieldAddress(result, Double::value_offset()), XMM0); |
| 1490 } | 1520 } |
| 1491 | 1521 |
| 1492 | 1522 |
| 1493 } // namespace dart | 1523 } // namespace dart |
| 1494 | 1524 |
| 1495 #undef __ | 1525 #undef __ |
| 1496 | 1526 |
| 1497 #endif // defined TARGET_ARCH_X64 | 1527 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |