| OLD | NEW |
| 1 //===- subzero/src/IceTargetLoweringX86BaseImpl.h - x86 lowering -*- C++ -*-==// | 1 //===- subzero/src/IceTargetLoweringX86BaseImpl.h - x86 lowering -*- C++ -*-==// |
| 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 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 301 } | 301 } |
| 302 | 302 |
| 303 template <typename TraitsType> | 303 template <typename TraitsType> |
| 304 void TargetX86Base<TraitsType>::initNodeForLowering(CfgNode *Node) { | 304 void TargetX86Base<TraitsType>::initNodeForLowering(CfgNode *Node) { |
| 305 FoldingInfo.init(Node); | 305 FoldingInfo.init(Node); |
| 306 FoldingInfo.dump(Func); | 306 FoldingInfo.dump(Func); |
| 307 } | 307 } |
| 308 | 308 |
| 309 template <typename TraitsType> | 309 template <typename TraitsType> |
| 310 TargetX86Base<TraitsType>::TargetX86Base(Cfg *Func) | 310 TargetX86Base<TraitsType>::TargetX86Base(Cfg *Func) |
| 311 : TargetLowering(Func), NeedSandboxing(Ctx->getFlags().getUseSandboxing()) { | 311 : TargetLowering(Func), NeedSandboxing(SandboxingType == ST_NaCl) { |
| 312 static_assert( | 312 static_assert( |
| 313 (Traits::InstructionSet::End - Traits::InstructionSet::Begin) == | 313 (Traits::InstructionSet::End - Traits::InstructionSet::Begin) == |
| 314 (TargetInstructionSet::X86InstructionSet_End - | 314 (TargetInstructionSet::X86InstructionSet_End - |
| 315 TargetInstructionSet::X86InstructionSet_Begin), | 315 TargetInstructionSet::X86InstructionSet_Begin), |
| 316 "Traits::InstructionSet range different from TargetInstructionSet"); | 316 "Traits::InstructionSet range different from TargetInstructionSet"); |
| 317 if (Func->getContext()->getFlags().getTargetInstructionSet() != | 317 if (Func->getContext()->getFlags().getTargetInstructionSet() != |
| 318 TargetInstructionSet::BaseInstructionSet) { | 318 TargetInstructionSet::BaseInstructionSet) { |
| 319 InstructionSet = static_cast<InstructionSetEnum>( | 319 InstructionSet = static_cast<InstructionSetEnum>( |
| 320 (Func->getContext()->getFlags().getTargetInstructionSet() - | 320 (Func->getContext()->getFlags().getTargetInstructionSet() - |
| 321 TargetInstructionSet::X86InstructionSet_Begin) + | 321 TargetInstructionSet::X86InstructionSet_Begin) + |
| 322 Traits::InstructionSet::Begin); | 322 Traits::InstructionSet::Begin); |
| 323 } | 323 } |
| 324 } | 324 } |
| 325 | 325 |
| 326 template <typename TraitsType> | 326 template <typename TraitsType> |
| 327 void TargetX86Base<TraitsType>::staticInit(GlobalContext *Ctx) { | 327 void TargetX86Base<TraitsType>::staticInit(GlobalContext *Ctx) { |
| 328 Traits::initRegisterSet(Ctx->getFlags(), &TypeToRegisterSet, | 328 Traits::initRegisterSet(Ctx->getFlags(), &TypeToRegisterSet, |
| 329 &RegisterAliases); | 329 &RegisterAliases); |
| 330 filterTypeToRegisterSet(Ctx, Traits::RegisterSet::Reg_NUM, | 330 filterTypeToRegisterSet(Ctx, Traits::RegisterSet::Reg_NUM, |
| 331 TypeToRegisterSet.data(), TypeToRegisterSet.size(), | 331 TypeToRegisterSet.data(), TypeToRegisterSet.size(), |
| 332 Traits::getRegName); | 332 Traits::getRegName); |
| 333 PcRelFixup = Traits::FK_PcRel; | 333 PcRelFixup = Traits::FK_PcRel; |
| 334 AbsFixup = | 334 AbsFixup = |
| 335 Ctx->getFlags().getUseNonsfi() ? Traits::FK_Gotoff : Traits::FK_Abs; | 335 Ctx->getFlags().getUseNonsfi() ? Traits::FK_Gotoff : Traits::FK_Abs; |
| 336 } | 336 } |
| 337 | 337 |
| 338 template <typename TraitsType> void TargetX86Base<TraitsType>::translateO2() { | 338 template <typename TraitsType> void TargetX86Base<TraitsType>::translateO2() { |
| 339 TimerMarker T(TimerStack::TT_O2, Func); | 339 TimerMarker T(TimerStack::TT_O2, Func); |
| 340 | 340 |
| 341 if (!Traits::Is64Bit && Func->getContext()->getFlags().getUseNonsfi()) { | 341 if (SandboxingType != ST_None) { |
| 342 GotVar = Func->makeVariable(IceType_i32); | 342 initSandboxPtr(); |
| 343 } | |
| 344 | |
| 345 if (NeedSandboxing) { | |
| 346 initSandbox(); | |
| 347 } | 343 } |
| 348 | 344 |
| 349 genTargetHelperCalls(); | 345 genTargetHelperCalls(); |
| 350 Func->dump("After target helper call insertion"); | 346 Func->dump("After target helper call insertion"); |
| 351 | 347 |
| 352 // Merge Alloca instructions, and lay out the stack. | 348 // Merge Alloca instructions, and lay out the stack. |
| 353 static constexpr bool SortAndCombineAllocas = true; | 349 static constexpr bool SortAndCombineAllocas = true; |
| 354 Func->processAllocas(SortAndCombineAllocas); | 350 Func->processAllocas(SortAndCombineAllocas); |
| 355 Func->dump("After Alloca processing"); | 351 Func->dump("After Alloca processing"); |
| 356 | 352 |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 407 Func->dump("After x86 address mode opt"); | 403 Func->dump("After x86 address mode opt"); |
| 408 | 404 |
| 409 // Disable constant blinding or pooling for load optimization. | 405 // Disable constant blinding or pooling for load optimization. |
| 410 { | 406 { |
| 411 BoolFlagSaver B(RandomizationPoolingPaused, true); | 407 BoolFlagSaver B(RandomizationPoolingPaused, true); |
| 412 doLoadOpt(); | 408 doLoadOpt(); |
| 413 } | 409 } |
| 414 Func->genCode(); | 410 Func->genCode(); |
| 415 if (Func->hasError()) | 411 if (Func->hasError()) |
| 416 return; | 412 return; |
| 417 initGotVarIfNeeded(); | 413 if (SandboxingType != ST_None) { |
| 414 initSandbox(); |
| 415 } |
| 418 Func->dump("After x86 codegen"); | 416 Func->dump("After x86 codegen"); |
| 419 | 417 |
| 420 // Register allocation. This requires instruction renumbering and full | 418 // Register allocation. This requires instruction renumbering and full |
| 421 // liveness analysis. Loops must be identified before liveness so variable | 419 // liveness analysis. Loops must be identified before liveness so variable |
| 422 // use weights are correct. | 420 // use weights are correct. |
| 423 Func->renumberInstructions(); | 421 Func->renumberInstructions(); |
| 424 if (Func->hasError()) | 422 if (Func->hasError()) |
| 425 return; | 423 return; |
| 426 Func->liveness(Liveness_Intervals); | 424 Func->liveness(Liveness_Intervals); |
| 427 if (Func->hasError()) | 425 if (Func->hasError()) |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 467 | 465 |
| 468 // Mark nodes that require sandbox alignment | 466 // Mark nodes that require sandbox alignment |
| 469 if (NeedSandboxing) { | 467 if (NeedSandboxing) { |
| 470 Func->markNodesForSandboxing(); | 468 Func->markNodesForSandboxing(); |
| 471 } | 469 } |
| 472 } | 470 } |
| 473 | 471 |
| 474 template <typename TraitsType> void TargetX86Base<TraitsType>::translateOm1() { | 472 template <typename TraitsType> void TargetX86Base<TraitsType>::translateOm1() { |
| 475 TimerMarker T(TimerStack::TT_Om1, Func); | 473 TimerMarker T(TimerStack::TT_Om1, Func); |
| 476 | 474 |
| 477 if (!Traits::Is64Bit && Func->getContext()->getFlags().getUseNonsfi()) { | 475 if (SandboxingType != ST_None) { |
| 478 GotVar = Func->makeVariable(IceType_i32); | 476 initSandboxPtr(); |
| 479 } | |
| 480 | |
| 481 if (NeedSandboxing) { | |
| 482 initSandbox(); | |
| 483 } | 477 } |
| 484 | 478 |
| 485 genTargetHelperCalls(); | 479 genTargetHelperCalls(); |
| 486 | 480 |
| 487 // Do not merge Alloca instructions, and lay out the stack. | 481 // Do not merge Alloca instructions, and lay out the stack. |
| 488 static constexpr bool SortAndCombineAllocas = false; | 482 static constexpr bool SortAndCombineAllocas = false; |
| 489 Func->processAllocas(SortAndCombineAllocas); | 483 Func->processAllocas(SortAndCombineAllocas); |
| 490 Func->dump("After Alloca processing"); | 484 Func->dump("After Alloca processing"); |
| 491 | 485 |
| 492 Func->placePhiLoads(); | 486 Func->placePhiLoads(); |
| 493 if (Func->hasError()) | 487 if (Func->hasError()) |
| 494 return; | 488 return; |
| 495 Func->placePhiStores(); | 489 Func->placePhiStores(); |
| 496 if (Func->hasError()) | 490 if (Func->hasError()) |
| 497 return; | 491 return; |
| 498 Func->deletePhis(); | 492 Func->deletePhis(); |
| 499 if (Func->hasError()) | 493 if (Func->hasError()) |
| 500 return; | 494 return; |
| 501 Func->dump("After Phi lowering"); | 495 Func->dump("After Phi lowering"); |
| 502 | 496 |
| 503 Func->doArgLowering(); | 497 Func->doArgLowering(); |
| 504 Func->genCode(); | 498 Func->genCode(); |
| 505 if (Func->hasError()) | 499 if (Func->hasError()) |
| 506 return; | 500 return; |
| 507 initGotVarIfNeeded(); | 501 if (SandboxingType != ST_None) { |
| 502 initSandbox(); |
| 503 } |
| 508 Func->dump("After initial x8632 codegen"); | 504 Func->dump("After initial x8632 codegen"); |
| 509 | 505 |
| 510 regAlloc(RAK_InfOnly); | 506 regAlloc(RAK_InfOnly); |
| 511 if (Func->hasError()) | 507 if (Func->hasError()) |
| 512 return; | 508 return; |
| 513 Func->dump("After regalloc of infinite-weight variables"); | 509 Func->dump("After regalloc of infinite-weight variables"); |
| 514 | 510 |
| 515 Func->genFrame(); | 511 Func->genFrame(); |
| 516 if (Func->hasError()) | 512 if (Func->hasError()) |
| 517 return; | 513 return; |
| (...skipping 476 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 994 } | 990 } |
| 995 | 991 |
| 996 template <typename TraitsType> | 992 template <typename TraitsType> |
| 997 llvm::SmallBitVector | 993 llvm::SmallBitVector |
| 998 TargetX86Base<TraitsType>::getRegisterSet(RegSetMask Include, | 994 TargetX86Base<TraitsType>::getRegisterSet(RegSetMask Include, |
| 999 RegSetMask Exclude) const { | 995 RegSetMask Exclude) const { |
| 1000 return Traits::getRegisterSet(Ctx->getFlags(), Include, Exclude); | 996 return Traits::getRegisterSet(Ctx->getFlags(), Include, Exclude); |
| 1001 } | 997 } |
| 1002 | 998 |
| 1003 template <typename TraitsType> | 999 template <typename TraitsType> |
| 1004 void TargetX86Base<TraitsType>::initGotVarIfNeeded() { | |
| 1005 if (!Func->getContext()->getFlags().getUseNonsfi()) | |
| 1006 return; | |
| 1007 if (Traits::Is64Bit) { | |
| 1008 // Probably no implementation is needed, but error to be safe for now. | |
| 1009 llvm::report_fatal_error( | |
| 1010 "Need to implement initGotVarIfNeeded() for 64-bit."); | |
| 1011 } | |
| 1012 // Insert the GotVar assignment as the very first lowered instruction. Later, | |
| 1013 // it will be moved into the right place - after the stack frame is set up but | |
| 1014 // before in-args are copied into registers. | |
| 1015 Context.init(Func->getEntryNode()); | |
| 1016 Context.setInsertPoint(Context.getCur()); | |
| 1017 Context.insert<typename Traits::Insts::GetIP>(GotVar); | |
| 1018 } | |
| 1019 | |
| 1020 template <typename TraitsType> | |
| 1021 void TargetX86Base<TraitsType>::lowerAlloca(const InstAlloca *Inst) { | 1000 void TargetX86Base<TraitsType>::lowerAlloca(const InstAlloca *Inst) { |
| 1022 // Conservatively require the stack to be aligned. Some stack adjustment | 1001 // Conservatively require the stack to be aligned. Some stack adjustment |
| 1023 // operations implemented below assume that the stack is aligned before the | 1002 // operations implemented below assume that the stack is aligned before the |
| 1024 // alloca. All the alloca code ensures that the stack alignment is preserved | 1003 // alloca. All the alloca code ensures that the stack alignment is preserved |
| 1025 // after the alloca. The stack alignment restriction can be relaxed in some | 1004 // after the alloca. The stack alignment restriction can be relaxed in some |
| 1026 // cases. | 1005 // cases. |
| 1027 NeedsStackAlignment = true; | 1006 NeedsStackAlignment = true; |
| 1028 | 1007 |
| 1029 // For default align=0, set it to the real value 1, to avoid any | 1008 // For default align=0, set it to the real value 1, to avoid any |
| 1030 // bit-manipulation problems below. | 1009 // bit-manipulation problems below. |
| (...skipping 3550 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4581 lowerCast(InstCast::create(Func, InstCast::Zext, ValExtVar, Val)); | 4560 lowerCast(InstCast::create(Func, InstCast::Zext, ValExtVar, Val)); |
| 4582 ValExt = ValExtVar; | 4561 ValExt = ValExtVar; |
| 4583 } | 4562 } |
| 4584 InstCall *Call = makeHelperCall(H_call_memset, nullptr, 3); | 4563 InstCall *Call = makeHelperCall(H_call_memset, nullptr, 3); |
| 4585 Call->addArg(Dest); | 4564 Call->addArg(Dest); |
| 4586 Call->addArg(ValExt); | 4565 Call->addArg(ValExt); |
| 4587 Call->addArg(Count); | 4566 Call->addArg(Count); |
| 4588 lowerCall(Call); | 4567 lowerCall(Call); |
| 4589 } | 4568 } |
| 4590 | 4569 |
| 4591 inline bool isAdd(const Inst *Inst) { | 4570 class AddressOptimizer { |
| 4592 if (auto *Arith = llvm::dyn_cast_or_null<const InstArithmetic>(Inst)) { | 4571 AddressOptimizer() = delete; |
| 4593 return (Arith->getOp() == InstArithmetic::Add); | 4572 AddressOptimizer(const AddressOptimizer &) = delete; |
| 4573 AddressOptimizer &operator=(const AddressOptimizer &) = delete; |
| 4574 |
| 4575 public: |
| 4576 explicit AddressOptimizer(const Cfg *Func) |
| 4577 : Func(Func), VMetadata(Func->getVMetadata()) {} |
| 4578 |
| 4579 inline void dumpAddressOpt(const ConstantRelocatable *const Relocatable, |
| 4580 int32_t Offset, const Variable *Base, |
| 4581 const Variable *Index, uint16_t Shift, |
| 4582 const Inst *Reason) const; |
| 4583 |
| 4584 inline const Inst *matchAssign(Variable **Var, |
| 4585 ConstantRelocatable **Relocatable, |
| 4586 int32_t *Offset); |
| 4587 |
| 4588 inline const Inst *matchCombinedBaseIndex(Variable **Base, Variable **Index, |
| 4589 uint16_t *Shift); |
| 4590 |
| 4591 inline const Inst *matchShiftedIndex(Variable **Index, uint16_t *Shift); |
| 4592 |
| 4593 inline const Inst *matchOffsetBase(Variable **Base, |
| 4594 ConstantRelocatable **Relocatable, |
| 4595 int32_t *Offset); |
| 4596 |
| 4597 private: |
| 4598 const Cfg *const Func; |
| 4599 const VariablesMetadata *const VMetadata; |
| 4600 |
| 4601 static bool isAdd(const Inst *Inst) { |
| 4602 if (auto *Arith = llvm::dyn_cast_or_null<const InstArithmetic>(Inst)) { |
| 4603 return (Arith->getOp() == InstArithmetic::Add); |
| 4604 } |
| 4605 return false; |
| 4594 } | 4606 } |
| 4595 return false; | 4607 }; |
| 4596 } | |
| 4597 | 4608 |
| 4598 inline void dumpAddressOpt(const Cfg *Func, | 4609 void AddressOptimizer::dumpAddressOpt( |
| 4599 const ConstantRelocatable *Relocatable, | 4610 const ConstantRelocatable *const Relocatable, int32_t Offset, |
| 4600 int32_t Offset, const Variable *Base, | 4611 const Variable *Base, const Variable *Index, uint16_t Shift, |
| 4601 const Variable *Index, uint16_t Shift, | 4612 const Inst *Reason) const { |
| 4602 const Inst *Reason) { | |
| 4603 if (!BuildDefs::dump()) | 4613 if (!BuildDefs::dump()) |
| 4604 return; | 4614 return; |
| 4605 if (!Func->isVerbose(IceV_AddrOpt)) | 4615 if (!Func->isVerbose(IceV_AddrOpt)) |
| 4606 return; | 4616 return; |
| 4607 OstreamLocker L(Func->getContext()); | 4617 OstreamLocker L(Func->getContext()); |
| 4608 Ostream &Str = Func->getContext()->getStrDump(); | 4618 Ostream &Str = Func->getContext()->getStrDump(); |
| 4609 Str << "Instruction: "; | 4619 Str << "Instruction: "; |
| 4610 Reason->dumpDecorated(Func); | 4620 Reason->dumpDecorated(Func); |
| 4611 Str << " results in Base="; | 4621 Str << " results in Base="; |
| 4612 if (Base) | 4622 if (Base) |
| 4613 Base->dump(Func); | 4623 Base->dump(Func); |
| 4614 else | 4624 else |
| 4615 Str << "<null>"; | 4625 Str << "<null>"; |
| 4616 Str << ", Index="; | 4626 Str << ", Index="; |
| 4617 if (Index) | 4627 if (Index) |
| 4618 Index->dump(Func); | 4628 Index->dump(Func); |
| 4619 else | 4629 else |
| 4620 Str << "<null>"; | 4630 Str << "<null>"; |
| 4621 Str << ", Shift=" << Shift << ", Offset=" << Offset | 4631 Str << ", Shift=" << Shift << ", Offset=" << Offset |
| 4622 << ", Relocatable=" << Relocatable << "\n"; | 4632 << ", Relocatable=" << Relocatable << "\n"; |
| 4623 } | 4633 } |
| 4624 | 4634 |
| 4625 inline bool matchAssign(const VariablesMetadata *VMetadata, Variable *GotVar, | 4635 const Inst *AddressOptimizer::matchAssign(Variable **Var, |
| 4626 Variable *&Var, ConstantRelocatable *&Relocatable, | 4636 ConstantRelocatable **Relocatable, |
| 4627 int32_t &Offset, const Inst *&Reason) { | 4637 int32_t *Offset) { |
| 4628 // Var originates from Var=SrcVar ==> set Var:=SrcVar | 4638 // Var originates from Var=SrcVar ==> set Var:=SrcVar |
| 4629 if (Var == nullptr) | 4639 if (*Var == nullptr) |
| 4630 return false; | 4640 return nullptr; |
| 4631 if (const Inst *VarAssign = VMetadata->getSingleDefinition(Var)) { | 4641 if (const Inst *VarAssign = VMetadata->getSingleDefinition(*Var)) { |
| 4632 assert(!VMetadata->isMultiDef(Var)); | 4642 assert(!VMetadata->isMultiDef(*Var)); |
| 4633 if (llvm::isa<InstAssign>(VarAssign)) { | 4643 if (llvm::isa<InstAssign>(VarAssign)) { |
| 4634 Operand *SrcOp = VarAssign->getSrc(0); | 4644 Operand *SrcOp = VarAssign->getSrc(0); |
| 4635 assert(SrcOp); | 4645 assert(SrcOp); |
| 4636 if (auto *SrcVar = llvm::dyn_cast<Variable>(SrcOp)) { | 4646 if (auto *SrcVar = llvm::dyn_cast<Variable>(SrcOp)) { |
| 4637 if (!VMetadata->isMultiDef(SrcVar) && | 4647 if (!VMetadata->isMultiDef(SrcVar) && |
| 4638 // TODO: ensure SrcVar stays single-BB | 4648 // TODO: ensure SrcVar stays single-BB |
| 4639 true) { | 4649 true) { |
| 4640 Var = SrcVar; | 4650 *Var = SrcVar; |
| 4641 Reason = VarAssign; | 4651 return VarAssign; |
| 4642 return true; | |
| 4643 } | 4652 } |
| 4644 } else if (auto *Const = llvm::dyn_cast<ConstantInteger32>(SrcOp)) { | 4653 } else if (auto *Const = llvm::dyn_cast<ConstantInteger32>(SrcOp)) { |
| 4645 int32_t MoreOffset = Const->getValue(); | 4654 int32_t MoreOffset = Const->getValue(); |
| 4646 if (Utils::WouldOverflowAdd(Offset, MoreOffset)) | 4655 if (Utils::WouldOverflowAdd(*Offset, MoreOffset)) |
| 4647 return false; | 4656 return nullptr; |
| 4648 Var = nullptr; | 4657 *Var = nullptr; |
| 4649 Offset += MoreOffset; | 4658 Offset += MoreOffset; |
| 4650 Reason = VarAssign; | 4659 return VarAssign; |
| 4651 return true; | |
| 4652 } else if (auto *AddReloc = llvm::dyn_cast<ConstantRelocatable>(SrcOp)) { | 4660 } else if (auto *AddReloc = llvm::dyn_cast<ConstantRelocatable>(SrcOp)) { |
| 4653 if (Relocatable == nullptr) { | 4661 if (*Relocatable == nullptr) { |
| 4654 Var = GotVar; | 4662 // It is always safe to fold a relocatable through assignment -- the |
| 4655 Relocatable = AddReloc; | 4663 // assignment frees a slot in the address operand that can be used to |
| 4656 Reason = VarAssign; | 4664 // hold the Sandbox Pointer -- if any. |
| 4657 return true; | 4665 *Var = nullptr; |
| 4666 *Relocatable = AddReloc; |
| 4667 return VarAssign; |
| 4658 } | 4668 } |
| 4659 } | 4669 } |
| 4660 } | 4670 } |
| 4661 } | 4671 } |
| 4662 return false; | 4672 return nullptr; |
| 4663 } | 4673 } |
| 4664 | 4674 |
| 4665 inline bool matchCombinedBaseIndex(const VariablesMetadata *VMetadata, | 4675 const Inst *AddressOptimizer::matchCombinedBaseIndex(Variable **Base, |
| 4666 Variable *&Base, Variable *&Index, | 4676 Variable **Index, |
| 4667 uint16_t &Shift, const Inst *&Reason) { | 4677 uint16_t *Shift) { |
| 4668 // Index==nullptr && Base is Base=Var1+Var2 ==> | 4678 // Index==nullptr && Base is Base=Var1+Var2 ==> |
| 4669 // set Base=Var1, Index=Var2, Shift=0 | 4679 // set Base=Var1, Index=Var2, Shift=0 |
| 4670 if (Base == nullptr) | 4680 if (*Base == nullptr) |
| 4671 return false; | 4681 return nullptr; |
| 4672 if (Index != nullptr) | 4682 if (*Index != nullptr) |
| 4673 return false; | 4683 return nullptr; |
| 4674 auto *BaseInst = VMetadata->getSingleDefinition(Base); | 4684 auto *BaseInst = VMetadata->getSingleDefinition(*Base); |
| 4675 if (BaseInst == nullptr) | 4685 if (BaseInst == nullptr) |
| 4676 return false; | 4686 return nullptr; |
| 4677 assert(!VMetadata->isMultiDef(Base)); | 4687 assert(!VMetadata->isMultiDef(*Base)); |
| 4678 if (BaseInst->getSrcSize() < 2) | 4688 if (BaseInst->getSrcSize() < 2) |
| 4679 return false; | 4689 return nullptr; |
| 4680 if (auto *Var1 = llvm::dyn_cast<Variable>(BaseInst->getSrc(0))) { | 4690 if (auto *Var1 = llvm::dyn_cast<Variable>(BaseInst->getSrc(0))) { |
| 4681 if (VMetadata->isMultiDef(Var1)) | 4691 if (VMetadata->isMultiDef(Var1)) |
| 4682 return false; | 4692 return nullptr; |
| 4683 if (auto *Var2 = llvm::dyn_cast<Variable>(BaseInst->getSrc(1))) { | 4693 if (auto *Var2 = llvm::dyn_cast<Variable>(BaseInst->getSrc(1))) { |
| 4684 if (VMetadata->isMultiDef(Var2)) | 4694 if (VMetadata->isMultiDef(Var2)) |
| 4685 return false; | 4695 return nullptr; |
| 4686 if (isAdd(BaseInst) && | 4696 if (isAdd(BaseInst) && |
| 4687 // TODO: ensure Var1 and Var2 stay single-BB | 4697 // TODO: ensure Var1 and Var2 stay single-BB |
| 4688 true) { | 4698 true) { |
| 4689 Base = Var1; | 4699 *Base = Var1; |
| 4690 Index = Var2; | 4700 *Index = Var2; |
| 4691 Shift = 0; // should already have been 0 | 4701 *Shift = 0; // should already have been 0 |
| 4692 Reason = BaseInst; | 4702 return BaseInst; |
| 4693 return true; | |
| 4694 } | 4703 } |
| 4695 } | 4704 } |
| 4696 } | 4705 } |
| 4697 return false; | 4706 return nullptr; |
| 4698 } | 4707 } |
| 4699 | 4708 |
| 4700 inline bool matchShiftedIndex(const VariablesMetadata *VMetadata, | 4709 const Inst *AddressOptimizer::matchShiftedIndex(Variable **Index, |
| 4701 Variable *&Index, uint16_t &Shift, | 4710 uint16_t *Shift) { |
| 4702 const Inst *&Reason) { | |
| 4703 // Index is Index=Var*Const && log2(Const)+Shift<=3 ==> | 4711 // Index is Index=Var*Const && log2(Const)+Shift<=3 ==> |
| 4704 // Index=Var, Shift+=log2(Const) | 4712 // Index=Var, Shift+=log2(Const) |
| 4705 if (Index == nullptr) | 4713 if (*Index == nullptr) |
| 4706 return false; | 4714 return nullptr; |
| 4707 auto *IndexInst = VMetadata->getSingleDefinition(Index); | 4715 auto *IndexInst = VMetadata->getSingleDefinition(*Index); |
| 4708 if (IndexInst == nullptr) | 4716 if (IndexInst == nullptr) |
| 4709 return false; | 4717 return nullptr; |
| 4710 assert(!VMetadata->isMultiDef(Index)); | 4718 assert(!VMetadata->isMultiDef(*Index)); |
| 4711 if (IndexInst->getSrcSize() < 2) | 4719 if (IndexInst->getSrcSize() < 2) |
| 4712 return false; | 4720 return nullptr; |
| 4713 if (auto *ArithInst = llvm::dyn_cast<InstArithmetic>(IndexInst)) { | 4721 if (auto *ArithInst = llvm::dyn_cast<InstArithmetic>(IndexInst)) { |
| 4714 if (auto *Var = llvm::dyn_cast<Variable>(ArithInst->getSrc(0))) { | 4722 if (auto *Var = llvm::dyn_cast<Variable>(ArithInst->getSrc(0))) { |
| 4715 if (auto *Const = | 4723 if (auto *Const = |
| 4716 llvm::dyn_cast<ConstantInteger32>(ArithInst->getSrc(1))) { | 4724 llvm::dyn_cast<ConstantInteger32>(ArithInst->getSrc(1))) { |
| 4717 if (VMetadata->isMultiDef(Var) || Const->getType() != IceType_i32) | 4725 if (VMetadata->isMultiDef(Var) || Const->getType() != IceType_i32) |
| 4718 return false; | 4726 return nullptr; |
| 4719 switch (ArithInst->getOp()) { | 4727 switch (ArithInst->getOp()) { |
| 4720 default: | 4728 default: |
| 4721 return false; | 4729 return nullptr; |
| 4722 case InstArithmetic::Mul: { | 4730 case InstArithmetic::Mul: { |
| 4723 uint32_t Mult = Const->getValue(); | 4731 uint32_t Mult = Const->getValue(); |
| 4724 uint32_t LogMult; | 4732 uint32_t LogMult; |
| 4725 switch (Mult) { | 4733 switch (Mult) { |
| 4726 case 1: | 4734 case 1: |
| 4727 LogMult = 0; | 4735 LogMult = 0; |
| 4728 break; | 4736 break; |
| 4729 case 2: | 4737 case 2: |
| 4730 LogMult = 1; | 4738 LogMult = 1; |
| 4731 break; | 4739 break; |
| 4732 case 4: | 4740 case 4: |
| 4733 LogMult = 2; | 4741 LogMult = 2; |
| 4734 break; | 4742 break; |
| 4735 case 8: | 4743 case 8: |
| 4736 LogMult = 3; | 4744 LogMult = 3; |
| 4737 break; | 4745 break; |
| 4738 default: | 4746 default: |
| 4739 return false; | 4747 return nullptr; |
| 4740 } | 4748 } |
| 4741 if (Shift + LogMult <= 3) { | 4749 if (*Shift + LogMult <= 3) { |
| 4742 Index = Var; | 4750 *Index = Var; |
| 4743 Shift += LogMult; | 4751 *Shift += LogMult; |
| 4744 Reason = IndexInst; | 4752 return IndexInst; |
| 4745 return true; | |
| 4746 } | 4753 } |
| 4747 } | 4754 } |
| 4748 case InstArithmetic::Shl: { | 4755 case InstArithmetic::Shl: { |
| 4749 uint32_t ShiftAmount = Const->getValue(); | 4756 uint32_t ShiftAmount = Const->getValue(); |
| 4750 switch (ShiftAmount) { | 4757 switch (ShiftAmount) { |
| 4751 case 0: | 4758 case 0: |
| 4752 case 1: | 4759 case 1: |
| 4753 case 2: | 4760 case 2: |
| 4754 case 3: | 4761 case 3: |
| 4755 break; | 4762 break; |
| 4756 default: | 4763 default: |
| 4757 return false; | 4764 return nullptr; |
| 4758 } | 4765 } |
| 4759 if (Shift + ShiftAmount <= 3) { | 4766 if (*Shift + ShiftAmount <= 3) { |
| 4760 Index = Var; | 4767 *Index = Var; |
| 4761 Shift += ShiftAmount; | 4768 *Shift += ShiftAmount; |
| 4762 Reason = IndexInst; | 4769 return IndexInst; |
| 4763 return true; | |
| 4764 } | 4770 } |
| 4765 } | 4771 } |
| 4766 } | 4772 } |
| 4767 } | 4773 } |
| 4768 } | 4774 } |
| 4769 } | 4775 } |
| 4770 return false; | 4776 return nullptr; |
| 4771 } | 4777 } |
| 4772 | 4778 |
| 4773 inline bool matchOffsetBase(const VariablesMetadata *VMetadata, | 4779 const Inst *AddressOptimizer::matchOffsetBase(Variable **Base, |
| 4774 Variable *GotVar, Variable *&Base, | 4780 ConstantRelocatable **Relocatable, |
| 4775 Variable *&BaseOther, | 4781 int32_t *Offset) { |
| 4776 ConstantRelocatable *&Relocatable, int32_t &Offset, | |
| 4777 const Inst *&Reason) { | |
| 4778 // Base is Base=Var+Const || Base is Base=Const+Var ==> | 4782 // Base is Base=Var+Const || Base is Base=Const+Var ==> |
| 4779 // set Base=Var, Offset+=Const | 4783 // set Base=Var, Offset+=Const |
| 4780 // Base is Base=Var-Const ==> | 4784 // Base is Base=Var-Const ==> |
| 4781 // set Base=Var, Offset-=Const | 4785 // set Base=Var, Offset-=Const |
| 4782 if (Base == nullptr) { | 4786 if (*Base == nullptr) { |
| 4783 return false; | 4787 return nullptr; |
| 4784 } | 4788 } |
| 4785 const Inst *BaseInst = VMetadata->getSingleDefinition(Base); | 4789 const Inst *BaseInst = VMetadata->getSingleDefinition(*Base); |
| 4786 if (BaseInst == nullptr) { | 4790 if (BaseInst == nullptr) { |
| 4787 return false; | 4791 return nullptr; |
| 4788 } | 4792 } |
| 4789 assert(!VMetadata->isMultiDef(Base)); | 4793 assert(!VMetadata->isMultiDef(*Base)); |
| 4790 if (auto *ArithInst = llvm::dyn_cast<const InstArithmetic>(BaseInst)) { | 4794 if (auto *ArithInst = llvm::dyn_cast<const InstArithmetic>(BaseInst)) { |
| 4791 if (ArithInst->getOp() != InstArithmetic::Add && | 4795 if (ArithInst->getOp() != InstArithmetic::Add && |
| 4792 ArithInst->getOp() != InstArithmetic::Sub) | 4796 ArithInst->getOp() != InstArithmetic::Sub) |
| 4793 return false; | 4797 return nullptr; |
| 4794 bool IsAdd = ArithInst->getOp() == InstArithmetic::Add; | 4798 bool IsAdd = ArithInst->getOp() == InstArithmetic::Add; |
| 4795 Operand *Src0 = ArithInst->getSrc(0); | 4799 Operand *Src0 = ArithInst->getSrc(0); |
| 4796 Operand *Src1 = ArithInst->getSrc(1); | 4800 Operand *Src1 = ArithInst->getSrc(1); |
| 4797 auto *Var0 = llvm::dyn_cast<Variable>(Src0); | 4801 auto *Var0 = llvm::dyn_cast<Variable>(Src0); |
| 4798 auto *Var1 = llvm::dyn_cast<Variable>(Src1); | 4802 auto *Var1 = llvm::dyn_cast<Variable>(Src1); |
| 4799 auto *Const0 = llvm::dyn_cast<ConstantInteger32>(Src0); | 4803 auto *Const0 = llvm::dyn_cast<ConstantInteger32>(Src0); |
| 4800 auto *Const1 = llvm::dyn_cast<ConstantInteger32>(Src1); | 4804 auto *Const1 = llvm::dyn_cast<ConstantInteger32>(Src1); |
| 4801 auto *Reloc0 = llvm::dyn_cast<ConstantRelocatable>(Src0); | 4805 auto *Reloc0 = llvm::dyn_cast<ConstantRelocatable>(Src0); |
| 4802 auto *Reloc1 = llvm::dyn_cast<ConstantRelocatable>(Src1); | 4806 auto *Reloc1 = llvm::dyn_cast<ConstantRelocatable>(Src1); |
| 4803 Variable *NewBase = nullptr; | 4807 Variable *NewBase = nullptr; |
| 4804 int32_t NewOffset = Offset; | 4808 int32_t NewOffset = *Offset; |
| 4805 ConstantRelocatable *NewRelocatable = Relocatable; | 4809 ConstantRelocatable *NewRelocatable = *Relocatable; |
| 4806 if (Var0 && Var1) | 4810 if (Var0 && Var1) |
| 4807 // TODO(sehr): merge base/index splitting into here. | 4811 // TODO(sehr): merge base/index splitting into here. |
| 4808 return false; | 4812 return nullptr; |
| 4809 if (!IsAdd && Var1) | 4813 if (!IsAdd && Var1) |
| 4810 return false; | 4814 return nullptr; |
| 4811 if (Var0) | 4815 if (Var0) |
| 4812 NewBase = Var0; | 4816 NewBase = Var0; |
| 4813 else if (Var1) | 4817 else if (Var1) |
| 4814 NewBase = Var1; | 4818 NewBase = Var1; |
| 4815 // Don't know how to add/subtract two relocatables. | 4819 // Don't know how to add/subtract two relocatables. |
| 4816 if ((Relocatable && (Reloc0 || Reloc1)) || (Reloc0 && Reloc1)) | 4820 if ((*Relocatable && (Reloc0 || Reloc1)) || (Reloc0 && Reloc1)) |
| 4817 return false; | 4821 return nullptr; |
| 4818 // Don't know how to subtract a relocatable. | 4822 // Don't know how to subtract a relocatable. |
| 4819 if (!IsAdd && Reloc1) | 4823 if (!IsAdd && Reloc1) |
| 4820 return false; | 4824 return nullptr; |
| 4821 // Incorporate ConstantRelocatables. | 4825 // Incorporate ConstantRelocatables. |
| 4822 if (Reloc0) | 4826 if (Reloc0) |
| 4823 NewRelocatable = Reloc0; | 4827 NewRelocatable = Reloc0; |
| 4824 else if (Reloc1) | 4828 else if (Reloc1) |
| 4825 NewRelocatable = Reloc1; | 4829 NewRelocatable = Reloc1; |
| 4826 if ((Reloc0 || Reloc1) && BaseOther && GotVar) | |
| 4827 return false; | |
| 4828 // Compute the updated constant offset. | 4830 // Compute the updated constant offset. |
| 4829 if (Const0) { | 4831 if (Const0) { |
| 4830 const int32_t MoreOffset = | 4832 const int32_t MoreOffset = |
| 4831 IsAdd ? Const0->getValue() : -Const0->getValue(); | 4833 IsAdd ? Const0->getValue() : -Const0->getValue(); |
| 4832 if (Utils::WouldOverflowAdd(NewOffset, MoreOffset)) | 4834 if (Utils::WouldOverflowAdd(NewOffset, MoreOffset)) |
| 4833 return false; | 4835 return nullptr; |
| 4834 NewOffset += MoreOffset; | 4836 NewOffset += MoreOffset; |
| 4835 } | 4837 } |
| 4836 if (Const1) { | 4838 if (Const1) { |
| 4837 const int32_t MoreOffset = | 4839 const int32_t MoreOffset = |
| 4838 IsAdd ? Const1->getValue() : -Const1->getValue(); | 4840 IsAdd ? Const1->getValue() : -Const1->getValue(); |
| 4839 if (Utils::WouldOverflowAdd(NewOffset, MoreOffset)) | 4841 if (Utils::WouldOverflowAdd(NewOffset, MoreOffset)) |
| 4840 return false; | 4842 return nullptr; |
| 4841 NewOffset += MoreOffset; | 4843 NewOffset += MoreOffset; |
| 4842 } | 4844 } |
| 4843 // Update the computed address parameters once we are sure optimization | 4845 *Base = NewBase; |
| 4844 // is valid. | 4846 *Offset = NewOffset; |
| 4845 if ((Reloc0 || Reloc1) && GotVar) { | 4847 *Relocatable = NewRelocatable; |
| 4846 assert(BaseOther == nullptr); | 4848 return BaseInst; |
| 4847 BaseOther = GotVar; | |
| 4848 } | |
| 4849 Base = NewBase; | |
| 4850 Offset = NewOffset; | |
| 4851 Relocatable = NewRelocatable; | |
| 4852 Reason = BaseInst; | |
| 4853 return true; | |
| 4854 } | 4849 } |
| 4855 return false; | 4850 return nullptr; |
| 4856 } | 4851 } |
| 4857 | 4852 |
| 4858 // Builds information for a canonical address expresion: | 4853 template <typename TypeTraits> |
| 4859 // <Relocatable + Offset>(Base, Index, Shift) | 4854 typename TargetX86Base<TypeTraits>::X86OperandMem * |
| 4860 // On entry: | 4855 TargetX86Base<TypeTraits>::computeAddressOpt(const Inst *Instr, Type MemType, |
| 4861 // Relocatable == null, | 4856 Operand *Addr) { |
| 4862 // Offset == 0, | |
| 4863 // Base is a Variable, | |
| 4864 // Index == nullptr, | |
| 4865 // Shift == 0 | |
| 4866 inline bool computeAddressOpt(Cfg *Func, const Inst *Instr, Variable *GotVar, | |
| 4867 bool ReserveSlot, | |
| 4868 ConstantRelocatable *&Relocatable, | |
| 4869 int32_t &Offset, Variable *&Base, | |
| 4870 Variable *&Index, uint16_t &Shift) { | |
| 4871 bool AddressWasOptimized = false; | |
| 4872 Func->resetCurrentNode(); | 4857 Func->resetCurrentNode(); |
| 4873 if (Func->isVerbose(IceV_AddrOpt)) { | 4858 if (Func->isVerbose(IceV_AddrOpt)) { |
| 4874 OstreamLocker L(Func->getContext()); | 4859 OstreamLocker L(Func->getContext()); |
| 4875 Ostream &Str = Func->getContext()->getStrDump(); | 4860 Ostream &Str = Func->getContext()->getStrDump(); |
| 4876 Str << "\nStarting computeAddressOpt for instruction:\n "; | 4861 Str << "\nStarting computeAddressOpt for instruction:\n "; |
| 4877 Instr->dumpDecorated(Func); | 4862 Instr->dumpDecorated(Func); |
| 4878 } | 4863 } |
| 4879 if (Base == nullptr) | 4864 |
| 4880 return AddressWasOptimized; | 4865 OptAddr NewAddr; |
| 4866 NewAddr.Base = llvm::dyn_cast<Variable>(Addr); |
| 4867 if (NewAddr.Base == nullptr) |
| 4868 return nullptr; |
| 4869 |
| 4881 // If the Base has more than one use or is live across multiple blocks, then | 4870 // If the Base has more than one use or is live across multiple blocks, then |
| 4882 // don't go further. Alternatively (?), never consider a transformation that | 4871 // don't go further. Alternatively (?), never consider a transformation that |
| 4883 // would change a variable that is currently *not* live across basic block | 4872 // would change a variable that is currently *not* live across basic block |
| 4884 // boundaries into one that *is*. | 4873 // boundaries into one that *is*. |
| 4885 if (Func->getVMetadata()->isMultiBlock(Base) /* || Base->getUseCount() > 1*/) | 4874 if (Func->getVMetadata()->isMultiBlock( |
| 4886 return AddressWasOptimized; | 4875 NewAddr.Base) /* || Base->getUseCount() > 1*/) |
| 4876 return nullptr; |
| 4887 | 4877 |
| 4878 AddressOptimizer AddrOpt(Func); |
| 4888 const bool MockBounds = Func->getContext()->getFlags().getMockBoundsCheck(); | 4879 const bool MockBounds = Func->getContext()->getFlags().getMockBoundsCheck(); |
| 4889 const VariablesMetadata *VMetadata = Func->getVMetadata(); | |
| 4890 const Inst *Reason = nullptr; | 4880 const Inst *Reason = nullptr; |
| 4881 bool AddressWasOptimized = false; |
| 4882 // The following unnamed struct identifies the address mode formation steps |
| 4883 // that could potentially create an invalid memory operand (i.e., no free |
| 4884 // slots for SandboxPtr.) We add all those variables to this struct so that we |
| 4885 // can use memset() to reset all members to false. |
| 4886 struct { |
| 4887 bool AssignBase = false; |
| 4888 bool AssignIndex = false; |
| 4889 bool OffsetFromBase = false; |
| 4890 bool OffsetFromIndex = false; |
| 4891 bool CombinedBaseIndex = false; |
| 4892 } Skip; |
| 4893 // This points to the boolean in Skip that represents the last folding |
| 4894 // performed. This is used to disable a pattern match that generated an |
| 4895 // invalid address. Without this, the algorithm would never finish. |
| 4896 bool *SkipLastFolding = nullptr; |
| 4897 // NewAddrCheckpoint is used to rollback the address being formed in case an |
| 4898 // invalid address is formed. |
| 4899 OptAddr NewAddrCheckpoint; |
| 4900 Reason = Instr; |
| 4891 do { | 4901 do { |
| 4892 assert(!ReserveSlot || Base == nullptr || Index == nullptr); | 4902 if (SandboxingType != ST_None) { |
| 4903 // When sandboxing, we defer the sandboxing of NewAddr to the Concrete |
| 4904 // Target. If our optimization was overly aggressive, then we simply undo |
| 4905 // what the previous iteration did, and set the previous pattern's skip |
| 4906 // bit to true. |
| 4907 if (!legalizeOptAddrForSandbox(&NewAddr)) { |
| 4908 *SkipLastFolding = true; |
| 4909 SkipLastFolding = nullptr; |
| 4910 NewAddr = NewAddrCheckpoint; |
| 4911 Reason = nullptr; |
| 4912 } |
| 4913 } |
| 4914 |
| 4893 if (Reason) { | 4915 if (Reason) { |
| 4894 dumpAddressOpt(Func, Relocatable, Offset, Base, Index, Shift, Reason); | 4916 AddrOpt.dumpAddressOpt(NewAddr.Relocatable, NewAddr.Offset, NewAddr.Base, |
| 4917 NewAddr.Index, NewAddr.Shift, Reason); |
| 4895 AddressWasOptimized = true; | 4918 AddressWasOptimized = true; |
| 4896 Reason = nullptr; | 4919 Reason = nullptr; |
| 4920 SkipLastFolding = nullptr; |
| 4921 memset(&Skip, 0, sizeof(Skip)); |
| 4897 } | 4922 } |
| 4923 |
| 4924 NewAddrCheckpoint = NewAddr; |
| 4925 |
| 4898 // Update Base and Index to follow through assignments to definitions. | 4926 // Update Base and Index to follow through assignments to definitions. |
| 4899 if (matchAssign(VMetadata, GotVar, Base, Relocatable, Offset, Reason)) { | 4927 if (!Skip.AssignBase && |
| 4928 (Reason = AddrOpt.matchAssign(&NewAddr.Base, &NewAddr.Relocatable, |
| 4929 &NewAddr.Offset))) { |
| 4930 SkipLastFolding = &Skip.AssignBase; |
| 4900 // Assignments of Base from a Relocatable or ConstantInt32 can result | 4931 // Assignments of Base from a Relocatable or ConstantInt32 can result |
| 4901 // in Base becoming nullptr. To avoid code duplication in this loop we | 4932 // in Base becoming nullptr. To avoid code duplication in this loop we |
| 4902 // prefer that Base be non-nullptr if possible. | 4933 // prefer that Base be non-nullptr if possible. |
| 4903 if ((Base == nullptr) && (Index != nullptr) && Shift == 0) | 4934 if ((NewAddr.Base == nullptr) && (NewAddr.Index != nullptr) && |
| 4904 std::swap(Base, Index); | 4935 NewAddr.Shift == 0) { |
| 4936 std::swap(NewAddr.Base, NewAddr.Index); |
| 4937 } |
| 4905 continue; | 4938 continue; |
| 4906 } | 4939 } |
| 4907 if (matchAssign(VMetadata, GotVar, Index, Relocatable, Offset, Reason)) | 4940 if (!Skip.AssignBase && |
| 4941 (Reason = AddrOpt.matchAssign(&NewAddr.Index, &NewAddr.Relocatable, |
| 4942 &NewAddr.Offset))) { |
| 4943 SkipLastFolding = &Skip.AssignIndex; |
| 4908 continue; | 4944 continue; |
| 4945 } |
| 4909 | 4946 |
| 4910 if (!MockBounds) { | 4947 if (!MockBounds) { |
| 4911 // Transition from: | 4948 // Transition from: |
| 4912 // <Relocatable + Offset>(Base) to | 4949 // <Relocatable + Offset>(Base) to |
| 4913 // <Relocatable + Offset>(Base, Index) | 4950 // <Relocatable + Offset>(Base, Index) |
| 4914 if (!ReserveSlot && | 4951 if (!Skip.CombinedBaseIndex && |
| 4915 matchCombinedBaseIndex(VMetadata, Base, Index, Shift, Reason)) | 4952 (Reason = AddrOpt.matchCombinedBaseIndex( |
| 4953 &NewAddr.Base, &NewAddr.Index, &NewAddr.Shift))) { |
| 4954 SkipLastFolding = &Skip.CombinedBaseIndex; |
| 4916 continue; | 4955 continue; |
| 4956 } |
| 4957 |
| 4917 // Recognize multiply/shift and update Shift amount. | 4958 // Recognize multiply/shift and update Shift amount. |
| 4918 // Index becomes Index=Var<<Const && Const+Shift<=3 ==> | 4959 // Index becomes Index=Var<<Const && Const+Shift<=3 ==> |
| 4919 // Index=Var, Shift+=Const | 4960 // Index=Var, Shift+=Const |
| 4920 // Index becomes Index=Const*Var && log2(Const)+Shift<=3 ==> | 4961 // Index becomes Index=Const*Var && log2(Const)+Shift<=3 ==> |
| 4921 // Index=Var, Shift+=log2(Const) | 4962 // Index=Var, Shift+=log2(Const) |
| 4922 if (matchShiftedIndex(VMetadata, Index, Shift, Reason)) | 4963 if ((Reason = |
| 4964 AddrOpt.matchShiftedIndex(&NewAddr.Index, &NewAddr.Shift))) { |
| 4923 continue; | 4965 continue; |
| 4966 } |
| 4967 |
| 4924 // If Shift is zero, the choice of Base and Index was purely arbitrary. | 4968 // If Shift is zero, the choice of Base and Index was purely arbitrary. |
| 4925 // Recognize multiply/shift and set Shift amount. | 4969 // Recognize multiply/shift and set Shift amount. |
| 4926 // Shift==0 && Base is Base=Var*Const && log2(Const)+Shift<=3 ==> | 4970 // Shift==0 && Base is Base=Var*Const && log2(Const)+Shift<=3 ==> |
| 4927 // swap(Index,Base) | 4971 // swap(Index,Base) |
| 4928 // Similar for Base=Const*Var and Base=Var<<Const | 4972 // Similar for Base=Const*Var and Base=Var<<Const |
| 4929 if (Shift == 0 && matchShiftedIndex(VMetadata, Base, Shift, Reason)) { | 4973 if (NewAddr.Shift == 0 && |
| 4930 std::swap(Base, Index); | 4974 (Reason = AddrOpt.matchShiftedIndex(&NewAddr.Base, &NewAddr.Shift))) { |
| 4975 std::swap(NewAddr.Base, NewAddr.Index); |
| 4931 continue; | 4976 continue; |
| 4932 } | 4977 } |
| 4933 } | 4978 } |
| 4979 |
| 4934 // Update Offset to reflect additions/subtractions with constants and | 4980 // Update Offset to reflect additions/subtractions with constants and |
| 4935 // relocatables. | 4981 // relocatables. |
| 4936 // TODO: consider overflow issues with respect to Offset. | 4982 // TODO: consider overflow issues with respect to Offset. |
| 4937 if (matchOffsetBase(VMetadata, GotVar, Base, Index, Relocatable, Offset, | 4983 if (!Skip.OffsetFromBase && |
| 4938 Reason)) | 4984 (Reason = AddrOpt.matchOffsetBase(&NewAddr.Base, &NewAddr.Relocatable, |
| 4985 &NewAddr.Offset))) { |
| 4986 SkipLastFolding = &Skip.OffsetFromBase; |
| 4939 continue; | 4987 continue; |
| 4940 if (Shift == 0 && matchOffsetBase(VMetadata, GotVar, Index, Base, | 4988 } |
| 4941 Relocatable, Offset, Reason)) | 4989 if (NewAddr.Shift == 0 && !Skip.OffsetFromIndex && |
| 4990 (Reason = AddrOpt.matchOffsetBase(&NewAddr.Index, &NewAddr.Relocatable, |
| 4991 &NewAddr.Offset))) { |
| 4992 SkipLastFolding = &Skip.OffsetFromIndex; |
| 4942 continue; | 4993 continue; |
| 4994 } |
| 4995 |
| 4943 // TODO(sehr, stichnot): Handle updates of Index with Shift != 0. | 4996 // TODO(sehr, stichnot): Handle updates of Index with Shift != 0. |
| 4944 // Index is Index=Var+Const ==> | 4997 // Index is Index=Var+Const ==> |
| 4945 // set Index=Var, Offset+=(Const<<Shift) | 4998 // set Index=Var, Offset+=(Const<<Shift) |
| 4946 // Index is Index=Const+Var ==> | 4999 // Index is Index=Const+Var ==> |
| 4947 // set Index=Var, Offset+=(Const<<Shift) | 5000 // set Index=Var, Offset+=(Const<<Shift) |
| 4948 // Index is Index=Var-Const ==> | 5001 // Index is Index=Var-Const ==> |
| 4949 // set Index=Var, Offset-=(Const<<Shift) | 5002 // set Index=Var, Offset-=(Const<<Shift) |
| 4950 break; | 5003 break; |
| 4951 } while (Reason); | 5004 } while (Reason); |
| 4952 // Undo any addition of GotVar. It will be added back when the mem operand is | 5005 |
| 4953 // legalized. | 5006 if (!AddressWasOptimized) { |
| 4954 if (Base == GotVar) | 5007 return nullptr; |
| 4955 Base = nullptr; | 5008 } |
| 4956 if (Index == GotVar) | 5009 |
| 4957 Index = nullptr; | 5010 // Undo any addition of SandboxPtr. It will be added back when the mem |
| 4958 return AddressWasOptimized; | 5011 // operand is sandboxed. |
| 5012 if (NewAddr.Base == SandboxPtr) { |
| 5013 NewAddr.Base = nullptr; |
| 5014 } |
| 5015 |
| 5016 if (NewAddr.Index == SandboxPtr) { |
| 5017 NewAddr.Index = nullptr; |
| 5018 NewAddr.Shift = 0; |
| 5019 } |
| 5020 |
| 5021 Constant *OffsetOp = nullptr; |
| 5022 if (NewAddr.Relocatable == nullptr) { |
| 5023 OffsetOp = Ctx->getConstantInt32(NewAddr.Offset); |
| 5024 } else { |
| 5025 OffsetOp = |
| 5026 Ctx->getConstantSym(NewAddr.Relocatable->getOffset() + NewAddr.Offset, |
| 5027 NewAddr.Relocatable->getName(), |
| 5028 NewAddr.Relocatable->getSuppressMangling()); |
| 5029 } |
| 5030 // Vanilla ICE load instructions should not use the segment registers, and |
| 5031 // computeAddressOpt only works at the level of Variables and Constants, not |
| 5032 // other X86OperandMem, so there should be no mention of segment |
| 5033 // registers there either. |
| 5034 static constexpr auto SegmentReg = |
| 5035 X86OperandMem::SegmentRegisters::DefaultSegment; |
| 5036 |
| 5037 return X86OperandMem::create(Func, MemType, NewAddr.Base, OffsetOp, |
| 5038 NewAddr.Index, NewAddr.Shift, SegmentReg); |
| 4959 } | 5039 } |
| 4960 | 5040 |
| 4961 /// Add a mock bounds check on the memory address before using it as a load or | 5041 /// Add a mock bounds check on the memory address before using it as a load or |
| 4962 /// store operand. The basic idea is that given a memory operand [reg], we | 5042 /// store operand. The basic idea is that given a memory operand [reg], we |
| 4963 /// would first add bounds-check code something like: | 5043 /// would first add bounds-check code something like: |
| 4964 /// | 5044 /// |
| 4965 /// cmp reg, <lb> | 5045 /// cmp reg, <lb> |
| 4966 /// jl out_of_line_error | 5046 /// jl out_of_line_error |
| 4967 /// cmp reg, <ub> | 5047 /// cmp reg, <ub> |
| 4968 /// jg out_of_line_error | 5048 /// jg out_of_line_error |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5026 Type Ty = DestLoad->getType(); | 5106 Type Ty = DestLoad->getType(); |
| 5027 Operand *Src0 = formMemoryOperand(Load->getSourceAddress(), Ty); | 5107 Operand *Src0 = formMemoryOperand(Load->getSourceAddress(), Ty); |
| 5028 doMockBoundsCheck(Src0); | 5108 doMockBoundsCheck(Src0); |
| 5029 auto *Assign = InstAssign::create(Func, DestLoad, Src0); | 5109 auto *Assign = InstAssign::create(Func, DestLoad, Src0); |
| 5030 lowerAssign(Assign); | 5110 lowerAssign(Assign); |
| 5031 } | 5111 } |
| 5032 | 5112 |
| 5033 template <typename TraitsType> | 5113 template <typename TraitsType> |
| 5034 void TargetX86Base<TraitsType>::doAddressOptLoad() { | 5114 void TargetX86Base<TraitsType>::doAddressOptLoad() { |
| 5035 Inst *Inst = Context.getCur(); | 5115 Inst *Inst = Context.getCur(); |
| 5116 Operand *Addr = Inst->getSrc(0); |
| 5036 Variable *Dest = Inst->getDest(); | 5117 Variable *Dest = Inst->getDest(); |
| 5037 Operand *Addr = Inst->getSrc(0); | 5118 if (auto *OptAddr = computeAddressOpt(Inst, Dest->getType(), Addr)) { |
| 5038 Variable *Index = nullptr; | |
| 5039 ConstantRelocatable *Relocatable = nullptr; | |
| 5040 uint16_t Shift = 0; | |
| 5041 int32_t Offset = 0; | |
| 5042 // Vanilla ICE load instructions should not use the segment registers, and | |
| 5043 // computeAddressOpt only works at the level of Variables and Constants, not | |
| 5044 // other X86OperandMem, so there should be no mention of segment | |
| 5045 // registers there either. | |
| 5046 constexpr auto SegmentReg = X86OperandMem::SegmentRegisters::DefaultSegment; | |
| 5047 auto *Base = llvm::dyn_cast<Variable>(Addr); | |
| 5048 const bool ReserveSlot = Traits::Is64Bit && NeedSandboxing; | |
| 5049 if (computeAddressOpt(Func, Inst, GotVar, ReserveSlot, Relocatable, Offset, | |
| 5050 Base, Index, Shift)) { | |
| 5051 Inst->setDeleted(); | 5119 Inst->setDeleted(); |
| 5052 Constant *OffsetOp = nullptr; | 5120 Context.insert<InstLoad>(Dest, OptAddr); |
| 5053 if (Relocatable == nullptr) { | |
| 5054 OffsetOp = Ctx->getConstantInt32(Offset); | |
| 5055 } else { | |
| 5056 OffsetOp = Ctx->getConstantSym(Relocatable->getOffset() + Offset, | |
| 5057 Relocatable->getName(), | |
| 5058 Relocatable->getSuppressMangling()); | |
| 5059 } | |
| 5060 // The new mem operand is created without IsRebased being set, because | |
| 5061 // computeAddressOpt() doesn't include GotVar in its final result. | |
| 5062 Addr = X86OperandMem::create(Func, Dest->getType(), Base, OffsetOp, Index, | |
| 5063 Shift, SegmentReg); | |
| 5064 Context.insert<InstLoad>(Dest, Addr); | |
| 5065 } | 5121 } |
| 5066 } | 5122 } |
| 5067 | 5123 |
| 5068 template <typename TraitsType> | 5124 template <typename TraitsType> |
| 5069 void TargetX86Base<TraitsType>::randomlyInsertNop(float Probability, | 5125 void TargetX86Base<TraitsType>::randomlyInsertNop(float Probability, |
| 5070 RandomNumberGenerator &RNG) { | 5126 RandomNumberGenerator &RNG) { |
| 5071 RandomNumberGeneratorWrapper RNGW(RNG); | 5127 RandomNumberGeneratorWrapper RNGW(RNG); |
| 5072 if (RNGW.getTrueWithProbability(Probability)) { | 5128 if (RNGW.getTrueWithProbability(Probability)) { |
| 5073 _nop(RNGW(Traits::X86_NUM_NOP_VARIANTS)); | 5129 _nop(RNGW(Traits::X86_NUM_NOP_VARIANTS)); |
| 5074 } | 5130 } |
| (...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5351 _storep(legalizeToReg(Value), NewAddr); | 5407 _storep(legalizeToReg(Value), NewAddr); |
| 5352 } else { | 5408 } else { |
| 5353 Value = legalize(Value, Legal_Reg | Legal_Imm); | 5409 Value = legalize(Value, Legal_Reg | Legal_Imm); |
| 5354 _store(Value, NewAddr); | 5410 _store(Value, NewAddr); |
| 5355 } | 5411 } |
| 5356 } | 5412 } |
| 5357 | 5413 |
| 5358 template <typename TraitsType> | 5414 template <typename TraitsType> |
| 5359 void TargetX86Base<TraitsType>::doAddressOptStore() { | 5415 void TargetX86Base<TraitsType>::doAddressOptStore() { |
| 5360 auto *Inst = llvm::cast<InstStore>(Context.getCur()); | 5416 auto *Inst = llvm::cast<InstStore>(Context.getCur()); |
| 5417 Operand *Addr = Inst->getAddr(); |
| 5361 Operand *Data = Inst->getData(); | 5418 Operand *Data = Inst->getData(); |
| 5362 Operand *Addr = Inst->getAddr(); | 5419 if (auto *OptAddr = computeAddressOpt(Inst, Data->getType(), Addr)) { |
| 5363 Variable *Index = nullptr; | |
| 5364 ConstantRelocatable *Relocatable = nullptr; | |
| 5365 uint16_t Shift = 0; | |
| 5366 int32_t Offset = 0; | |
| 5367 auto *Base = llvm::dyn_cast<Variable>(Addr); | |
| 5368 // Vanilla ICE store instructions should not use the segment registers, and | |
| 5369 // computeAddressOpt only works at the level of Variables and Constants, not | |
| 5370 // other X86OperandMem, so there should be no mention of segment | |
| 5371 // registers there either. | |
| 5372 constexpr auto SegmentReg = X86OperandMem::SegmentRegisters::DefaultSegment; | |
| 5373 const bool ReserveSlot = Traits::Is64Bit && NeedSandboxing; | |
| 5374 if (computeAddressOpt(Func, Inst, GotVar, ReserveSlot, Relocatable, Offset, | |
| 5375 Base, Index, Shift)) { | |
| 5376 Inst->setDeleted(); | 5420 Inst->setDeleted(); |
| 5377 Constant *OffsetOp = nullptr; | 5421 auto *NewStore = Context.insert<InstStore>(Data, OptAddr); |
| 5378 if (Relocatable == nullptr) { | |
| 5379 OffsetOp = Ctx->getConstantInt32(Offset); | |
| 5380 } else { | |
| 5381 OffsetOp = Ctx->getConstantSym(Relocatable->getOffset() + Offset, | |
| 5382 Relocatable->getName(), | |
| 5383 Relocatable->getSuppressMangling()); | |
| 5384 } | |
| 5385 // The new mem operand is created without IsRebased being set, because | |
| 5386 // computeAddressOpt() doesn't include GotVar in its final result. | |
| 5387 Addr = X86OperandMem::create(Func, Data->getType(), Base, OffsetOp, Index, | |
| 5388 Shift, SegmentReg); | |
| 5389 auto *NewStore = Context.insert<InstStore>(Data, Addr); | |
| 5390 if (Inst->getDest()) | 5422 if (Inst->getDest()) |
| 5391 NewStore->setRmwBeacon(Inst->getRmwBeacon()); | 5423 NewStore->setRmwBeacon(Inst->getRmwBeacon()); |
| 5392 } | 5424 } |
| 5393 } | 5425 } |
| 5394 | 5426 |
| 5395 template <typename TraitsType> | 5427 template <typename TraitsType> |
| 5396 Operand *TargetX86Base<TraitsType>::lowerCmpRange(Operand *Comparison, | 5428 Operand *TargetX86Base<TraitsType>::lowerCmpRange(Operand *Comparison, |
| 5397 uint64_t Min, uint64_t Max) { | 5429 uint64_t Min, uint64_t Max) { |
| 5398 // TODO(ascull): 64-bit should not reach here but only because it is not | 5430 // TODO(ascull): 64-bit should not reach here but only because it is not |
| 5399 // implemented yet. This should be able to handle the 64-bit case. | 5431 // implemented yet. This should be able to handle the 64-bit case. |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5439 const Type PointerType = getPointerType(); | 5471 const Type PointerType = getPointerType(); |
| 5440 if (RangeIndex->getType() != PointerType) { | 5472 if (RangeIndex->getType() != PointerType) { |
| 5441 Index = makeReg(PointerType); | 5473 Index = makeReg(PointerType); |
| 5442 _movzx(Index, RangeIndex); | 5474 _movzx(Index, RangeIndex); |
| 5443 } else { | 5475 } else { |
| 5444 Index = legalizeToReg(RangeIndex); | 5476 Index = legalizeToReg(RangeIndex); |
| 5445 } | 5477 } |
| 5446 | 5478 |
| 5447 constexpr RelocOffsetT RelocOffset = 0; | 5479 constexpr RelocOffsetT RelocOffset = 0; |
| 5448 constexpr bool SuppressMangling = true; | 5480 constexpr bool SuppressMangling = true; |
| 5449 const bool IsRebased = Ctx->getFlags().getUseNonsfi(); | |
| 5450 IceString MangledName = Ctx->mangleName(Func->getFunctionName()); | 5481 IceString MangledName = Ctx->mangleName(Func->getFunctionName()); |
| 5451 Variable *Base = IsRebased ? legalizeToReg(GotVar) : nullptr; | 5482 constexpr Variable *NoBase = nullptr; |
| 5452 Constant *Offset = Ctx->getConstantSym( | 5483 Constant *Offset = Ctx->getConstantSym( |
| 5453 RelocOffset, InstJumpTable::makeName(MangledName, JumpTable->getId()), | 5484 RelocOffset, InstJumpTable::makeName(MangledName, JumpTable->getId()), |
| 5454 SuppressMangling); | 5485 SuppressMangling); |
| 5455 uint16_t Shift = typeWidthInBytesLog2(PointerType); | 5486 uint16_t Shift = typeWidthInBytesLog2(PointerType); |
| 5456 constexpr auto Segment = X86OperandMem::SegmentRegisters::DefaultSegment; | 5487 constexpr auto Segment = X86OperandMem::SegmentRegisters::DefaultSegment; |
| 5457 | 5488 |
| 5458 Variable *Target = nullptr; | 5489 Variable *Target = nullptr; |
| 5459 if (Traits::Is64Bit && NeedSandboxing) { | 5490 if (Traits::Is64Bit && NeedSandboxing) { |
| 5460 assert(Base == nullptr); | |
| 5461 assert(Index != nullptr && Index->getType() == IceType_i32); | 5491 assert(Index != nullptr && Index->getType() == IceType_i32); |
| 5462 } | 5492 } |
| 5463 auto *TargetInMemory = X86OperandMem::create( | 5493 auto *TargetInMemory = X86OperandMem::create(Func, PointerType, NoBase, |
| 5464 Func, PointerType, Base, Offset, Index, Shift, Segment, IsRebased); | 5494 Offset, Index, Shift, Segment); |
| 5465 _mov(Target, TargetInMemory); | 5495 _mov(Target, TargetInMemory); |
| 5466 | 5496 |
| 5467 lowerIndirectJump(Target); | 5497 lowerIndirectJump(Target); |
| 5468 | 5498 |
| 5469 if (DefaultTarget == nullptr) | 5499 if (DefaultTarget == nullptr) |
| 5470 Context.insert(SkipJumpTable); | 5500 Context.insert(SkipJumpTable); |
| 5471 return; | 5501 return; |
| 5472 } | 5502 } |
| 5473 case CaseCluster::Range: { | 5503 case CaseCluster::Range: { |
| 5474 if (Case.isUnitRange()) { | 5504 if (Case.isUnitRange()) { |
| (...skipping 306 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5781 if (const auto *RMW = llvm::dyn_cast<InstX86FakeRMW>(Instr)) { | 5811 if (const auto *RMW = llvm::dyn_cast<InstX86FakeRMW>(Instr)) { |
| 5782 lowerRMW(RMW); | 5812 lowerRMW(RMW); |
| 5783 } else { | 5813 } else { |
| 5784 TargetLowering::lowerOther(Instr); | 5814 TargetLowering::lowerOther(Instr); |
| 5785 } | 5815 } |
| 5786 } | 5816 } |
| 5787 | 5817 |
| 5788 /// Turn an i64 Phi instruction into a pair of i32 Phi instructions, to preserve | 5818 /// Turn an i64 Phi instruction into a pair of i32 Phi instructions, to preserve |
| 5789 /// integrity of liveness analysis. Undef values are also turned into zeroes, | 5819 /// integrity of liveness analysis. Undef values are also turned into zeroes, |
| 5790 /// since loOperand() and hiOperand() don't expect Undef input. Also, in | 5820 /// since loOperand() and hiOperand() don't expect Undef input. Also, in |
| 5791 /// Non-SFI mode, add a FakeUse(GotVar) for every pooled constant operand. | 5821 /// Non-SFI mode, add a FakeUse(SandboxPtr) for every pooled constant operand. |
| 5792 template <typename TraitsType> void TargetX86Base<TraitsType>::prelowerPhis() { | 5822 template <typename TraitsType> void TargetX86Base<TraitsType>::prelowerPhis() { |
| 5793 if (Ctx->getFlags().getUseNonsfi()) { | 5823 if (Ctx->getFlags().getUseNonsfi()) { |
| 5794 assert(GotVar); | 5824 assert(SandboxPtr); |
| 5795 CfgNode *Node = Context.getNode(); | 5825 CfgNode *Node = Context.getNode(); |
| 5796 uint32_t GotVarUseCount = 0; | 5826 uint32_t SandboxPtrUseCount = 0; |
| 5797 for (Inst &I : Node->getPhis()) { | 5827 for (Inst &I : Node->getPhis()) { |
| 5798 auto *Phi = llvm::dyn_cast<InstPhi>(&I); | 5828 auto *Phi = llvm::dyn_cast<InstPhi>(&I); |
| 5799 if (Phi->isDeleted()) | 5829 if (Phi->isDeleted()) |
| 5800 continue; | 5830 continue; |
| 5801 for (SizeT I = 0; I < Phi->getSrcSize(); ++I) { | 5831 for (SizeT I = 0; I < Phi->getSrcSize(); ++I) { |
| 5802 Operand *Src = Phi->getSrc(I); | 5832 Operand *Src = Phi->getSrc(I); |
| 5803 // TODO(stichnot): This over-counts for +0.0, and under-counts for other | 5833 // TODO(stichnot): This over-counts for +0.0, and under-counts for other |
| 5804 // kinds of pooling. | 5834 // kinds of pooling. |
| 5805 if (llvm::isa<ConstantRelocatable>(Src) || | 5835 if (llvm::isa<ConstantRelocatable>(Src) || |
| 5806 llvm::isa<ConstantFloat>(Src) || llvm::isa<ConstantDouble>(Src)) { | 5836 llvm::isa<ConstantFloat>(Src) || llvm::isa<ConstantDouble>(Src)) { |
| 5807 ++GotVarUseCount; | 5837 ++SandboxPtrUseCount; |
| 5808 } | 5838 } |
| 5809 } | 5839 } |
| 5810 } | 5840 } |
| 5811 if (GotVarUseCount) { | 5841 if (SandboxPtrUseCount) { |
| 5812 Node->getInsts().push_front(InstFakeUse::create(Func, GotVar)); | 5842 Node->getInsts().push_front(InstFakeUse::create(Func, SandboxPtr)); |
| 5813 } | 5843 } |
| 5814 } | 5844 } |
| 5815 if (Traits::Is64Bit) { | 5845 if (Traits::Is64Bit) { |
| 5816 // On x86-64 we don't need to prelower phis -- the architecture can handle | 5846 // On x86-64 we don't need to prelower phis -- the architecture can handle |
| 5817 // 64-bit integer natively. | 5847 // 64-bit integer natively. |
| 5818 return; | 5848 return; |
| 5819 } | 5849 } |
| 5820 | 5850 |
| 5821 // Pause constant blinding or pooling, blinding or pooling will be done later | 5851 // Pause constant blinding or pooling, blinding or pooling will be done later |
| 5822 // during phi lowering assignments | 5852 // during phi lowering assignments |
| (...skipping 527 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6350 if (Base) { | 6380 if (Base) { |
| 6351 RegBase = llvm::cast<Variable>( | 6381 RegBase = llvm::cast<Variable>( |
| 6352 legalize(Base, Legal_Reg | Legal_Rematerializable)); | 6382 legalize(Base, Legal_Reg | Legal_Rematerializable)); |
| 6353 } | 6383 } |
| 6354 if (Index) { | 6384 if (Index) { |
| 6355 // TODO(jpp): perhaps we should only allow Legal_Reg if | 6385 // TODO(jpp): perhaps we should only allow Legal_Reg if |
| 6356 // Base->isRematerializable. | 6386 // Base->isRematerializable. |
| 6357 RegIndex = llvm::cast<Variable>( | 6387 RegIndex = llvm::cast<Variable>( |
| 6358 legalize(Index, Legal_Reg | Legal_Rematerializable)); | 6388 legalize(Index, Legal_Reg | Legal_Rematerializable)); |
| 6359 } | 6389 } |
| 6360 // For Non-SFI mode, if the Offset field is a ConstantRelocatable, we | 6390 |
| 6361 // replace either Base or Index with a legalized GotVar. At emission time, | |
| 6362 // the ConstantRelocatable will be emitted with the @GOTOFF relocation. | |
| 6363 bool IsRebased = false; | |
| 6364 if (UseNonsfi && !Mem->getIsRebased() && Offset && | |
| 6365 llvm::isa<ConstantRelocatable>(Offset)) { | |
| 6366 assert(!(Allowed & Legal_AddrAbs)); | |
| 6367 IsRebased = true; | |
| 6368 if (RegBase == nullptr) { | |
| 6369 RegBase = legalizeToReg(GotVar); | |
| 6370 } else if (RegIndex == nullptr) { | |
| 6371 RegIndex = legalizeToReg(GotVar); | |
| 6372 } else { | |
| 6373 llvm::report_fatal_error( | |
| 6374 "Either Base or Index must be unused in Non-SFI mode"); | |
| 6375 } | |
| 6376 } | |
| 6377 if (Base != RegBase || Index != RegIndex) { | 6391 if (Base != RegBase || Index != RegIndex) { |
| 6378 Mem = X86OperandMem::create(Func, Ty, RegBase, Offset, RegIndex, Shift, | 6392 Mem = X86OperandMem::create(Func, Ty, RegBase, Offset, RegIndex, Shift, |
| 6379 Mem->getSegmentRegister(), IsRebased); | 6393 Mem->getSegmentRegister()); |
| 6380 } | 6394 } |
| 6381 | 6395 |
| 6382 // For all Memory Operands, we do randomization/pooling here | 6396 // For all Memory Operands, we do randomization/pooling here. |
| 6383 From = randomizeOrPoolImmediate(Mem); | 6397 From = randomizeOrPoolImmediate(Mem); |
| 6384 | 6398 |
| 6385 if (!(Allowed & Legal_Mem)) { | 6399 if (!(Allowed & Legal_Mem)) { |
| 6386 From = copyToReg(From, RegNum); | 6400 From = copyToReg(From, RegNum); |
| 6387 } | 6401 } |
| 6388 return From; | 6402 return From; |
| 6389 } | 6403 } |
| 6390 | 6404 |
| 6391 if (auto *Const = llvm::dyn_cast<Constant>(From)) { | 6405 if (auto *Const = llvm::dyn_cast<Constant>(From)) { |
| 6392 if (llvm::isa<ConstantUndef>(Const)) { | 6406 if (llvm::isa<ConstantUndef>(Const)) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 6411 | 6425 |
| 6412 // If the operand is an 32 bit constant integer, we should check whether we | 6426 // If the operand is an 32 bit constant integer, we should check whether we |
| 6413 // need to randomize it or pool it. | 6427 // need to randomize it or pool it. |
| 6414 if (auto *C = llvm::dyn_cast<ConstantInteger32>(Const)) { | 6428 if (auto *C = llvm::dyn_cast<ConstantInteger32>(Const)) { |
| 6415 Operand *NewConst = randomizeOrPoolImmediate(C, RegNum); | 6429 Operand *NewConst = randomizeOrPoolImmediate(C, RegNum); |
| 6416 if (NewConst != Const) { | 6430 if (NewConst != Const) { |
| 6417 return NewConst; | 6431 return NewConst; |
| 6418 } | 6432 } |
| 6419 } | 6433 } |
| 6420 | 6434 |
| 6421 // If the operand is a ConstantRelocatable, and Legal_AddrAbs is not | |
| 6422 // specified, and UseNonsfi is indicated, we need to add GotVar. | |
| 6423 if (auto *CR = llvm::dyn_cast<ConstantRelocatable>(Const)) { | 6435 if (auto *CR = llvm::dyn_cast<ConstantRelocatable>(Const)) { |
| 6436 // If the operand is a ConstantRelocatable, and Legal_AddrAbs is not |
| 6437 // specified, and UseNonsfi is indicated, we need to add SandboxPtr. |
| 6424 if (UseNonsfi && !(Allowed & Legal_AddrAbs)) { | 6438 if (UseNonsfi && !(Allowed & Legal_AddrAbs)) { |
| 6425 assert(Ty == IceType_i32); | 6439 assert(Ty == IceType_i32); |
| 6426 Variable *RegBase = legalizeToReg(GotVar); | |
| 6427 Variable *NewVar = makeReg(Ty, RegNum); | 6440 Variable *NewVar = makeReg(Ty, RegNum); |
| 6428 static constexpr bool IsRebased = true; | 6441 auto *Mem = Traits::X86OperandMem::create(Func, Ty, nullptr, CR); |
| 6429 auto *Mem = | 6442 // LEAs are not automatically sandboxed, thus we explicitly invoke |
| 6430 Traits::X86OperandMem::create(Func, Ty, RegBase, CR, IsRebased); | 6443 // _sandbox_mem_reference. |
| 6431 _lea(NewVar, Mem); | 6444 _lea(NewVar, _sandbox_mem_reference(Mem)); |
| 6432 From = NewVar; | 6445 From = NewVar; |
| 6433 } | 6446 } |
| 6434 } | 6447 } else if (isScalarFloatingType(Ty)) { |
| 6435 | 6448 // Convert a scalar floating point constant into an explicit memory |
| 6436 // Convert a scalar floating point constant into an explicit memory | 6449 // operand. |
| 6437 // operand. | |
| 6438 if (isScalarFloatingType(Ty)) { | |
| 6439 if (auto *ConstFloat = llvm::dyn_cast<ConstantFloat>(Const)) { | 6450 if (auto *ConstFloat = llvm::dyn_cast<ConstantFloat>(Const)) { |
| 6440 if (Utils::isPositiveZero(ConstFloat->getValue())) | 6451 if (Utils::isPositiveZero(ConstFloat->getValue())) |
| 6441 return makeZeroedRegister(Ty, RegNum); | 6452 return makeZeroedRegister(Ty, RegNum); |
| 6442 } else if (auto *ConstDouble = llvm::dyn_cast<ConstantDouble>(Const)) { | 6453 } else if (auto *ConstDouble = llvm::dyn_cast<ConstantDouble>(Const)) { |
| 6443 if (Utils::isPositiveZero(ConstDouble->getValue())) | 6454 if (Utils::isPositiveZero(ConstDouble->getValue())) |
| 6444 return makeZeroedRegister(Ty, RegNum); | 6455 return makeZeroedRegister(Ty, RegNum); |
| 6445 } | 6456 } |
| 6446 Variable *Base = UseNonsfi ? legalizeToReg(GotVar) : nullptr; | 6457 |
| 6447 std::string Buffer; | 6458 std::string Buffer; |
| 6448 llvm::raw_string_ostream StrBuf(Buffer); | 6459 llvm::raw_string_ostream StrBuf(Buffer); |
| 6449 llvm::cast<Constant>(From)->emitPoolLabel(StrBuf, Ctx); | 6460 llvm::cast<Constant>(From)->emitPoolLabel(StrBuf, Ctx); |
| 6450 llvm::cast<Constant>(From)->setShouldBePooled(true); | 6461 llvm::cast<Constant>(From)->setShouldBePooled(true); |
| 6451 Constant *Offset = Ctx->getConstantSym(0, StrBuf.str(), true); | 6462 Constant *Offset = Ctx->getConstantSym(0, StrBuf.str(), true); |
| 6452 const bool IsRebased = Base != nullptr; | 6463 auto *Mem = X86OperandMem::create(Func, Ty, nullptr, Offset); |
| 6453 auto *Mem = X86OperandMem::create(Func, Ty, Base, Offset, IsRebased); | |
| 6454 From = Mem; | 6464 From = Mem; |
| 6455 } | 6465 } |
| 6466 |
| 6456 bool NeedsReg = false; | 6467 bool NeedsReg = false; |
| 6457 if (!(Allowed & Legal_Imm) && !isScalarFloatingType(Ty)) | 6468 if (!(Allowed & Legal_Imm) && !isScalarFloatingType(Ty)) |
| 6458 // Immediate specifically not allowed | 6469 // Immediate specifically not allowed. |
| 6459 NeedsReg = true; | 6470 NeedsReg = true; |
| 6460 if (!(Allowed & Legal_Mem) && isScalarFloatingType(Ty)) | 6471 if (!(Allowed & Legal_Mem) && isScalarFloatingType(Ty)) |
| 6461 // On x86, FP constants are lowered to mem operands. | 6472 // On x86, FP constants are lowered to mem operands. |
| 6462 NeedsReg = true; | 6473 NeedsReg = true; |
| 6463 if (NeedsReg) { | 6474 if (NeedsReg) { |
| 6464 From = copyToReg(From, RegNum); | 6475 From = copyToReg(From, RegNum); |
| 6465 } | 6476 } |
| 6466 return From; | 6477 return From; |
| 6467 } | 6478 } |
| 6468 | 6479 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 6481 if (MustRematerialize) { | 6492 if (MustRematerialize) { |
| 6482 assert(Ty == IceType_i32); | 6493 assert(Ty == IceType_i32); |
| 6483 Variable *NewVar = makeReg(Ty, RegNum); | 6494 Variable *NewVar = makeReg(Ty, RegNum); |
| 6484 // Since Var is rematerializable, the offset will be added when the lea is | 6495 // Since Var is rematerializable, the offset will be added when the lea is |
| 6485 // emitted. | 6496 // emitted. |
| 6486 constexpr Constant *NoOffset = nullptr; | 6497 constexpr Constant *NoOffset = nullptr; |
| 6487 auto *Mem = X86OperandMem::create(Func, Ty, Var, NoOffset); | 6498 auto *Mem = X86OperandMem::create(Func, Ty, Var, NoOffset); |
| 6488 _lea(NewVar, Mem); | 6499 _lea(NewVar, Mem); |
| 6489 From = NewVar; | 6500 From = NewVar; |
| 6490 } else if ((!(Allowed & Legal_Mem) && !MustHaveRegister) || | 6501 } else if ((!(Allowed & Legal_Mem) && !MustHaveRegister) || |
| 6491 (RegNum != Variable::NoRegister && RegNum != Var->getRegNum()) || | 6502 (RegNum != Variable::NoRegister && RegNum != Var->getRegNum())) { |
| 6492 MustRematerialize) { | |
| 6493 From = copyToReg(From, RegNum); | 6503 From = copyToReg(From, RegNum); |
| 6494 } | 6504 } |
| 6495 return From; | 6505 return From; |
| 6496 } | 6506 } |
| 6497 | 6507 |
| 6498 llvm::report_fatal_error("Unhandled operand kind in legalize()"); | 6508 llvm::report_fatal_error("Unhandled operand kind in legalize()"); |
| 6499 return From; | 6509 return From; |
| 6500 } | 6510 } |
| 6501 | 6511 |
| 6502 /// Provide a trivial wrapper to legalize() for this common usage. | 6512 /// Provide a trivial wrapper to legalize() for this common usage. |
| (...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6762 // assigned register as this assignment is that start of its use-def | 6772 // assigned register as this assignment is that start of its use-def |
| 6763 // chain. So we add RegNum argument here. | 6773 // chain. So we add RegNum argument here. |
| 6764 Variable *Reg = makeReg(Immediate->getType(), RegNum); | 6774 Variable *Reg = makeReg(Immediate->getType(), RegNum); |
| 6765 IceString Label; | 6775 IceString Label; |
| 6766 llvm::raw_string_ostream Label_stream(Label); | 6776 llvm::raw_string_ostream Label_stream(Label); |
| 6767 Immediate->emitPoolLabel(Label_stream, Ctx); | 6777 Immediate->emitPoolLabel(Label_stream, Ctx); |
| 6768 constexpr RelocOffsetT Offset = 0; | 6778 constexpr RelocOffsetT Offset = 0; |
| 6769 constexpr bool SuppressMangling = true; | 6779 constexpr bool SuppressMangling = true; |
| 6770 Constant *Symbol = | 6780 Constant *Symbol = |
| 6771 Ctx->getConstantSym(Offset, Label_stream.str(), SuppressMangling); | 6781 Ctx->getConstantSym(Offset, Label_stream.str(), SuppressMangling); |
| 6772 const bool UseNonsfi = Ctx->getFlags().getUseNonsfi(); | 6782 constexpr Variable *NoBase = nullptr; |
| 6773 Variable *Base = UseNonsfi ? legalizeToReg(GotVar) : nullptr; | 6783 X86OperandMem *MemOperand = |
| 6774 const bool IsRebased = Base != nullptr; | 6784 X86OperandMem::create(Func, Immediate->getType(), NoBase, Symbol); |
| 6775 X86OperandMem *MemOperand = X86OperandMem::create( | |
| 6776 Func, Immediate->getType(), Base, Symbol, IsRebased); | |
| 6777 _mov(Reg, MemOperand); | 6785 _mov(Reg, MemOperand); |
| 6778 return Reg; | 6786 return Reg; |
| 6779 } | 6787 } |
| 6780 } | 6788 } |
| 6781 } | 6789 } |
| 6782 | 6790 |
| 6783 template <typename TraitsType> | 6791 template <typename TraitsType> |
| 6784 typename TargetX86Base<TraitsType>::X86OperandMem * | 6792 typename TargetX86Base<TraitsType>::X86OperandMem * |
| 6785 TargetX86Base<TraitsType>::randomizeOrPoolImmediate(X86OperandMem *MemOperand, | 6793 TargetX86Base<TraitsType>::randomizeOrPoolImmediate(X86OperandMem *MemOperand, |
| 6786 int32_t RegNum) { | 6794 int32_t RegNum) { |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6872 return MemOperand; | 6880 return MemOperand; |
| 6873 Variable *RegTemp = makeReg(IceType_i32); | 6881 Variable *RegTemp = makeReg(IceType_i32); |
| 6874 IceString Label; | 6882 IceString Label; |
| 6875 llvm::raw_string_ostream Label_stream(Label); | 6883 llvm::raw_string_ostream Label_stream(Label); |
| 6876 MemOperand->getOffset()->emitPoolLabel(Label_stream, Ctx); | 6884 MemOperand->getOffset()->emitPoolLabel(Label_stream, Ctx); |
| 6877 MemOperand->getOffset()->setShouldBePooled(true); | 6885 MemOperand->getOffset()->setShouldBePooled(true); |
| 6878 constexpr RelocOffsetT SymOffset = 0; | 6886 constexpr RelocOffsetT SymOffset = 0; |
| 6879 constexpr bool SuppressMangling = true; | 6887 constexpr bool SuppressMangling = true; |
| 6880 Constant *Symbol = | 6888 Constant *Symbol = |
| 6881 Ctx->getConstantSym(SymOffset, Label_stream.str(), SuppressMangling); | 6889 Ctx->getConstantSym(SymOffset, Label_stream.str(), SuppressMangling); |
| 6882 const bool UseNonsfi = Ctx->getFlags().getUseNonsfi(); | 6890 constexpr Variable *NoBase = nullptr; |
| 6883 Variable *Base = UseNonsfi ? legalizeToReg(GotVar) : nullptr; | |
| 6884 const bool IsRebased = Base != nullptr; | |
| 6885 X86OperandMem *SymbolOperand = X86OperandMem::create( | 6891 X86OperandMem *SymbolOperand = X86OperandMem::create( |
| 6886 Func, MemOperand->getOffset()->getType(), Base, Symbol, IsRebased); | 6892 Func, MemOperand->getOffset()->getType(), NoBase, Symbol); |
| 6887 _mov(RegTemp, SymbolOperand); | 6893 _mov(RegTemp, SymbolOperand); |
| 6888 // If we have a base variable here, we should add the lea instruction | 6894 // If we have a base variable here, we should add the lea instruction |
| 6889 // to add the value of the base variable to RegTemp. If there is no | 6895 // to add the value of the base variable to RegTemp. If there is no |
| 6890 // base variable, we won't need this lea instruction. | 6896 // base variable, we won't need this lea instruction. |
| 6891 if (MemOperand->getBase()) { | 6897 if (MemOperand->getBase()) { |
| 6892 X86OperandMem *CalculateOperand = X86OperandMem::create( | 6898 X86OperandMem *CalculateOperand = X86OperandMem::create( |
| 6893 Func, MemOperand->getType(), MemOperand->getBase(), nullptr, RegTemp, | 6899 Func, MemOperand->getType(), MemOperand->getBase(), nullptr, RegTemp, |
| 6894 0, MemOperand->getSegmentRegister()); | 6900 0, MemOperand->getSegmentRegister()); |
| 6895 _lea(RegTemp, CalculateOperand); | 6901 _lea(RegTemp, CalculateOperand); |
| 6896 } | 6902 } |
| 6897 X86OperandMem *NewMemOperand = X86OperandMem::create( | 6903 X86OperandMem *NewMemOperand = X86OperandMem::create( |
| 6898 Func, MemOperand->getType(), RegTemp, nullptr, MemOperand->getIndex(), | 6904 Func, MemOperand->getType(), RegTemp, nullptr, MemOperand->getIndex(), |
| 6899 MemOperand->getShift(), MemOperand->getSegmentRegister()); | 6905 MemOperand->getShift(), MemOperand->getSegmentRegister()); |
| 6900 return NewMemOperand; | 6906 return NewMemOperand; |
| 6901 } | 6907 } |
| 6902 } | 6908 } |
| 6903 } | 6909 } |
| 6904 } // end of namespace X86NAMESPACE | 6910 } // end of namespace X86NAMESPACE |
| 6905 } // end of namespace Ice | 6911 } // end of namespace Ice |
| 6906 | 6912 |
| 6907 #endif // SUBZERO_SRC_ICETARGETLOWERINGX86BASEIMPL_H | 6913 #endif // SUBZERO_SRC_ICETARGETLOWERINGX86BASEIMPL_H |
| OLD | NEW |