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 |