Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 //===- subzero/src/IceTargetLoweringARM32.cpp - ARM32 lowering ------------===// | 1 //===- subzero/src/IceTargetLoweringARM32.cpp - ARM32 lowering ------------===// |
| 2 // | 2 // |
| 3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
| 4 // | 4 // |
| 5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
| 6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
| 7 // | 7 // |
| 8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
| 9 /// | 9 /// |
| 10 /// \file | 10 /// \file |
| (...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 258 } | 258 } |
| 259 } | 259 } |
| 260 | 260 |
| 261 OutArgsSizeBytes = applyStackAlignmentTy(OutArgsSizeBytes, Ty); | 261 OutArgsSizeBytes = applyStackAlignmentTy(OutArgsSizeBytes, Ty); |
| 262 OutArgsSizeBytes += typeWidthInBytesOnStack(Ty); | 262 OutArgsSizeBytes += typeWidthInBytesOnStack(Ty); |
| 263 } | 263 } |
| 264 | 264 |
| 265 return applyStackAlignment(OutArgsSizeBytes); | 265 return applyStackAlignment(OutArgsSizeBytes); |
| 266 } | 266 } |
| 267 | 267 |
| 268 void TargetARM32::genTargetHelperCallFor(Inst *Instr) { | |
| 269 constexpr bool NoTailCall = false; | |
| 270 constexpr bool IsTargetHelperCall = true; | |
| 271 | |
| 272 switch (Instr->getKind()) { | |
| 273 default: | |
| 274 return; | |
| 275 case Inst::Arithmetic: { | |
| 276 Variable *Dest = Instr->getDest(); | |
| 277 const Type DestTy = Dest->getType(); | |
| 278 const InstArithmetic::OpKind Op = | |
| 279 llvm::cast<InstArithmetic>(Instr)->getOp(); | |
| 280 switch (DestTy) { | |
| 281 default: | |
| 282 return; | |
| 283 case IceType_i64: { | |
| 284 // Technically, ARM has its own aeabi routines, but we can use the | |
| 285 // non-aeabi routine as well. LLVM uses __aeabi_ldivmod for div, but uses | |
| 286 // the more standard __moddi3 for rem. | |
| 287 Operand *TargetHelper = nullptr; | |
| 288 switch (Op) { | |
| 289 default: | |
| 290 return; | |
| 291 case InstArithmetic::Udiv: | |
| 292 TargetHelper = Ctx->getConstantExternSym(H_udiv_i64); | |
| 293 break; | |
| 294 case InstArithmetic::Sdiv: | |
| 295 TargetHelper = Ctx->getConstantExternSym(H_sdiv_i64); | |
| 296 break; | |
| 297 case InstArithmetic::Urem: | |
| 298 TargetHelper = Ctx->getConstantExternSym(H_urem_i64); | |
| 299 break; | |
| 300 case InstArithmetic::Srem: | |
| 301 TargetHelper = Ctx->getConstantExternSym(H_srem_i64); | |
| 302 break; | |
| 303 } | |
| 304 assert(TargetHelper != nullptr); | |
| 305 ARM32HelpersPreamble[TargetHelper] = &TargetARM32::preambleDivRem; | |
| 306 constexpr SizeT MaxArgs = 2; | |
| 307 auto *Call = InstCall::create(Func, MaxArgs, Dest, TargetHelper, | |
| 308 NoTailCall, IsTargetHelperCall); | |
| 309 Call->addArg(Instr->getSrc(0)); | |
| 310 Call->addArg(Instr->getSrc(1)); | |
| 311 Context.insert(Call); | |
| 312 Instr->setDeleted(); | |
| 313 return; | |
| 314 } | |
| 315 case IceType_i32: | |
| 316 case IceType_i16: | |
| 317 case IceType_i8: { | |
| 318 const bool HasHWDiv = hasCPUFeature(TargetARM32Features::HWDivArm); | |
| 319 InstCast::OpKind CastKind; | |
| 320 Operand *TargetHelper; | |
| 321 switch (Op) { | |
| 322 default: | |
| 323 return; | |
| 324 case InstArithmetic::Udiv: | |
| 325 TargetHelper = | |
| 326 HasHWDiv ? nullptr : Ctx->getConstantExternSym(H_udiv_i32); | |
| 327 CastKind = InstCast::Zext; | |
| 328 break; | |
| 329 case InstArithmetic::Sdiv: | |
| 330 TargetHelper = | |
| 331 HasHWDiv ? nullptr : Ctx->getConstantExternSym(H_sdiv_i32); | |
| 332 CastKind = InstCast::Sext; | |
| 333 break; | |
| 334 case InstArithmetic::Urem: | |
| 335 TargetHelper = | |
| 336 HasHWDiv ? nullptr : Ctx->getConstantExternSym(H_urem_i32); | |
| 337 CastKind = InstCast::Zext; | |
| 338 break; | |
| 339 case InstArithmetic::Srem: | |
| 340 TargetHelper = | |
| 341 HasHWDiv ? nullptr : Ctx->getConstantExternSym(H_srem_i32); | |
| 342 CastKind = InstCast::Sext; | |
| 343 break; | |
| 344 } | |
| 345 if (TargetHelper == nullptr) { | |
| 346 // TargetHelper should only ever be nullptr when the processor does not | |
| 347 // have a hardware divider. If any other helpers are ever introduced, | |
| 348 // the following assert will have to be modified. | |
| 349 assert(HasHWDiv); | |
| 350 return; | |
| 351 } | |
| 352 Operand *Src0 = Instr->getSrc(0); | |
| 353 Operand *Src1 = Instr->getSrc(1); | |
| 354 if (DestTy != IceType_i32) { | |
| 355 // Src0 and Src1 have to be zero-, or signed-extended to i32. For Src0, | |
| 356 // we just insert a InstCast right before the call to the helper. | |
| 357 Variable *Src0_32 = Func->makeVariable(IceType_i32); | |
| 358 Context.insert(InstCast::create(Func, CastKind, Src0_32, Src0)); | |
| 359 Src0 = Src0_32; | |
| 360 | |
| 361 // For extending Src1, we will just insert an InstCast if Src1 is not a | |
| 362 // Constant. If it is, then we extend it here, and not during program | |
| 363 // runtime. This allows preambleDivRem to optimize-out the div-by-0 | |
| 364 // check. | |
| 365 if (auto *C = llvm::dyn_cast<ConstantInteger32>(Src1)) { | |
| 366 const int32_t ShAmt = (DestTy == IceType_i16) ? 16 : 24; | |
| 367 int32_t NewC = C->getValue(); | |
| 368 if (CastKind == InstCast::Zext) { | |
| 369 NewC &= ~(0x80000000l >> ShAmt); | |
| 370 } else { | |
| 371 NewC = (NewC << ShAmt) >> ShAmt; | |
| 372 } | |
| 373 Src1 = Ctx->getConstantInt32(NewC); | |
| 374 } else { | |
| 375 Variable *Src1_32 = Func->makeVariable(IceType_i32); | |
| 376 Context.insert(InstCast::create(Func, CastKind, Src1_32, Src1)); | |
| 377 Src1 = Src1_32; | |
| 378 } | |
| 379 } | |
| 380 assert(TargetHelper != nullptr); | |
| 381 ARM32HelpersPreamble[TargetHelper] = &TargetARM32::preambleDivRem; | |
| 382 constexpr SizeT MaxArgs = 2; | |
| 383 auto *Call = InstCall::create(Func, MaxArgs, Dest, TargetHelper, | |
| 384 NoTailCall, IsTargetHelperCall); | |
| 385 assert(Src0->getType() == IceType_i32); | |
| 386 Call->addArg(Src0); | |
| 387 assert(Src1->getType() == IceType_i32); | |
| 388 Call->addArg(Src1); | |
| 389 Context.insert(Call); | |
| 390 Instr->setDeleted(); | |
| 391 return; | |
| 392 } | |
| 393 case IceType_f64: | |
| 394 case IceType_f32: { | |
| 395 if (Op != InstArithmetic::Frem) { | |
| 396 return; | |
| 397 } | |
| 398 constexpr SizeT MaxArgs = 2; | |
| 399 Operand *TargetHelper = Ctx->getConstantExternSym( | |
| 400 DestTy == IceType_f32 ? H_frem_f32 : H_frem_f64); | |
| 401 auto *Call = InstCall::create(Func, MaxArgs, Dest, TargetHelper, | |
| 402 NoTailCall, IsTargetHelperCall); | |
| 403 Call->addArg(Instr->getSrc(0)); | |
| 404 Call->addArg(Instr->getSrc(1)); | |
| 405 Context.insert(Call); | |
| 406 Instr->setDeleted(); | |
| 407 return; | |
| 408 } | |
| 409 } | |
| 410 llvm::report_fatal_error("Control flow should never have reached here."); | |
| 411 } | |
| 412 case Inst::Cast: { | |
| 413 Variable *Dest = Instr->getDest(); | |
| 414 Operand *Src0 = Instr->getSrc(0); | |
| 415 const Type DestTy = Dest->getType(); | |
| 416 const InstCast::OpKind CastKind = | |
| 417 llvm::cast<InstCast>(Instr)->getCastKind(); | |
| 418 switch (CastKind) { | |
| 419 default: | |
| 420 return; | |
| 421 case InstCast::Fptosi: | |
| 422 case InstCast::Fptoui: { | |
| 423 if (DestTy != IceType_i64) { | |
| 424 return; | |
| 425 } | |
| 426 const bool DestIsSigned = CastKind == InstCast::Fptosi; | |
| 427 const bool Src0IsF32 = isFloat32Asserting32Or64(Src0->getType()); | |
| 428 Operand *TargetHelper = Ctx->getConstantExternSym( | |
| 429 Src0IsF32 ? (DestIsSigned ? H_fptosi_f32_i64 : H_fptoui_f32_i64) | |
| 430 : (DestIsSigned ? H_fptosi_f64_i64 : H_fptoui_f64_i64)); | |
| 431 static constexpr SizeT MaxArgs = 1; | |
| 432 auto *Call = InstCall::create(Func, MaxArgs, Dest, TargetHelper, | |
| 433 NoTailCall, IsTargetHelperCall); | |
| 434 Call->addArg(Src0); | |
| 435 Context.insert(Call); | |
| 436 Instr->setDeleted(); | |
| 437 return; | |
| 438 } | |
| 439 case InstCast::Sitofp: | |
| 440 case InstCast::Uitofp: { | |
| 441 if (Src0->getType() != IceType_i64) { | |
| 442 return; | |
| 443 } | |
| 444 const bool SourceIsSigned = CastKind == InstCast::Sitofp; | |
| 445 const bool DestIsF32 = isFloat32Asserting32Or64(Dest->getType()); | |
| 446 Operand *TargetHelper = Ctx->getConstantExternSym( | |
| 447 DestIsF32 ? (SourceIsSigned ? H_sitofp_i64_f32 : H_uitofp_i64_f32) | |
| 448 : (SourceIsSigned ? H_sitofp_i64_f64 : H_uitofp_i64_f64)); | |
| 449 static constexpr SizeT MaxArgs = 1; | |
| 450 auto *Call = InstCall::create(Func, MaxArgs, Dest, TargetHelper, | |
| 451 NoTailCall, IsTargetHelperCall); | |
| 452 Call->addArg(Src0); | |
| 453 Context.insert(Call); | |
| 454 Instr->setDeleted(); | |
| 455 return; | |
| 456 } | |
| 457 } | |
| 458 llvm_unreachable("Control flow should never have reached here."); | |
| 459 } | |
| 460 case Inst::IntrinsicCall: { | |
| 461 Variable *Dest = Instr->getDest(); | |
| 462 auto *IntrinsicCall = llvm::cast<InstIntrinsicCall>(Instr); | |
| 463 Intrinsics::IntrinsicID ID = IntrinsicCall->getIntrinsicInfo().ID; | |
| 464 switch (ID) { | |
| 465 default: | |
| 466 return; | |
| 467 case Intrinsics::Ctpop: { | |
| 468 Operand *Src0 = IntrinsicCall->getArg(0); | |
| 469 Operand *TargetHelper = Ctx->getConstantExternSym( | |
| 470 isInt32Asserting32Or64(Src0->getType()) ? H_call_ctpop_i32 | |
| 471 : H_call_ctpop_i64); | |
| 472 static constexpr SizeT MaxArgs = 1; | |
| 473 auto *Call = InstCall::create(Func, MaxArgs, Dest, TargetHelper, | |
| 474 NoTailCall, IsTargetHelperCall); | |
| 475 Call->addArg(Src0); | |
| 476 Context.insert(Call); | |
| 477 Instr->setDeleted(); | |
| 478 if (Src0->getType() == IceType_i64) { | |
| 479 ARM32HelpersPostamble[TargetHelper] = &TargetARM32::postambleCtpop64; | |
| 480 } | |
| 481 return; | |
| 482 } | |
| 483 case Intrinsics::Longjmp: { | |
| 484 static constexpr SizeT MaxArgs = 2; | |
| 485 static constexpr Variable *NoDest = nullptr; | |
| 486 Operand *TargetHelper = Ctx->getConstantExternSym(H_call_longjmp); | |
| 487 auto *Call = InstCall::create(Func, MaxArgs, NoDest, TargetHelper, | |
| 488 NoTailCall, IsTargetHelperCall); | |
| 489 Call->addArg(IntrinsicCall->getArg(0)); | |
| 490 Call->addArg(IntrinsicCall->getArg(1)); | |
| 491 Context.insert(Call); | |
| 492 Instr->setDeleted(); | |
| 493 return; | |
| 494 } | |
| 495 case Intrinsics::Memcpy: { | |
| 496 // In the future, we could potentially emit an inline memcpy/memset, etc. | |
| 497 // for intrinsic calls w/ a known length. | |
| 498 static constexpr SizeT MaxArgs = 3; | |
| 499 static constexpr Variable *NoDest = nullptr; | |
| 500 Operand *TargetHelper = Ctx->getConstantExternSym(H_call_memcpy); | |
| 501 auto *Call = InstCall::create(Func, MaxArgs, NoDest, TargetHelper, | |
| 502 NoTailCall, IsTargetHelperCall); | |
| 503 Call->addArg(IntrinsicCall->getArg(0)); | |
| 504 Call->addArg(IntrinsicCall->getArg(1)); | |
| 505 Call->addArg(IntrinsicCall->getArg(2)); | |
| 506 Context.insert(Call); | |
| 507 Instr->setDeleted(); | |
| 508 return; | |
| 509 } | |
| 510 case Intrinsics::Memmove: { | |
| 511 static constexpr SizeT MaxArgs = 3; | |
| 512 static constexpr Variable *NoDest = nullptr; | |
| 513 Operand *TargetHelper = Ctx->getConstantExternSym(H_call_memmove); | |
| 514 auto *Call = InstCall::create(Func, MaxArgs, NoDest, TargetHelper, | |
| 515 NoTailCall, IsTargetHelperCall); | |
| 516 Call->addArg(IntrinsicCall->getArg(0)); | |
| 517 Call->addArg(IntrinsicCall->getArg(1)); | |
| 518 Call->addArg(IntrinsicCall->getArg(2)); | |
| 519 Context.insert(Call); | |
| 520 Instr->setDeleted(); | |
| 521 return; | |
| 522 } | |
| 523 case Intrinsics::Memset: { | |
| 524 // The value operand needs to be extended to a stack slot size because the | |
| 525 // PNaCl ABI requires arguments to be at least 32 bits wide. | |
| 526 Operand *ValOp = IntrinsicCall->getArg(1); | |
| 527 assert(ValOp->getType() == IceType_i8); | |
| 528 Variable *ValExt = Func->makeVariable(stackSlotType()); | |
| 529 Context.insert(InstCast::create(Func, InstCast::Zext, ValExt, ValOp)); | |
| 530 | |
| 531 // Technically, ARM has its own __aeabi_memset, but we can use plain | |
| 532 // memset too. The value and size argument need to be flipped if we ever | |
| 533 // decide to use __aeabi_memset. | |
| 534 static constexpr SizeT MaxArgs = 3; | |
| 535 static constexpr Variable *NoDest = nullptr; | |
| 536 Operand *TargetHelper = Ctx->getConstantExternSym(H_call_memset); | |
| 537 auto *Call = InstCall::create(Func, MaxArgs, NoDest, TargetHelper, | |
| 538 NoTailCall, IsTargetHelperCall); | |
| 539 Call->addArg(IntrinsicCall->getArg(0)); | |
| 540 Call->addArg(ValExt); | |
| 541 Call->addArg(IntrinsicCall->getArg(2)); | |
| 542 Context.insert(Call); | |
| 543 Instr->setDeleted(); | |
| 544 return; | |
| 545 } | |
| 546 case Intrinsics::NaClReadTP: { | |
| 547 if (Ctx->getFlags().getUseSandboxing()) { | |
| 548 UnimplementedError(Func->getContext()->getFlags()); | |
| 549 return; | |
| 550 } | |
| 551 static constexpr SizeT MaxArgs = 0; | |
| 552 Operand *TargetHelper = Ctx->getConstantExternSym(H_call_read_tp); | |
| 553 auto *Call = InstCall::create(Func, MaxArgs, Dest, TargetHelper, | |
| 554 NoTailCall, IsTargetHelperCall); | |
| 555 Context.insert(Call); | |
| 556 Instr->setDeleted(); | |
| 557 return; | |
| 558 } | |
| 559 case Intrinsics::Setjmp: { | |
| 560 static constexpr SizeT MaxArgs = 1; | |
| 561 Operand *TargetHelper = Ctx->getConstantExternSym(H_call_setjmp); | |
| 562 auto *Call = InstCall::create(Func, MaxArgs, Dest, TargetHelper, | |
| 563 NoTailCall, IsTargetHelperCall); | |
| 564 Call->addArg(IntrinsicCall->getArg(0)); | |
| 565 Context.insert(Call); | |
| 566 Instr->setDeleted(); | |
| 567 return; | |
| 568 } | |
| 569 } | |
| 570 llvm_unreachable("Control flow should never have reached here."); | |
| 571 } | |
| 572 } | |
| 573 } | |
| 574 | |
| 268 void TargetARM32::findMaxStackOutArgsSize() { | 575 void TargetARM32::findMaxStackOutArgsSize() { |
| 269 // MinNeededOutArgsBytes should be updated if the Target ever creates a | 576 // MinNeededOutArgsBytes should be updated if the Target ever creates a |
| 270 // high-level InstCall that requires more stack bytes. | 577 // high-level InstCall that requires more stack bytes. |
| 271 constexpr size_t MinNeededOutArgsBytes = 0; | 578 constexpr size_t MinNeededOutArgsBytes = 0; |
| 272 MaxOutArgsSizeBytes = MinNeededOutArgsBytes; | 579 MaxOutArgsSizeBytes = MinNeededOutArgsBytes; |
| 273 for (CfgNode *Node : Func->getNodes()) { | 580 for (CfgNode *Node : Func->getNodes()) { |
| 274 Context.init(Node); | 581 Context.init(Node); |
| 275 while (!Context.atEnd()) { | 582 while (!Context.atEnd()) { |
| 276 PostIncrLoweringContext PostIncrement(Context); | 583 PostIncrLoweringContext PostIncrement(Context); |
| 277 Inst *CurInstr = Context.getCur(); | 584 Inst *CurInstr = Context.getCur(); |
| (...skipping 921 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1199 if (Mem->isRegReg()) { | 1506 if (Mem->isRegReg()) { |
| 1200 Variable *IndexR = legalizeToReg(Mem->getIndex()); | 1507 Variable *IndexR = legalizeToReg(Mem->getIndex()); |
| 1201 return OperandARM32Mem::create(Func, IceType_i32, BaseR, IndexR, | 1508 return OperandARM32Mem::create(Func, IceType_i32, BaseR, IndexR, |
| 1202 Mem->getShiftOp(), Mem->getShiftAmt(), | 1509 Mem->getShiftOp(), Mem->getShiftAmt(), |
| 1203 Mem->getAddrMode()); | 1510 Mem->getAddrMode()); |
| 1204 } else { | 1511 } else { |
| 1205 return OperandARM32Mem::create(Func, IceType_i32, BaseR, Mem->getOffset(), | 1512 return OperandARM32Mem::create(Func, IceType_i32, BaseR, Mem->getOffset(), |
| 1206 Mem->getAddrMode()); | 1513 Mem->getAddrMode()); |
| 1207 } | 1514 } |
| 1208 } | 1515 } |
| 1209 llvm_unreachable("Unsupported operand type"); | 1516 llvm_unreachable("Unsupported operand type"); |
|
Jim Stichnoth
2015/12/01 17:01:56
report_fatal_error
John
2015/12/01 20:56:27
Done.
| |
| 1210 return nullptr; | 1517 return nullptr; |
| 1211 } | 1518 } |
| 1212 | 1519 |
| 1213 Operand *TargetARM32::hiOperand(Operand *Operand) { | 1520 Operand *TargetARM32::hiOperand(Operand *Operand) { |
| 1214 assert(Operand->getType() == IceType_i64); | 1521 assert(Operand->getType() == IceType_i64); |
| 1215 if (Operand->getType() != IceType_i64) | 1522 if (Operand->getType() != IceType_i64) |
| 1216 return Operand; | 1523 return Operand; |
| 1217 if (auto *Var64On32 = llvm::dyn_cast<Variable64On32>(Operand)) | 1524 if (auto *Var64On32 = llvm::dyn_cast<Variable64On32>(Operand)) |
| 1218 return Var64On32->getHi(); | 1525 return Var64On32->getHi(); |
| 1219 if (auto *Const = llvm::dyn_cast<ConstantInteger64>(Operand)) { | 1526 if (auto *Const = llvm::dyn_cast<ConstantInteger64>(Operand)) { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1259 Base = NewBase; | 1566 Base = NewBase; |
| 1260 } else { | 1567 } else { |
| 1261 Offset = | 1568 Offset = |
| 1262 llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(NextOffsetVal)); | 1569 llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(NextOffsetVal)); |
| 1263 } | 1570 } |
| 1264 Variable *BaseR = legalizeToReg(Base); | 1571 Variable *BaseR = legalizeToReg(Base); |
| 1265 return OperandARM32Mem::create(Func, SplitType, BaseR, Offset, | 1572 return OperandARM32Mem::create(Func, SplitType, BaseR, Offset, |
| 1266 Mem->getAddrMode()); | 1573 Mem->getAddrMode()); |
| 1267 } | 1574 } |
| 1268 } | 1575 } |
| 1269 llvm_unreachable("Unsupported operand type"); | 1576 llvm_unreachable("Unsupported operand type"); |
|
Jim Stichnoth
2015/12/01 17:01:56
report_fatal_error
John
2015/12/01 20:56:27
Done.
| |
| 1270 return nullptr; | 1577 return nullptr; |
| 1271 } | 1578 } |
| 1272 | 1579 |
| 1273 llvm::SmallBitVector TargetARM32::getRegisterSet(RegSetMask Include, | 1580 llvm::SmallBitVector TargetARM32::getRegisterSet(RegSetMask Include, |
| 1274 RegSetMask Exclude) const { | 1581 RegSetMask Exclude) const { |
| 1275 llvm::SmallBitVector Registers(RegARM32::Reg_NUM); | 1582 llvm::SmallBitVector Registers(RegARM32::Reg_NUM); |
| 1276 | 1583 |
| 1277 #define X(val, encode, name, scratch, preserved, stackptr, frameptr, isInt, \ | 1584 #define X(val, encode, name, scratch, preserved, stackptr, frameptr, isInt, \ |
| 1278 isI64Pair, isFP32, isFP64, isVec128, alias_init) \ | 1585 isI64Pair, isFP32, isFP64, isVec128, alias_init) \ |
| 1279 if (scratch && (Include & RegSet_CallerSave)) \ | 1586 if (scratch && (Include & RegSet_CallerSave)) \ |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1406 } | 1713 } |
| 1407 } | 1714 } |
| 1408 InstARM32Label *Label = InstARM32Label::create(Func, this); | 1715 InstARM32Label *Label = InstARM32Label::create(Func, this); |
| 1409 _br(Label, CondARM32::NE); | 1716 _br(Label, CondARM32::NE); |
| 1410 _trap(); | 1717 _trap(); |
| 1411 Context.insert(Label); | 1718 Context.insert(Label); |
| 1412 } | 1719 } |
| 1413 | 1720 |
| 1414 void TargetARM32::lowerIDivRem(Variable *Dest, Variable *T, Variable *Src0R, | 1721 void TargetARM32::lowerIDivRem(Variable *Dest, Variable *T, Variable *Src0R, |
| 1415 Operand *Src1, ExtInstr ExtFunc, | 1722 Operand *Src1, ExtInstr ExtFunc, |
| 1416 DivInstr DivFunc, const char *DivHelperName, | 1723 DivInstr DivFunc, bool IsRemainder) { |
| 1417 bool IsRemainder) { | |
| 1418 div0Check(Dest->getType(), Src1, nullptr); | 1724 div0Check(Dest->getType(), Src1, nullptr); |
| 1419 Variable *Src1R = legalizeToReg(Src1); | 1725 Variable *Src1R = legalizeToReg(Src1); |
| 1420 Variable *T0R = Src0R; | 1726 Variable *T0R = Src0R; |
| 1421 Variable *T1R = Src1R; | 1727 Variable *T1R = Src1R; |
| 1422 if (Dest->getType() != IceType_i32) { | 1728 if (Dest->getType() != IceType_i32) { |
| 1423 T0R = makeReg(IceType_i32); | 1729 T0R = makeReg(IceType_i32); |
| 1424 (this->*ExtFunc)(T0R, Src0R, CondARM32::AL); | 1730 (this->*ExtFunc)(T0R, Src0R, CondARM32::AL); |
| 1425 T1R = makeReg(IceType_i32); | 1731 T1R = makeReg(IceType_i32); |
| 1426 (this->*ExtFunc)(T1R, Src1R, CondARM32::AL); | 1732 (this->*ExtFunc)(T1R, Src1R, CondARM32::AL); |
| 1427 } | 1733 } |
| 1428 if (hasCPUFeature(TargetARM32Features::HWDivArm)) { | 1734 if (hasCPUFeature(TargetARM32Features::HWDivArm)) { |
| 1429 (this->*DivFunc)(T, T0R, T1R, CondARM32::AL); | 1735 (this->*DivFunc)(T, T0R, T1R, CondARM32::AL); |
| 1430 if (IsRemainder) { | 1736 if (IsRemainder) { |
| 1431 Variable *T2 = makeReg(IceType_i32); | 1737 Variable *T2 = makeReg(IceType_i32); |
| 1432 _mls(T2, T, T1R, T0R); | 1738 _mls(T2, T, T1R, T0R); |
| 1433 T = T2; | 1739 T = T2; |
| 1434 } | 1740 } |
| 1435 _mov(Dest, T); | 1741 _mov(Dest, T); |
| 1436 } else { | 1742 } else { |
| 1437 constexpr SizeT MaxSrcs = 2; | 1743 llvm::report_fatal_error("div should have already been turned into a call"); |
| 1438 InstCall *Call = makeHelperCall(DivHelperName, Dest, MaxSrcs); | |
| 1439 Call->addArg(T0R); | |
| 1440 Call->addArg(T1R); | |
| 1441 lowerCall(Call); | |
| 1442 } | 1744 } |
| 1443 return; | |
| 1444 } | 1745 } |
| 1445 | 1746 |
| 1446 TargetARM32::SafeBoolChain | 1747 TargetARM32::SafeBoolChain |
| 1447 TargetARM32::lowerInt1Arithmetic(const InstArithmetic *Inst) { | 1748 TargetARM32::lowerInt1Arithmetic(const InstArithmetic *Inst) { |
| 1448 Variable *Dest = Inst->getDest(); | 1749 Variable *Dest = Inst->getDest(); |
| 1449 assert(Dest->getType() == IceType_i1); | 1750 assert(Dest->getType() == IceType_i1); |
| 1450 | 1751 |
| 1451 // So folding didn't work for Inst. Not a problem: We just need to | 1752 // So folding didn't work for Inst. Not a problem: We just need to |
| 1452 // materialize the Sources, and perform the operation. We create regular | 1753 // materialize the Sources, and perform the operation. We create regular |
| 1453 // Variables (and not infinite-weight ones) because this call might recurse a | 1754 // Variables (and not infinite-weight ones) because this call might recurse a |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1635 } | 1936 } |
| 1636 | 1937 |
| 1637 Operand *invertedSrc1F(TargetARM32 *Target) const { | 1938 Operand *invertedSrc1F(TargetARM32 *Target) const { |
| 1638 return legalizeToRegOrFlex(Target, | 1939 return legalizeToRegOrFlex(Target, |
| 1639 Target->getCtx()->getConstantInt32( | 1940 Target->getCtx()->getConstantInt32( |
| 1640 ~static_cast<uint32_t>(getConstantValue()))); | 1941 ~static_cast<uint32_t>(getConstantValue()))); |
| 1641 } | 1942 } |
| 1642 }; | 1943 }; |
| 1643 } // end of anonymous namespace | 1944 } // end of anonymous namespace |
| 1644 | 1945 |
| 1946 void TargetARM32::preambleDivRem(const InstCall *Instr) { | |
| 1947 Operand *Src1 = Instr->getArg(1); | |
| 1948 | |
| 1949 switch (Src1->getType()) { | |
| 1950 default: | |
| 1951 llvm::report_fatal_error("Invalid type for idiv."); | |
| 1952 case IceType_i64: { | |
| 1953 if (auto *C = llvm::dyn_cast<ConstantInteger64>(Src1)) { | |
| 1954 if (C->getValue() == 0) { | |
| 1955 _trap(); | |
| 1956 return; | |
| 1957 } | |
| 1958 } | |
| 1959 div0Check(IceType_i64, loOperand(Src1), hiOperand(Src1)); | |
| 1960 return; | |
| 1961 } | |
| 1962 case IceType_i32: { | |
| 1963 // Src0 and Src1 have already been appropriately extended to an i32, so we | |
| 1964 // don't check for i8 and i16. | |
| 1965 if (auto *C = llvm::dyn_cast<ConstantInteger32>(Src1)) { | |
| 1966 if (C->getValue() == 0) { | |
| 1967 _trap(); | |
| 1968 return; | |
| 1969 } | |
| 1970 } | |
| 1971 div0Check(IceType_i32, Src1, nullptr); | |
| 1972 return; | |
| 1973 } | |
| 1974 } | |
| 1975 } | |
| 1976 | |
| 1645 void TargetARM32::lowerInt64Arithmetic(InstArithmetic::OpKind Op, | 1977 void TargetARM32::lowerInt64Arithmetic(InstArithmetic::OpKind Op, |
| 1646 Variable *Dest, Operand *Src0, | 1978 Variable *Dest, Operand *Src0, |
| 1647 Operand *Src1) { | 1979 Operand *Src1) { |
| 1648 Int32Operands SrcsLo(loOperand(Src0), loOperand(Src1)); | 1980 Int32Operands SrcsLo(loOperand(Src0), loOperand(Src1)); |
| 1649 Int32Operands SrcsHi(hiOperand(Src0), hiOperand(Src1)); | 1981 Int32Operands SrcsHi(hiOperand(Src0), hiOperand(Src1)); |
| 1650 assert(SrcsLo.swappedOperands() == SrcsHi.swappedOperands()); | 1982 assert(SrcsLo.swappedOperands() == SrcsHi.swappedOperands()); |
| 1651 assert(SrcsLo.hasConstOperand() == SrcsHi.hasConstOperand()); | 1983 assert(SrcsLo.hasConstOperand() == SrcsHi.hasConstOperand()); |
| 1652 | 1984 |
| 1653 // These helper-call-involved instructions are lowered in this separate | |
| 1654 // switch. This is because we would otherwise assume that we need to | |
| 1655 // legalize Src0 to Src0RLo and Src0Hi. However, those go unused with | |
| 1656 // helper calls, and such unused/redundant instructions will fail liveness | |
| 1657 // analysis under -Om1 setting. | |
| 1658 switch (Op) { | |
| 1659 default: | |
| 1660 break; | |
| 1661 case InstArithmetic::Udiv: | |
| 1662 case InstArithmetic::Sdiv: | |
| 1663 case InstArithmetic::Urem: | |
| 1664 case InstArithmetic::Srem: { | |
| 1665 // Check for divide by 0 (ARM normally doesn't trap, but we want it to | |
| 1666 // trap for NaCl). Src1Lo and Src1Hi may have already been legalized to a | |
| 1667 // register, which will hide a constant source operand. Instead, check | |
| 1668 // the not-yet-legalized Src1 to optimize-out a divide by 0 check. | |
| 1669 if (!SrcsLo.swappedOperands() && SrcsLo.hasConstOperand()) { | |
| 1670 if (SrcsLo.getConstantValue() == 0 && SrcsHi.getConstantValue() == 0) { | |
| 1671 _trap(); | |
| 1672 return; | |
| 1673 } | |
| 1674 } else { | |
| 1675 Operand *Src1Lo = SrcsLo.unswappedSrc1R(this); | |
| 1676 Operand *Src1Hi = SrcsHi.unswappedSrc1R(this); | |
| 1677 div0Check(IceType_i64, Src1Lo, Src1Hi); | |
| 1678 } | |
| 1679 // Technically, ARM has its own aeabi routines, but we can use the | |
| 1680 // non-aeabi routine as well. LLVM uses __aeabi_ldivmod for div, but uses | |
| 1681 // the more standard __moddi3 for rem. | |
| 1682 const char *HelperName = ""; | |
| 1683 switch (Op) { | |
| 1684 default: | |
| 1685 llvm::report_fatal_error("Should have only matched div ops."); | |
| 1686 break; | |
| 1687 case InstArithmetic::Udiv: | |
| 1688 HelperName = H_udiv_i64; | |
| 1689 break; | |
| 1690 case InstArithmetic::Sdiv: | |
| 1691 HelperName = H_sdiv_i64; | |
| 1692 break; | |
| 1693 case InstArithmetic::Urem: | |
| 1694 HelperName = H_urem_i64; | |
| 1695 break; | |
| 1696 case InstArithmetic::Srem: | |
| 1697 HelperName = H_srem_i64; | |
| 1698 break; | |
| 1699 } | |
| 1700 constexpr SizeT MaxSrcs = 2; | |
| 1701 InstCall *Call = makeHelperCall(HelperName, Dest, MaxSrcs); | |
| 1702 Call->addArg(Src0); | |
| 1703 Call->addArg(Src1); | |
| 1704 lowerCall(Call); | |
| 1705 return; | |
| 1706 } | |
| 1707 } | |
| 1708 | |
| 1709 Variable *DestLo = llvm::cast<Variable>(loOperand(Dest)); | 1985 Variable *DestLo = llvm::cast<Variable>(loOperand(Dest)); |
| 1710 Variable *DestHi = llvm::cast<Variable>(hiOperand(Dest)); | 1986 Variable *DestHi = llvm::cast<Variable>(hiOperand(Dest)); |
| 1711 Variable *T_Lo = makeReg(DestLo->getType()); | 1987 Variable *T_Lo = makeReg(DestLo->getType()); |
| 1712 Variable *T_Hi = makeReg(DestHi->getType()); | 1988 Variable *T_Hi = makeReg(DestHi->getType()); |
| 1713 | 1989 |
| 1714 switch (Op) { | 1990 switch (Op) { |
| 1715 case InstArithmetic::_num: | 1991 case InstArithmetic::_num: |
| 1716 llvm::report_fatal_error("Unknown arithmetic operator"); | 1992 llvm::report_fatal_error("Unknown arithmetic operator"); |
| 1717 return; | 1993 return; |
| 1718 case InstArithmetic::Add: { | 1994 case InstArithmetic::Add: { |
| (...skipping 504 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2223 // difficult to determine (constant may be moved to a register). | 2499 // difficult to determine (constant may be moved to a register). |
| 2224 // * Handle floating point arithmetic separately: they require Src1 to be | 2500 // * Handle floating point arithmetic separately: they require Src1 to be |
| 2225 // legalized to a register. | 2501 // legalized to a register. |
| 2226 switch (Inst->getOp()) { | 2502 switch (Inst->getOp()) { |
| 2227 default: | 2503 default: |
| 2228 break; | 2504 break; |
| 2229 case InstArithmetic::Udiv: { | 2505 case InstArithmetic::Udiv: { |
| 2230 constexpr bool NotRemainder = false; | 2506 constexpr bool NotRemainder = false; |
| 2231 Variable *Src0R = legalizeToReg(Src0); | 2507 Variable *Src0R = legalizeToReg(Src0); |
| 2232 lowerIDivRem(Dest, T, Src0R, Src1, &TargetARM32::_uxt, &TargetARM32::_udiv, | 2508 lowerIDivRem(Dest, T, Src0R, Src1, &TargetARM32::_uxt, &TargetARM32::_udiv, |
| 2233 H_udiv_i32, NotRemainder); | 2509 NotRemainder); |
| 2234 return; | 2510 return; |
| 2235 } | 2511 } |
| 2236 case InstArithmetic::Sdiv: { | 2512 case InstArithmetic::Sdiv: { |
| 2237 constexpr bool NotRemainder = false; | 2513 constexpr bool NotRemainder = false; |
| 2238 Variable *Src0R = legalizeToReg(Src0); | 2514 Variable *Src0R = legalizeToReg(Src0); |
| 2239 lowerIDivRem(Dest, T, Src0R, Src1, &TargetARM32::_sxt, &TargetARM32::_sdiv, | 2515 lowerIDivRem(Dest, T, Src0R, Src1, &TargetARM32::_sxt, &TargetARM32::_sdiv, |
| 2240 H_sdiv_i32, NotRemainder); | 2516 NotRemainder); |
| 2241 return; | 2517 return; |
| 2242 } | 2518 } |
| 2243 case InstArithmetic::Urem: { | 2519 case InstArithmetic::Urem: { |
| 2244 constexpr bool IsRemainder = true; | 2520 constexpr bool IsRemainder = true; |
| 2245 Variable *Src0R = legalizeToReg(Src0); | 2521 Variable *Src0R = legalizeToReg(Src0); |
| 2246 lowerIDivRem(Dest, T, Src0R, Src1, &TargetARM32::_uxt, &TargetARM32::_udiv, | 2522 lowerIDivRem(Dest, T, Src0R, Src1, &TargetARM32::_uxt, &TargetARM32::_udiv, |
| 2247 H_urem_i32, IsRemainder); | 2523 IsRemainder); |
| 2248 return; | 2524 return; |
| 2249 } | 2525 } |
| 2250 case InstArithmetic::Srem: { | 2526 case InstArithmetic::Srem: { |
| 2251 constexpr bool IsRemainder = true; | 2527 constexpr bool IsRemainder = true; |
| 2252 Variable *Src0R = legalizeToReg(Src0); | 2528 Variable *Src0R = legalizeToReg(Src0); |
| 2253 lowerIDivRem(Dest, T, Src0R, Src1, &TargetARM32::_sxt, &TargetARM32::_sdiv, | 2529 lowerIDivRem(Dest, T, Src0R, Src1, &TargetARM32::_sxt, &TargetARM32::_sdiv, |
| 2254 H_srem_i32, IsRemainder); | 2530 IsRemainder); |
| 2255 return; | 2531 return; |
| 2256 } | 2532 } |
| 2257 case InstArithmetic::Frem: { | 2533 case InstArithmetic::Frem: { |
| 2258 constexpr SizeT MaxSrcs = 2; | 2534 if (!isScalarFloatingType(DestTy)) { |
| 2259 Variable *Src0R = legalizeToReg(Src0); | 2535 llvm::report_fatal_error("Unexpected type when lowering frem."); |
| 2260 Type Ty = DestTy; | 2536 } |
| 2261 InstCall *Call = makeHelperCall( | 2537 llvm::report_fatal_error("Frem should have already been lowered."); |
| 2262 isFloat32Asserting32Or64(Ty) ? H_frem_f32 : H_frem_f64, Dest, MaxSrcs); | |
| 2263 Call->addArg(Src0R); | |
| 2264 Call->addArg(Src1); | |
| 2265 lowerCall(Call); | |
| 2266 return; | |
| 2267 } | 2538 } |
| 2268 case InstArithmetic::Fadd: { | 2539 case InstArithmetic::Fadd: { |
| 2269 Variable *Src0R = legalizeToReg(Src0); | 2540 Variable *Src0R = legalizeToReg(Src0); |
| 2270 Variable *Src1R = legalizeToReg(Src1); | 2541 Variable *Src1R = legalizeToReg(Src1); |
| 2271 _vadd(T, Src0R, Src1R); | 2542 _vadd(T, Src0R, Src1R); |
| 2272 _mov(Dest, T); | 2543 _mov(Dest, T); |
| 2273 return; | 2544 return; |
| 2274 } | 2545 } |
| 2275 case InstArithmetic::Fsub: { | 2546 case InstArithmetic::Fsub: { |
| 2276 Variable *Src0R = legalizeToReg(Src0); | 2547 Variable *Src0R = legalizeToReg(Src0); |
| (...skipping 398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2675 case CondARM32::kNone: | 2946 case CondARM32::kNone: |
| 2676 _br(TargetFalse); | 2947 _br(TargetFalse); |
| 2677 break; | 2948 break; |
| 2678 case CondARM32::AL: | 2949 case CondARM32::AL: |
| 2679 _br(TargetTrue); | 2950 _br(TargetTrue); |
| 2680 break; | 2951 break; |
| 2681 } | 2952 } |
| 2682 } | 2953 } |
| 2683 | 2954 |
| 2684 void TargetARM32::lowerCall(const InstCall *Instr) { | 2955 void TargetARM32::lowerCall(const InstCall *Instr) { |
| 2956 Operand *CallTarget = Instr->getCallTarget(); | |
| 2957 if (Instr->isTargetHelperCall()) { | |
| 2958 auto TargetHelperPreamble = ARM32HelpersPreamble.find(CallTarget); | |
| 2959 if (TargetHelperPreamble != ARM32HelpersPreamble.end()) { | |
| 2960 (this->*TargetHelperPreamble->second)(Instr); | |
| 2961 } | |
| 2962 } | |
| 2685 MaybeLeafFunc = false; | 2963 MaybeLeafFunc = false; |
| 2686 NeedsStackAlignment = true; | 2964 NeedsStackAlignment = true; |
| 2687 | 2965 |
| 2688 // Assign arguments to registers and stack. Also reserve stack. | 2966 // Assign arguments to registers and stack. Also reserve stack. |
| 2689 TargetARM32::CallingConv CC; | 2967 TargetARM32::CallingConv CC; |
| 2690 // Pair of Arg Operand -> GPR number assignments. | 2968 // Pair of Arg Operand -> GPR number assignments. |
| 2691 llvm::SmallVector<std::pair<Operand *, int32_t>, | 2969 llvm::SmallVector<std::pair<Operand *, int32_t>, |
| 2692 TargetARM32::CallingConv::ARM32_MAX_GPR_ARG> GPRArgs; | 2970 TargetARM32::CallingConv::ARM32_MAX_GPR_ARG> GPRArgs; |
| 2693 llvm::SmallVector<std::pair<Operand *, int32_t>, | 2971 llvm::SmallVector<std::pair<Operand *, int32_t>, |
| 2694 TargetARM32::CallingConv::ARM32_MAX_FP_REG_UNITS> FPArgs; | 2972 TargetARM32::CallingConv::ARM32_MAX_FP_REG_UNITS> FPArgs; |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2797 case IceType_v8i1: | 3075 case IceType_v8i1: |
| 2798 case IceType_v16i1: | 3076 case IceType_v16i1: |
| 2799 case IceType_v16i8: | 3077 case IceType_v16i8: |
| 2800 case IceType_v8i16: | 3078 case IceType_v8i16: |
| 2801 case IceType_v4i32: | 3079 case IceType_v4i32: |
| 2802 case IceType_v4f32: | 3080 case IceType_v4f32: |
| 2803 ReturnReg = makeReg(Dest->getType(), RegARM32::Reg_q0); | 3081 ReturnReg = makeReg(Dest->getType(), RegARM32::Reg_q0); |
| 2804 break; | 3082 break; |
| 2805 } | 3083 } |
| 2806 } | 3084 } |
| 2807 Operand *CallTarget = Instr->getCallTarget(); | |
| 2808 // TODO(jvoung): Handle sandboxing. const bool NeedSandboxing = | 3085 // TODO(jvoung): Handle sandboxing. const bool NeedSandboxing = |
| 2809 // Ctx->getFlags().getUseSandboxing(); | 3086 // Ctx->getFlags().getUseSandboxing(); |
| 2810 | 3087 |
| 2811 // Allow ConstantRelocatable to be left alone as a direct call, but force | 3088 // Allow ConstantRelocatable to be left alone as a direct call, but force |
| 2812 // other constants like ConstantInteger32 to be in a register and make it an | 3089 // other constants like ConstantInteger32 to be in a register and make it an |
| 2813 // indirect call. | 3090 // indirect call. |
| 2814 if (!llvm::isa<ConstantRelocatable>(CallTarget)) { | 3091 if (!llvm::isa<ConstantRelocatable>(CallTarget)) { |
| 2815 CallTarget = legalize(CallTarget, Legal_Reg); | 3092 CallTarget = legalize(CallTarget, Legal_Reg); |
| 2816 } | 3093 } |
| 2817 | 3094 |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 2834 | 3111 |
| 2835 // Insert a register-kill pseudo instruction. | 3112 // Insert a register-kill pseudo instruction. |
| 2836 Context.insert(InstFakeKill::create(Func, NewCall)); | 3113 Context.insert(InstFakeKill::create(Func, NewCall)); |
| 2837 | 3114 |
| 2838 // Generate a FakeUse to keep the call live if necessary. | 3115 // Generate a FakeUse to keep the call live if necessary. |
| 2839 if (Instr->hasSideEffects() && ReturnReg) { | 3116 if (Instr->hasSideEffects() && ReturnReg) { |
| 2840 Inst *FakeUse = InstFakeUse::create(Func, ReturnReg); | 3117 Inst *FakeUse = InstFakeUse::create(Func, ReturnReg); |
| 2841 Context.insert(FakeUse); | 3118 Context.insert(FakeUse); |
| 2842 } | 3119 } |
| 2843 | 3120 |
| 2844 if (!Dest) | 3121 if (Dest != nullptr) { |
| 2845 return; | 3122 // Assign the result of the call to Dest. |
| 3123 if (ReturnReg != nullptr) { | |
| 3124 if (ReturnRegHi) { | |
| 3125 auto *Dest64On32 = llvm::cast<Variable64On32>(Dest); | |
| 3126 Variable *DestLo = Dest64On32->getLo(); | |
| 3127 Variable *DestHi = Dest64On32->getHi(); | |
| 3128 _mov(DestLo, ReturnReg); | |
| 3129 _mov(DestHi, ReturnRegHi); | |
| 3130 } else { | |
| 3131 if (isFloatingType(Dest->getType()) || isVectorType(Dest->getType())) { | |
| 3132 _mov(Dest, ReturnReg); | |
| 3133 } else { | |
| 3134 assert(isIntegerType(Dest->getType()) && | |
| 3135 typeWidthInBytes(Dest->getType()) <= 4); | |
| 3136 _mov(Dest, ReturnReg); | |
| 3137 } | |
| 3138 } | |
| 3139 } | |
| 3140 } | |
| 2846 | 3141 |
| 2847 // Assign the result of the call to Dest. | 3142 if (Instr->isTargetHelperCall()) { |
| 2848 if (ReturnReg) { | 3143 auto TargetHelpersPostamble = ARM32HelpersPostamble.find(CallTarget); |
| 2849 if (ReturnRegHi) { | 3144 if (TargetHelpersPostamble != ARM32HelpersPostamble.end()) { |
| 2850 auto *Dest64On32 = llvm::cast<Variable64On32>(Dest); | 3145 (this->*TargetHelpersPostamble->second)(Instr); |
| 2851 Variable *DestLo = Dest64On32->getLo(); | |
| 2852 Variable *DestHi = Dest64On32->getHi(); | |
| 2853 _mov(DestLo, ReturnReg); | |
| 2854 _mov(DestHi, ReturnRegHi); | |
| 2855 } else { | |
| 2856 if (isFloatingType(Dest->getType()) || isVectorType(Dest->getType())) { | |
| 2857 _mov(Dest, ReturnReg); | |
| 2858 } else { | |
| 2859 assert(isIntegerType(Dest->getType()) && | |
| 2860 typeWidthInBytes(Dest->getType()) <= 4); | |
| 2861 _mov(Dest, ReturnReg); | |
| 2862 } | |
| 2863 } | 3146 } |
| 2864 } | 3147 } |
| 2865 } | 3148 } |
| 2866 | 3149 |
| 2867 namespace { | 3150 namespace { |
| 2868 void configureBitcastTemporary(Variable64On32 *Var) { | 3151 void configureBitcastTemporary(Variable64On32 *Var) { |
| 2869 Var->setMustNotHaveReg(); | 3152 Var->setMustNotHaveReg(); |
| 2870 Var->getHi()->setMustHaveReg(); | 3153 Var->getHi()->setMustHaveReg(); |
| 2871 Var->getLo()->setMustHaveReg(); | 3154 Var->getLo()->setMustHaveReg(); |
| 2872 } | 3155 } |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3029 Variable *T = makeReg(Dest->getType()); | 3312 Variable *T = makeReg(Dest->getType()); |
| 3030 Context.insert(InstFakeDef::create(Func, T, legalizeToReg(Src0))); | 3313 Context.insert(InstFakeDef::create(Func, T, legalizeToReg(Src0))); |
| 3031 _mov(Dest, T); | 3314 _mov(Dest, T); |
| 3032 UnimplementedError(Func->getContext()->getFlags()); | 3315 UnimplementedError(Func->getContext()->getFlags()); |
| 3033 break; | 3316 break; |
| 3034 } | 3317 } |
| 3035 | 3318 |
| 3036 const bool DestIsSigned = CastKind == InstCast::Fptosi; | 3319 const bool DestIsSigned = CastKind == InstCast::Fptosi; |
| 3037 const bool Src0IsF32 = isFloat32Asserting32Or64(Src0->getType()); | 3320 const bool Src0IsF32 = isFloat32Asserting32Or64(Src0->getType()); |
| 3038 if (llvm::isa<Variable64On32>(Dest)) { | 3321 if (llvm::isa<Variable64On32>(Dest)) { |
| 3039 const char *HelperName = | 3322 llvm::report_fatal_error("fp-to-i64 should have been pre-lowered."); |
| 3040 Src0IsF32 ? (DestIsSigned ? H_fptosi_f32_i64 : H_fptoui_f32_i64) | |
| 3041 : (DestIsSigned ? H_fptosi_f64_i64 : H_fptoui_f64_i64); | |
| 3042 static constexpr SizeT MaxSrcs = 1; | |
| 3043 InstCall *Call = makeHelperCall(HelperName, Dest, MaxSrcs); | |
| 3044 Call->addArg(Src0); | |
| 3045 lowerCall(Call); | |
| 3046 break; | |
| 3047 } | 3323 } |
| 3048 // fptosi: | 3324 // fptosi: |
| 3049 // t1.fp = vcvt src0.fp | 3325 // t1.fp = vcvt src0.fp |
| 3050 // t2.i32 = vmov t1.fp | 3326 // t2.i32 = vmov t1.fp |
| 3051 // dest.int = conv t2.i32 @ Truncates the result if needed. | 3327 // dest.int = conv t2.i32 @ Truncates the result if needed. |
| 3052 // fptoui: | 3328 // fptoui: |
| 3053 // t1.fp = vcvt src0.fp | 3329 // t1.fp = vcvt src0.fp |
| 3054 // t2.u32 = vmov t1.fp | 3330 // t2.u32 = vmov t1.fp |
| 3055 // dest.uint = conv t2.u32 @ Truncates the result if needed. | 3331 // dest.uint = conv t2.u32 @ Truncates the result if needed. |
| 3056 Variable *Src0R = legalizeToReg(Src0); | 3332 Variable *Src0R = legalizeToReg(Src0); |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 3074 if (isVectorType(Dest->getType())) { | 3350 if (isVectorType(Dest->getType())) { |
| 3075 Variable *T = makeReg(Dest->getType()); | 3351 Variable *T = makeReg(Dest->getType()); |
| 3076 Context.insert(InstFakeDef::create(Func, T, legalizeToReg(Src0))); | 3352 Context.insert(InstFakeDef::create(Func, T, legalizeToReg(Src0))); |
| 3077 _mov(Dest, T); | 3353 _mov(Dest, T); |
| 3078 UnimplementedError(Func->getContext()->getFlags()); | 3354 UnimplementedError(Func->getContext()->getFlags()); |
| 3079 break; | 3355 break; |
| 3080 } | 3356 } |
| 3081 const bool SourceIsSigned = CastKind == InstCast::Sitofp; | 3357 const bool SourceIsSigned = CastKind == InstCast::Sitofp; |
| 3082 const bool DestIsF32 = isFloat32Asserting32Or64(Dest->getType()); | 3358 const bool DestIsF32 = isFloat32Asserting32Or64(Dest->getType()); |
| 3083 if (Src0->getType() == IceType_i64) { | 3359 if (Src0->getType() == IceType_i64) { |
| 3084 const char *HelperName = | 3360 llvm::report_fatal_error("i64-to-fp should have been pre-lowered."); |
| 3085 DestIsF32 ? (SourceIsSigned ? H_sitofp_i64_f32 : H_uitofp_i64_f32) | |
| 3086 : (SourceIsSigned ? H_sitofp_i64_f64 : H_uitofp_i64_f64); | |
| 3087 static constexpr SizeT MaxSrcs = 1; | |
| 3088 InstCall *Call = makeHelperCall(HelperName, Dest, MaxSrcs); | |
| 3089 Call->addArg(Src0); | |
| 3090 lowerCall(Call); | |
| 3091 break; | |
| 3092 } | 3361 } |
| 3093 // sitofp: | 3362 // sitofp: |
| 3094 // t1.i32 = sext src.int @ sign-extends src0 if needed. | 3363 // t1.i32 = sext src.int @ sign-extends src0 if needed. |
| 3095 // t2.fp32 = vmov t1.i32 | 3364 // t2.fp32 = vmov t1.i32 |
| 3096 // t3.fp = vcvt.{fp}.s32 @ fp is either f32 or f64 | 3365 // t3.fp = vcvt.{fp}.s32 @ fp is either f32 or f64 |
| 3097 // uitofp: | 3366 // uitofp: |
| 3098 // t1.i32 = zext src.int @ zero-extends src0 if needed. | 3367 // t1.i32 = zext src.int @ zero-extends src0 if needed. |
| 3099 // t2.fp32 = vmov t1.i32 | 3368 // t2.fp32 = vmov t1.i32 |
| 3100 // t3.fp = vcvt.{fp}.s32 @ fp is either f32 or f64 | 3369 // t3.fp = vcvt.{fp}.s32 @ fp is either f32 or f64 |
| 3101 if (Src0->getType() != IceType_i32) { | 3370 if (Src0->getType() != IceType_i32) { |
| (...skipping 665 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3767 } | 4036 } |
| 3768 lowerAssign(InstAssign::create(Func, Dest, PtrContentsReg)); | 4037 lowerAssign(InstAssign::create(Func, Dest, PtrContentsReg)); |
| 3769 if (auto *Dest64 = llvm::dyn_cast<Variable64On32>(Dest)) { | 4038 if (auto *Dest64 = llvm::dyn_cast<Variable64On32>(Dest)) { |
| 3770 Context.insert(InstFakeUse::create(Func, Dest64->getLo())); | 4039 Context.insert(InstFakeUse::create(Func, Dest64->getLo())); |
| 3771 Context.insert(InstFakeUse::create(Func, Dest64->getHi())); | 4040 Context.insert(InstFakeUse::create(Func, Dest64->getHi())); |
| 3772 } else { | 4041 } else { |
| 3773 Context.insert(InstFakeUse::create(Func, Dest)); | 4042 Context.insert(InstFakeUse::create(Func, Dest)); |
| 3774 } | 4043 } |
| 3775 } | 4044 } |
| 3776 | 4045 |
| 4046 void TargetARM32::postambleCtpop64(const InstCall *Instr) { | |
| 4047 Operand *Arg0 = Instr->getArg(0); | |
| 4048 if (isInt32Asserting32Or64(Arg0->getType())) { | |
| 4049 return; | |
| 4050 } | |
| 4051 // The popcount helpers always return 32-bit values, while the intrinsic's | |
| 4052 // signature matches some 64-bit platform's native instructions and expect to | |
| 4053 // fill a 64-bit reg. Thus, clear the upper bits of the dest just in case the | |
| 4054 // user doesn't do that in the IR or doesn't toss the bits via truncate. | |
| 4055 Variable *DestHi = llvm::cast<Variable>(hiOperand(Instr->getDest())); | |
| 4056 Variable *T = makeReg(IceType_i32); | |
| 4057 Operand *_0 = | |
| 4058 legalize(Ctx->getConstantZero(IceType_i32), Legal_Reg | Legal_Flex); | |
| 4059 _mov(T, _0); | |
| 4060 _mov(DestHi, T); | |
| 4061 } | |
| 4062 | |
| 3777 void TargetARM32::lowerIntrinsicCall(const InstIntrinsicCall *Instr) { | 4063 void TargetARM32::lowerIntrinsicCall(const InstIntrinsicCall *Instr) { |
| 3778 Variable *Dest = Instr->getDest(); | 4064 Variable *Dest = Instr->getDest(); |
| 3779 Type DestTy = (Dest != nullptr) ? Dest->getType() : IceType_void; | 4065 Type DestTy = (Dest != nullptr) ? Dest->getType() : IceType_void; |
| 3780 Intrinsics::IntrinsicID ID = Instr->getIntrinsicInfo().ID; | 4066 Intrinsics::IntrinsicID ID = Instr->getIntrinsicInfo().ID; |
| 3781 switch (ID) { | 4067 switch (ID) { |
| 3782 case Intrinsics::AtomicFence: | 4068 case Intrinsics::AtomicFence: |
| 3783 case Intrinsics::AtomicFenceAll: | 4069 case Intrinsics::AtomicFenceAll: |
| 3784 assert(Dest == nullptr); | 4070 assert(Dest == nullptr); |
| 3785 _dmb(); | 4071 _dmb(); |
| 3786 return; | 4072 return; |
| (...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4083 _rev(T, ValR); | 4369 _rev(T, ValR); |
| 4084 if (Val->getType() == IceType_i16) { | 4370 if (Val->getType() == IceType_i16) { |
| 4085 Operand *_16 = shAmtImm(16); | 4371 Operand *_16 = shAmtImm(16); |
| 4086 _lsr(T, T, _16); | 4372 _lsr(T, T, _16); |
| 4087 } | 4373 } |
| 4088 _mov(Dest, T); | 4374 _mov(Dest, T); |
| 4089 } | 4375 } |
| 4090 return; | 4376 return; |
| 4091 } | 4377 } |
| 4092 case Intrinsics::Ctpop: { | 4378 case Intrinsics::Ctpop: { |
| 4093 Operand *Val = Instr->getArg(0); | 4379 llvm::report_fatal_error("Ctpop should have been prelowered."); |
| 4094 InstCall *Call = makeHelperCall(isInt32Asserting32Or64(Val->getType()) | |
| 4095 ? H_call_ctpop_i32 | |
| 4096 : H_call_ctpop_i64, | |
| 4097 Dest, 1); | |
| 4098 Call->addArg(Val); | |
| 4099 lowerCall(Call); | |
| 4100 // The popcount helpers always return 32-bit values, while the intrinsic's | |
| 4101 // signature matches some 64-bit platform's native instructions and expect | |
| 4102 // to fill a 64-bit reg. Thus, clear the upper bits of the dest just in | |
| 4103 // case the user doesn't do that in the IR or doesn't toss the bits via | |
| 4104 // truncate. | |
| 4105 if (Val->getType() == IceType_i64) { | |
| 4106 Variable *DestHi = llvm::cast<Variable>(hiOperand(Dest)); | |
| 4107 Constant *Zero = Ctx->getConstantZero(IceType_i32); | |
| 4108 Variable *T = makeReg(Zero->getType()); | |
| 4109 _mov(T, Zero); | |
| 4110 _mov(DestHi, T); | |
| 4111 } | |
| 4112 return; | |
| 4113 } | 4380 } |
| 4114 case Intrinsics::Ctlz: { | 4381 case Intrinsics::Ctlz: { |
| 4115 // The "is zero undef" parameter is ignored and we always return a | 4382 // The "is zero undef" parameter is ignored and we always return a |
| 4116 // well-defined value. | 4383 // well-defined value. |
| 4117 Operand *Val = Instr->getArg(0); | 4384 Operand *Val = Instr->getArg(0); |
| 4118 Variable *ValLoR; | 4385 Variable *ValLoR; |
| 4119 Variable *ValHiR = nullptr; | 4386 Variable *ValHiR = nullptr; |
| 4120 if (Val->getType() == IceType_i64) { | 4387 if (Val->getType() == IceType_i64) { |
| 4121 Val = legalizeUndef(Val); | 4388 Val = legalizeUndef(Val); |
| 4122 ValLoR = legalizeToReg(loOperand(Val)); | 4389 ValLoR = legalizeToReg(loOperand(Val)); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4159 Context.insert(InstFakeDef::create(Func, T)); | 4426 Context.insert(InstFakeDef::create(Func, T)); |
| 4160 _mov(Dest, T); | 4427 _mov(Dest, T); |
| 4161 UnimplementedError(Func->getContext()->getFlags()); | 4428 UnimplementedError(Func->getContext()->getFlags()); |
| 4162 return; | 4429 return; |
| 4163 } | 4430 } |
| 4164 _vabs(T, legalizeToReg(Instr->getArg(0))); | 4431 _vabs(T, legalizeToReg(Instr->getArg(0))); |
| 4165 _mov(Dest, T); | 4432 _mov(Dest, T); |
| 4166 return; | 4433 return; |
| 4167 } | 4434 } |
| 4168 case Intrinsics::Longjmp: { | 4435 case Intrinsics::Longjmp: { |
| 4169 InstCall *Call = makeHelperCall(H_call_longjmp, nullptr, 2); | 4436 llvm::report_fatal_error("longjmp should have been prelowered."); |
| 4170 Call->addArg(Instr->getArg(0)); | |
| 4171 Call->addArg(Instr->getArg(1)); | |
| 4172 lowerCall(Call); | |
| 4173 return; | |
| 4174 } | 4437 } |
| 4175 case Intrinsics::Memcpy: { | 4438 case Intrinsics::Memcpy: { |
| 4176 // In the future, we could potentially emit an inline memcpy/memset, etc. | 4439 llvm::report_fatal_error("memcpy should have been prelowered."); |
| 4177 // for intrinsic calls w/ a known length. | |
| 4178 InstCall *Call = makeHelperCall(H_call_memcpy, nullptr, 3); | |
| 4179 Call->addArg(Instr->getArg(0)); | |
| 4180 Call->addArg(Instr->getArg(1)); | |
| 4181 Call->addArg(Instr->getArg(2)); | |
| 4182 lowerCall(Call); | |
| 4183 return; | |
| 4184 } | 4440 } |
| 4185 case Intrinsics::Memmove: { | 4441 case Intrinsics::Memmove: { |
| 4186 InstCall *Call = makeHelperCall(H_call_memmove, nullptr, 3); | 4442 llvm::report_fatal_error("memmove should have been prelowered."); |
| 4187 Call->addArg(Instr->getArg(0)); | |
| 4188 Call->addArg(Instr->getArg(1)); | |
| 4189 Call->addArg(Instr->getArg(2)); | |
| 4190 lowerCall(Call); | |
| 4191 return; | |
| 4192 } | 4443 } |
| 4193 case Intrinsics::Memset: { | 4444 case Intrinsics::Memset: { |
| 4194 // The value operand needs to be extended to a stack slot size because the | 4445 llvm::report_fatal_error("memmove should have been prelowered."); |
| 4195 // PNaCl ABI requires arguments to be at least 32 bits wide. | |
| 4196 Operand *ValOp = Instr->getArg(1); | |
| 4197 assert(ValOp->getType() == IceType_i8); | |
| 4198 Variable *ValExt = Func->makeVariable(stackSlotType()); | |
| 4199 lowerCast(InstCast::create(Func, InstCast::Zext, ValExt, ValOp)); | |
| 4200 // Technically, ARM has their own __aeabi_memset, but we can use plain | |
| 4201 // memset too. The value and size argument need to be flipped if we ever | |
| 4202 // decide to use __aeabi_memset. | |
| 4203 InstCall *Call = makeHelperCall(H_call_memset, nullptr, 3); | |
| 4204 Call->addArg(Instr->getArg(0)); | |
| 4205 Call->addArg(ValExt); | |
| 4206 Call->addArg(Instr->getArg(2)); | |
| 4207 lowerCall(Call); | |
| 4208 return; | |
| 4209 } | 4446 } |
| 4210 case Intrinsics::NaClReadTP: { | 4447 case Intrinsics::NaClReadTP: { |
| 4211 if (Ctx->getFlags().getUseSandboxing()) { | 4448 llvm::report_fatal_error("nacl-read-tp should have been prelowered."); |
| 4212 UnimplementedError(Func->getContext()->getFlags()); | |
| 4213 } else { | |
| 4214 InstCall *Call = makeHelperCall(H_call_read_tp, Dest, 0); | |
| 4215 lowerCall(Call); | |
| 4216 } | |
| 4217 return; | |
| 4218 } | 4449 } |
| 4219 case Intrinsics::Setjmp: { | 4450 case Intrinsics::Setjmp: { |
| 4220 InstCall *Call = makeHelperCall(H_call_setjmp, Dest, 1); | 4451 llvm::report_fatal_error("setjmp should have been prelowered."); |
| 4221 Call->addArg(Instr->getArg(0)); | |
| 4222 lowerCall(Call); | |
| 4223 return; | |
| 4224 } | 4452 } |
| 4225 case Intrinsics::Sqrt: { | 4453 case Intrinsics::Sqrt: { |
| 4226 Variable *Src = legalizeToReg(Instr->getArg(0)); | 4454 Variable *Src = legalizeToReg(Instr->getArg(0)); |
| 4227 Variable *T = makeReg(Dest->getType()); | 4455 Variable *T = makeReg(Dest->getType()); |
| 4228 _vsqrt(T, Src); | 4456 _vsqrt(T, Src); |
| 4229 _mov(Dest, T); | 4457 _mov(Dest, T); |
| 4230 return; | 4458 return; |
| 4231 } | 4459 } |
| 4232 case Intrinsics::Stacksave: { | 4460 case Intrinsics::Stacksave: { |
| 4233 Variable *SP = getPhysicalRegister(RegARM32::Reg_sp); | 4461 Variable *SP = getPhysicalRegister(RegARM32::Reg_sp); |
| (...skipping 875 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5109 // We need a new physical register for the operand if: | 5337 // We need a new physical register for the operand if: |
| 5110 // Mem is not allowed and Var isn't guaranteed a physical | 5338 // Mem is not allowed and Var isn't guaranteed a physical |
| 5111 // register, or | 5339 // register, or |
| 5112 // RegNum is required and Var->getRegNum() doesn't match. | 5340 // RegNum is required and Var->getRegNum() doesn't match. |
| 5113 if ((!(Allowed & Legal_Mem) && !MustHaveRegister) || | 5341 if ((!(Allowed & Legal_Mem) && !MustHaveRegister) || |
| 5114 (RegNum != Variable::NoRegister && RegNum != Var->getRegNum())) { | 5342 (RegNum != Variable::NoRegister && RegNum != Var->getRegNum())) { |
| 5115 From = copyToReg(From, RegNum); | 5343 From = copyToReg(From, RegNum); |
| 5116 } | 5344 } |
| 5117 return From; | 5345 return From; |
| 5118 } | 5346 } |
| 5119 llvm_unreachable("Unhandled operand kind in legalize()"); | 5347 llvm_unreachable("Unhandled operand kind in legalize()"); |
|
Jim Stichnoth
2015/12/01 17:01:56
report_fatal_error
John
2015/12/01 20:56:27
Done.
| |
| 5120 | 5348 |
| 5121 return From; | 5349 return From; |
| 5122 } | 5350 } |
| 5123 | 5351 |
| 5124 /// Provide a trivial wrapper to legalize() for this common usage. | 5352 /// Provide a trivial wrapper to legalize() for this common usage. |
| 5125 Variable *TargetARM32::legalizeToReg(Operand *From, int32_t RegNum) { | 5353 Variable *TargetARM32::legalizeToReg(Operand *From, int32_t RegNum) { |
| 5126 return llvm::cast<Variable>(legalize(From, Legal_Reg, RegNum)); | 5354 return llvm::cast<Variable>(legalize(From, Legal_Reg, RegNum)); |
| 5127 } | 5355 } |
| 5128 | 5356 |
| 5129 /// Legalize undef values to concrete values. | 5357 /// Legalize undef values to concrete values. |
| (...skipping 600 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5730 // Technically R9 is used for TLS with Sandboxing, and we reserve it. | 5958 // Technically R9 is used for TLS with Sandboxing, and we reserve it. |
| 5731 // However, for compatibility with current NaCl LLVM, don't claim that. | 5959 // However, for compatibility with current NaCl LLVM, don't claim that. |
| 5732 Str << ".eabi_attribute 14, 3 @ Tag_ABI_PCS_R9_use: Not used\n"; | 5960 Str << ".eabi_attribute 14, 3 @ Tag_ABI_PCS_R9_use: Not used\n"; |
| 5733 } | 5961 } |
| 5734 | 5962 |
| 5735 llvm::SmallBitVector TargetARM32::TypeToRegisterSet[IceType_NUM]; | 5963 llvm::SmallBitVector TargetARM32::TypeToRegisterSet[IceType_NUM]; |
| 5736 llvm::SmallBitVector TargetARM32::RegisterAliases[RegARM32::Reg_NUM]; | 5964 llvm::SmallBitVector TargetARM32::RegisterAliases[RegARM32::Reg_NUM]; |
| 5737 llvm::SmallBitVector TargetARM32::ScratchRegs; | 5965 llvm::SmallBitVector TargetARM32::ScratchRegs; |
| 5738 | 5966 |
| 5739 } // end of namespace Ice | 5967 } // end of namespace Ice |
| OLD | NEW |