Index: src/IceTargetLoweringX86BaseImpl.h |
diff --git a/src/IceTargetLoweringX86BaseImpl.h b/src/IceTargetLoweringX86BaseImpl.h |
index e70c757f9bb72abafb67984a4675f918f5b3c731..1d2ef6193a89877745ee1802f7f31d6cbad4f15c 100644 |
--- a/src/IceTargetLoweringX86BaseImpl.h |
+++ b/src/IceTargetLoweringX86BaseImpl.h |
@@ -308,7 +308,7 @@ void TargetX86Base<TraitsType>::initNodeForLowering(CfgNode *Node) { |
template <typename TraitsType> |
TargetX86Base<TraitsType>::TargetX86Base(Cfg *Func) |
- : TargetLowering(Func), NeedSandboxing(Ctx->getFlags().getUseSandboxing()) { |
+ : TargetLowering(Func), NeedSandboxing(SandboxingType == ST_NaCl) { |
static_assert( |
(Traits::InstructionSet::End - Traits::InstructionSet::Begin) == |
(TargetInstructionSet::X86InstructionSet_End - |
@@ -338,12 +338,8 @@ void TargetX86Base<TraitsType>::staticInit(GlobalContext *Ctx) { |
template <typename TraitsType> void TargetX86Base<TraitsType>::translateO2() { |
TimerMarker T(TimerStack::TT_O2, Func); |
- if (!Traits::Is64Bit && Func->getContext()->getFlags().getUseNonsfi()) { |
- GotVar = Func->makeVariable(IceType_i32); |
- } |
- |
- if (NeedSandboxing) { |
- initSandbox(); |
+ if (SandboxingType != ST_None) { |
+ initRebasePtr(); |
} |
genTargetHelperCalls(); |
@@ -414,7 +410,9 @@ template <typename TraitsType> void TargetX86Base<TraitsType>::translateO2() { |
Func->genCode(); |
if (Func->hasError()) |
return; |
- initGotVarIfNeeded(); |
+ if (SandboxingType != ST_None) { |
+ initSandbox(); |
+ } |
Func->dump("After x86 codegen"); |
// Register allocation. This requires instruction renumbering and full |
@@ -474,12 +472,8 @@ template <typename TraitsType> void TargetX86Base<TraitsType>::translateO2() { |
template <typename TraitsType> void TargetX86Base<TraitsType>::translateOm1() { |
TimerMarker T(TimerStack::TT_Om1, Func); |
- if (!Traits::Is64Bit && Func->getContext()->getFlags().getUseNonsfi()) { |
- GotVar = Func->makeVariable(IceType_i32); |
- } |
- |
- if (NeedSandboxing) { |
- initSandbox(); |
+ if (SandboxingType != ST_None) { |
+ initRebasePtr(); |
} |
genTargetHelperCalls(); |
@@ -504,7 +498,9 @@ template <typename TraitsType> void TargetX86Base<TraitsType>::translateOm1() { |
Func->genCode(); |
if (Func->hasError()) |
return; |
- initGotVarIfNeeded(); |
+ if (SandboxingType != ST_None) { |
+ initSandbox(); |
+ } |
Func->dump("After initial x8632 codegen"); |
regAlloc(RAK_InfOnly); |
@@ -1329,23 +1325,6 @@ TargetX86Base<TraitsType>::getRegisterSet(RegSetMask Include, |
} |
template <typename TraitsType> |
-void TargetX86Base<TraitsType>::initGotVarIfNeeded() { |
- if (!Func->getContext()->getFlags().getUseNonsfi()) |
- return; |
- if (Traits::Is64Bit) { |
- // Probably no implementation is needed, but error to be safe for now. |
- llvm::report_fatal_error( |
- "Need to implement initGotVarIfNeeded() for 64-bit."); |
- } |
- // Insert the GotVar assignment as the very first lowered instruction. Later, |
- // it will be moved into the right place - after the stack frame is set up but |
- // before in-args are copied into registers. |
- Context.init(Func->getEntryNode()); |
- Context.setInsertPoint(Context.getCur()); |
- Context.insert<typename Traits::Insts::GetIP>(GotVar); |
-} |
- |
-template <typename TraitsType> |
void TargetX86Base<TraitsType>::lowerAlloca(const InstAlloca *Inst) { |
// Conservatively require the stack to be aligned. Some stack adjustment |
// operations implemented below assume that the stack is aligned before the |
@@ -4916,18 +4895,49 @@ void TargetX86Base<TraitsType>::lowerMemset(Operand *Dest, Operand *Val, |
lowerCall(Call); |
} |
-inline bool isAdd(const Inst *Inst) { |
- if (auto *Arith = llvm::dyn_cast_or_null<const InstArithmetic>(Inst)) { |
- return (Arith->getOp() == InstArithmetic::Add); |
+class AddressOptimizer { |
+ AddressOptimizer() = delete; |
+ AddressOptimizer(const AddressOptimizer &) = delete; |
+ AddressOptimizer &operator=(const AddressOptimizer &) = delete; |
+ |
+public: |
+ explicit AddressOptimizer(const Cfg *Func) |
+ : Func(Func), VMetadata(Func->getVMetadata()) {} |
+ |
+ inline void dumpAddressOpt(const ConstantRelocatable *const Relocatable, |
+ int32_t Offset, const Variable *Base, |
+ const Variable *Index, uint16_t Shift, |
+ const Inst *Reason) const; |
+ |
+ inline const Inst *matchAssign(Variable **Var, |
+ ConstantRelocatable **Relocatable, |
+ int32_t *Offset); |
+ |
+ inline const Inst *matchCombinedBaseIndex(Variable **Base, Variable **Index, |
+ uint16_t *Shift); |
+ |
+ inline const Inst *matchShiftedIndex(Variable **Index, uint16_t *Shift); |
+ |
+ inline const Inst *matchOffsetBase(Variable **Base, |
+ ConstantRelocatable **Relocatable, |
+ int32_t *Offset); |
+ |
+private: |
+ const Cfg *const Func; |
+ const VariablesMetadata *const VMetadata; |
+ |
+ static bool isAdd(const Inst *Inst) { |
+ if (auto *Arith = llvm::dyn_cast_or_null<const InstArithmetic>(Inst)) { |
+ return (Arith->getOp() == InstArithmetic::Add); |
+ } |
+ return false; |
} |
- return false; |
-} |
+}; |
-inline void dumpAddressOpt(const Cfg *Func, |
- const ConstantRelocatable *Relocatable, |
- int32_t Offset, const Variable *Base, |
- const Variable *Index, uint16_t Shift, |
- const Inst *Reason) { |
+void AddressOptimizer::dumpAddressOpt( |
+ const ConstantRelocatable *const Relocatable, int32_t Offset, |
+ const Variable *Base, const Variable *Index, uint16_t Shift, |
+ const Inst *Reason) const { |
if (!BuildDefs::dump()) |
return; |
if (!Func->isVerbose(IceV_AddrOpt)) |
@@ -4950,14 +4960,14 @@ inline void dumpAddressOpt(const Cfg *Func, |
<< ", Relocatable=" << Relocatable << "\n"; |
} |
-inline bool matchAssign(const VariablesMetadata *VMetadata, Variable *GotVar, |
- Variable *&Var, ConstantRelocatable *&Relocatable, |
- int32_t &Offset, const Inst *&Reason) { |
+const Inst *AddressOptimizer::matchAssign(Variable **Var, |
+ ConstantRelocatable **Relocatable, |
+ int32_t *Offset) { |
// Var originates from Var=SrcVar ==> set Var:=SrcVar |
- if (Var == nullptr) |
- return false; |
- if (const Inst *VarAssign = VMetadata->getSingleDefinition(Var)) { |
- assert(!VMetadata->isMultiDef(Var)); |
+ if (*Var == nullptr) |
+ return nullptr; |
+ if (const Inst *VarAssign = VMetadata->getSingleDefinition(*Var)) { |
+ assert(!VMetadata->isMultiDef(*Var)); |
if (llvm::isa<InstAssign>(VarAssign)) { |
Operand *SrcOp = VarAssign->getSrc(0); |
assert(SrcOp); |
@@ -4965,88 +4975,86 @@ inline bool matchAssign(const VariablesMetadata *VMetadata, Variable *GotVar, |
if (!VMetadata->isMultiDef(SrcVar) && |
// TODO: ensure SrcVar stays single-BB |
true) { |
- Var = SrcVar; |
- Reason = VarAssign; |
- return true; |
+ *Var = SrcVar; |
+ return VarAssign; |
} |
} else if (auto *Const = llvm::dyn_cast<ConstantInteger32>(SrcOp)) { |
int32_t MoreOffset = Const->getValue(); |
- if (Utils::WouldOverflowAdd(Offset, MoreOffset)) |
- return false; |
- Var = nullptr; |
+ if (Utils::WouldOverflowAdd(*Offset, MoreOffset)) |
+ return nullptr; |
+ *Var = nullptr; |
Offset += MoreOffset; |
- Reason = VarAssign; |
- return true; |
+ return VarAssign; |
} else if (auto *AddReloc = llvm::dyn_cast<ConstantRelocatable>(SrcOp)) { |
- if (Relocatable == nullptr) { |
- Var = GotVar; |
- Relocatable = AddReloc; |
- Reason = VarAssign; |
- return true; |
+ if (*Relocatable == nullptr) { |
+ // It is always safe to fold a relocatable through assignment -- the |
+ // assignment frees a slot in the address operand that can be used to |
+ // hold the Sandbox Pointer -- if any. |
+ *Var = nullptr; |
+ *Relocatable = AddReloc; |
+ return VarAssign; |
} |
} |
} |
} |
- return false; |
+ return nullptr; |
} |
-inline bool matchCombinedBaseIndex(const VariablesMetadata *VMetadata, |
- Variable *&Base, Variable *&Index, |
- uint16_t &Shift, const Inst *&Reason) { |
+const Inst *AddressOptimizer::matchCombinedBaseIndex(Variable **Base, |
+ Variable **Index, |
+ uint16_t *Shift) { |
// Index==nullptr && Base is Base=Var1+Var2 ==> |
// set Base=Var1, Index=Var2, Shift=0 |
- if (Base == nullptr) |
- return false; |
- if (Index != nullptr) |
- return false; |
- auto *BaseInst = VMetadata->getSingleDefinition(Base); |
+ if (*Base == nullptr) |
+ return nullptr; |
+ if (*Index != nullptr) |
+ return nullptr; |
+ auto *BaseInst = VMetadata->getSingleDefinition(*Base); |
if (BaseInst == nullptr) |
- return false; |
- assert(!VMetadata->isMultiDef(Base)); |
+ return nullptr; |
+ assert(!VMetadata->isMultiDef(*Base)); |
if (BaseInst->getSrcSize() < 2) |
- return false; |
+ return nullptr; |
if (auto *Var1 = llvm::dyn_cast<Variable>(BaseInst->getSrc(0))) { |
if (VMetadata->isMultiDef(Var1)) |
- return false; |
+ return nullptr; |
if (auto *Var2 = llvm::dyn_cast<Variable>(BaseInst->getSrc(1))) { |
if (VMetadata->isMultiDef(Var2)) |
- return false; |
+ return nullptr; |
if (isAdd(BaseInst) && |
// TODO: ensure Var1 and Var2 stay single-BB |
true) { |
- Base = Var1; |
- Index = Var2; |
- Shift = 0; // should already have been 0 |
- Reason = BaseInst; |
- return true; |
+ *Base = Var1; |
+ *Index = Var2; |
+ *Shift = 0; // should already have been 0 |
+ return BaseInst; |
} |
} |
} |
- return false; |
+ return nullptr; |
} |
-inline bool matchShiftedIndex(const VariablesMetadata *VMetadata, |
- Variable *&Index, uint16_t &Shift, |
- const Inst *&Reason) { |
+const Inst *AddressOptimizer::matchShiftedIndex(Variable **Index, |
+ uint16_t *Shift) { |
// Index is Index=Var*Const && log2(Const)+Shift<=3 ==> |
// Index=Var, Shift+=log2(Const) |
- if (Index == nullptr) |
- return false; |
- auto *IndexInst = VMetadata->getSingleDefinition(Index); |
+ if (*Index == nullptr) |
+ return nullptr; |
+ auto *IndexInst = VMetadata->getSingleDefinition(*Index); |
if (IndexInst == nullptr) |
- return false; |
- assert(!VMetadata->isMultiDef(Index)); |
+ return nullptr; |
+ assert(!VMetadata->isMultiDef(*Index)); |
if (IndexInst->getSrcSize() < 2) |
- return false; |
+ return nullptr; |
if (auto *ArithInst = llvm::dyn_cast<InstArithmetic>(IndexInst)) { |
if (auto *Var = llvm::dyn_cast<Variable>(ArithInst->getSrc(0))) { |
if (auto *Const = |
llvm::dyn_cast<ConstantInteger32>(ArithInst->getSrc(1))) { |
if (VMetadata->isMultiDef(Var) || Const->getType() != IceType_i32) |
- return false; |
+ return nullptr; |
switch (ArithInst->getOp()) { |
default: |
- return false; |
+ return nullptr; |
case InstArithmetic::Mul: { |
uint32_t Mult = Const->getValue(); |
uint32_t LogMult; |
@@ -5064,13 +5072,12 @@ inline bool matchShiftedIndex(const VariablesMetadata *VMetadata, |
LogMult = 3; |
break; |
default: |
- return false; |
+ return nullptr; |
} |
- if (Shift + LogMult <= 3) { |
- Index = Var; |
- Shift += LogMult; |
- Reason = IndexInst; |
- return true; |
+ if (*Shift + LogMult <= 3) { |
+ *Index = Var; |
+ *Shift += LogMult; |
+ return IndexInst; |
} |
} |
case InstArithmetic::Shl: { |
@@ -5082,43 +5089,40 @@ inline bool matchShiftedIndex(const VariablesMetadata *VMetadata, |
case 3: |
break; |
default: |
- return false; |
+ return nullptr; |
} |
- if (Shift + ShiftAmount <= 3) { |
- Index = Var; |
- Shift += ShiftAmount; |
- Reason = IndexInst; |
- return true; |
+ if (*Shift + ShiftAmount <= 3) { |
+ *Index = Var; |
+ *Shift += ShiftAmount; |
+ return IndexInst; |
} |
} |
} |
} |
} |
} |
- return false; |
+ return nullptr; |
} |
-inline bool matchOffsetBase(const VariablesMetadata *VMetadata, |
- Variable *GotVar, Variable *&Base, |
- Variable *&BaseOther, |
- ConstantRelocatable *&Relocatable, int32_t &Offset, |
- const Inst *&Reason) { |
+const Inst *AddressOptimizer::matchOffsetBase(Variable **Base, |
+ ConstantRelocatable **Relocatable, |
+ int32_t *Offset) { |
// Base is Base=Var+Const || Base is Base=Const+Var ==> |
// set Base=Var, Offset+=Const |
// Base is Base=Var-Const ==> |
// set Base=Var, Offset-=Const |
- if (Base == nullptr) { |
- return false; |
+ if (*Base == nullptr) { |
+ return nullptr; |
} |
- const Inst *BaseInst = VMetadata->getSingleDefinition(Base); |
+ const Inst *BaseInst = VMetadata->getSingleDefinition(*Base); |
if (BaseInst == nullptr) { |
- return false; |
+ return nullptr; |
} |
- assert(!VMetadata->isMultiDef(Base)); |
+ assert(!VMetadata->isMultiDef(*Base)); |
if (auto *ArithInst = llvm::dyn_cast<const InstArithmetic>(BaseInst)) { |
if (ArithInst->getOp() != InstArithmetic::Add && |
ArithInst->getOp() != InstArithmetic::Sub) |
- return false; |
+ return nullptr; |
bool IsAdd = ArithInst->getOp() == InstArithmetic::Add; |
Operand *Src0 = ArithInst->getSrc(0); |
Operand *Src1 = ArithInst->getSrc(1); |
@@ -5129,74 +5133,55 @@ inline bool matchOffsetBase(const VariablesMetadata *VMetadata, |
auto *Reloc0 = llvm::dyn_cast<ConstantRelocatable>(Src0); |
auto *Reloc1 = llvm::dyn_cast<ConstantRelocatable>(Src1); |
Variable *NewBase = nullptr; |
- int32_t NewOffset = Offset; |
- ConstantRelocatable *NewRelocatable = Relocatable; |
+ int32_t NewOffset = *Offset; |
+ ConstantRelocatable *NewRelocatable = *Relocatable; |
if (Var0 && Var1) |
// TODO(sehr): merge base/index splitting into here. |
- return false; |
+ return nullptr; |
if (!IsAdd && Var1) |
- return false; |
+ return nullptr; |
if (Var0) |
NewBase = Var0; |
else if (Var1) |
NewBase = Var1; |
// Don't know how to add/subtract two relocatables. |
- if ((Relocatable && (Reloc0 || Reloc1)) || (Reloc0 && Reloc1)) |
- return false; |
+ if ((*Relocatable && (Reloc0 || Reloc1)) || (Reloc0 && Reloc1)) |
+ return nullptr; |
// Don't know how to subtract a relocatable. |
if (!IsAdd && Reloc1) |
- return false; |
+ return nullptr; |
// Incorporate ConstantRelocatables. |
if (Reloc0) |
NewRelocatable = Reloc0; |
else if (Reloc1) |
NewRelocatable = Reloc1; |
- if ((Reloc0 || Reloc1) && BaseOther && GotVar) |
- return false; |
// Compute the updated constant offset. |
if (Const0) { |
const int32_t MoreOffset = |
IsAdd ? Const0->getValue() : -Const0->getValue(); |
if (Utils::WouldOverflowAdd(NewOffset, MoreOffset)) |
- return false; |
+ return nullptr; |
NewOffset += MoreOffset; |
} |
if (Const1) { |
const int32_t MoreOffset = |
IsAdd ? Const1->getValue() : -Const1->getValue(); |
if (Utils::WouldOverflowAdd(NewOffset, MoreOffset)) |
- return false; |
+ return nullptr; |
NewOffset += MoreOffset; |
} |
- // Update the computed address parameters once we are sure optimization |
- // is valid. |
- if ((Reloc0 || Reloc1) && GotVar) { |
- assert(BaseOther == nullptr); |
- BaseOther = GotVar; |
- } |
- Base = NewBase; |
- Offset = NewOffset; |
- Relocatable = NewRelocatable; |
- Reason = BaseInst; |
- return true; |
+ *Base = NewBase; |
+ *Offset = NewOffset; |
+ *Relocatable = NewRelocatable; |
+ return BaseInst; |
} |
- return false; |
+ return nullptr; |
} |
-// Builds information for a canonical address expresion: |
-// <Relocatable + Offset>(Base, Index, Shift) |
-// On entry: |
-// Relocatable == null, |
-// Offset == 0, |
-// Base is a Variable, |
-// Index == nullptr, |
-// Shift == 0 |
-inline bool computeAddressOpt(Cfg *Func, const Inst *Instr, Variable *GotVar, |
- bool ReserveSlot, |
- ConstantRelocatable *&Relocatable, |
- int32_t &Offset, Variable *&Base, |
- Variable *&Index, uint16_t &Shift) { |
- bool AddressWasOptimized = false; |
+template <typename TypeTraits> |
+typename TargetX86Base<TypeTraits>::X86OperandMem * |
+TargetX86Base<TypeTraits>::computeAddressOpt(const Inst *Instr, Type MemType, |
+ Operand *Addr) { |
Func->resetCurrentNode(); |
if (Func->isVerbose(IceV_AddrOpt)) { |
OstreamLocker L(Func->getContext()); |
@@ -5204,70 +5189,138 @@ inline bool computeAddressOpt(Cfg *Func, const Inst *Instr, Variable *GotVar, |
Str << "\nStarting computeAddressOpt for instruction:\n "; |
Instr->dumpDecorated(Func); |
} |
- if (Base == nullptr) |
- return AddressWasOptimized; |
+ |
+ OptAddr NewAddr; |
+ NewAddr.Base = llvm::dyn_cast<Variable>(Addr); |
+ if (NewAddr.Base == nullptr) |
+ return nullptr; |
+ |
// If the Base has more than one use or is live across multiple blocks, then |
// don't go further. Alternatively (?), never consider a transformation that |
// would change a variable that is currently *not* live across basic block |
// boundaries into one that *is*. |
- if (Func->getVMetadata()->isMultiBlock(Base) /* || Base->getUseCount() > 1*/) |
- return AddressWasOptimized; |
+ if (Func->getVMetadata()->isMultiBlock( |
+ NewAddr.Base) /* || Base->getUseCount() > 1*/) |
+ return nullptr; |
+ AddressOptimizer AddrOpt(Func); |
const bool MockBounds = Func->getContext()->getFlags().getMockBoundsCheck(); |
- const VariablesMetadata *VMetadata = Func->getVMetadata(); |
const Inst *Reason = nullptr; |
+ bool AddressWasOptimized = false; |
+ // The following unnamed struct identifies the address mode formation steps |
+ // that could potentially create an invalid memory operand (i.e., no free |
+ // slots for RebasePtr.) We add all those variables to this struct so that we |
+ // can use memset() to reset all members to false. |
+ struct { |
+ bool AssignBase = false; |
+ bool AssignIndex = false; |
+ bool OffsetFromBase = false; |
+ bool OffsetFromIndex = false; |
+ bool CombinedBaseIndex = false; |
+ } Skip; |
+ // This points to the boolean in Skip that represents the last folding |
+ // performed. This is used to disable a pattern match that generated an |
+ // invalid address. Without this, the algorithm would never finish. |
+ bool *SkipLastFolding = nullptr; |
+ // NewAddrCheckpoint is used to rollback the address being formed in case an |
+ // invalid address is formed. |
+ OptAddr NewAddrCheckpoint; |
+ Reason = Instr; |
do { |
- assert(!ReserveSlot || Base == nullptr || Index == nullptr); |
+ if (SandboxingType != ST_None) { |
+ // When sandboxing, we defer the sandboxing of NewAddr to the Concrete |
+ // Target. If our optimization was overly aggressive, then we simply undo |
+ // what the previous iteration did, and set the previous pattern's skip |
+ // bit to true. |
+ if (!legalizeOptAddrForSandbox(&NewAddr)) { |
+ *SkipLastFolding = true; |
+ SkipLastFolding = nullptr; |
+ NewAddr = NewAddrCheckpoint; |
+ Reason = nullptr; |
+ } |
+ } |
+ |
if (Reason) { |
- dumpAddressOpt(Func, Relocatable, Offset, Base, Index, Shift, Reason); |
+ AddrOpt.dumpAddressOpt(NewAddr.Relocatable, NewAddr.Offset, NewAddr.Base, |
+ NewAddr.Index, NewAddr.Shift, Reason); |
AddressWasOptimized = true; |
Reason = nullptr; |
+ SkipLastFolding = nullptr; |
+ memset(&Skip, 0, sizeof(Skip)); |
} |
+ |
+ NewAddrCheckpoint = NewAddr; |
+ |
// Update Base and Index to follow through assignments to definitions. |
- if (matchAssign(VMetadata, GotVar, Base, Relocatable, Offset, Reason)) { |
+ if (!Skip.AssignBase && |
+ (Reason = AddrOpt.matchAssign(&NewAddr.Base, &NewAddr.Relocatable, |
+ &NewAddr.Offset))) { |
+ SkipLastFolding = &Skip.AssignBase; |
// Assignments of Base from a Relocatable or ConstantInt32 can result |
// in Base becoming nullptr. To avoid code duplication in this loop we |
// prefer that Base be non-nullptr if possible. |
- if ((Base == nullptr) && (Index != nullptr) && Shift == 0) |
- std::swap(Base, Index); |
+ if ((NewAddr.Base == nullptr) && (NewAddr.Index != nullptr) && |
+ NewAddr.Shift == 0) { |
+ std::swap(NewAddr.Base, NewAddr.Index); |
+ } |
continue; |
} |
- if (matchAssign(VMetadata, GotVar, Index, Relocatable, Offset, Reason)) |
+ if (!Skip.AssignBase && |
+ (Reason = AddrOpt.matchAssign(&NewAddr.Index, &NewAddr.Relocatable, |
+ &NewAddr.Offset))) { |
+ SkipLastFolding = &Skip.AssignIndex; |
continue; |
+ } |
if (!MockBounds) { |
// Transition from: |
// <Relocatable + Offset>(Base) to |
// <Relocatable + Offset>(Base, Index) |
- if (!ReserveSlot && |
- matchCombinedBaseIndex(VMetadata, Base, Index, Shift, Reason)) |
+ if (!Skip.CombinedBaseIndex && |
+ (Reason = AddrOpt.matchCombinedBaseIndex( |
+ &NewAddr.Base, &NewAddr.Index, &NewAddr.Shift))) { |
+ SkipLastFolding = &Skip.CombinedBaseIndex; |
continue; |
+ } |
+ |
// Recognize multiply/shift and update Shift amount. |
// Index becomes Index=Var<<Const && Const+Shift<=3 ==> |
// Index=Var, Shift+=Const |
// Index becomes Index=Const*Var && log2(Const)+Shift<=3 ==> |
// Index=Var, Shift+=log2(Const) |
- if (matchShiftedIndex(VMetadata, Index, Shift, Reason)) |
+ if ((Reason = |
+ AddrOpt.matchShiftedIndex(&NewAddr.Index, &NewAddr.Shift))) { |
continue; |
+ } |
+ |
// If Shift is zero, the choice of Base and Index was purely arbitrary. |
// Recognize multiply/shift and set Shift amount. |
// Shift==0 && Base is Base=Var*Const && log2(Const)+Shift<=3 ==> |
// swap(Index,Base) |
// Similar for Base=Const*Var and Base=Var<<Const |
- if (Shift == 0 && matchShiftedIndex(VMetadata, Base, Shift, Reason)) { |
- std::swap(Base, Index); |
+ if (NewAddr.Shift == 0 && |
+ (Reason = AddrOpt.matchShiftedIndex(&NewAddr.Base, &NewAddr.Shift))) { |
+ std::swap(NewAddr.Base, NewAddr.Index); |
continue; |
} |
} |
+ |
// Update Offset to reflect additions/subtractions with constants and |
// relocatables. |
// TODO: consider overflow issues with respect to Offset. |
- if (matchOffsetBase(VMetadata, GotVar, Base, Index, Relocatable, Offset, |
- Reason)) |
+ if (!Skip.OffsetFromBase && |
+ (Reason = AddrOpt.matchOffsetBase(&NewAddr.Base, &NewAddr.Relocatable, |
+ &NewAddr.Offset))) { |
+ SkipLastFolding = &Skip.OffsetFromBase; |
continue; |
- if (Shift == 0 && matchOffsetBase(VMetadata, GotVar, Index, Base, |
- Relocatable, Offset, Reason)) |
+ } |
+ if (NewAddr.Shift == 0 && !Skip.OffsetFromIndex && |
+ (Reason = AddrOpt.matchOffsetBase(&NewAddr.Index, &NewAddr.Relocatable, |
+ &NewAddr.Offset))) { |
+ SkipLastFolding = &Skip.OffsetFromIndex; |
continue; |
+ } |
+ |
// TODO(sehr, stichnot): Handle updates of Index with Shift != 0. |
// Index is Index=Var+Const ==> |
// set Index=Var, Offset+=(Const<<Shift) |
@@ -5277,13 +5330,40 @@ inline bool computeAddressOpt(Cfg *Func, const Inst *Instr, Variable *GotVar, |
// set Index=Var, Offset-=(Const<<Shift) |
break; |
} while (Reason); |
- // Undo any addition of GotVar. It will be added back when the mem operand is |
- // legalized. |
- if (Base == GotVar) |
- Base = nullptr; |
- if (Index == GotVar) |
- Index = nullptr; |
- return AddressWasOptimized; |
+ |
+ if (!AddressWasOptimized) { |
+ return nullptr; |
+ } |
+ |
+ // Undo any addition of RebasePtr. It will be added back when the mem |
+ // operand is sandboxed. |
+ if (NewAddr.Base == RebasePtr) { |
+ NewAddr.Base = nullptr; |
+ } |
+ |
+ if (NewAddr.Index == RebasePtr) { |
+ NewAddr.Index = nullptr; |
+ NewAddr.Shift = 0; |
+ } |
+ |
+ Constant *OffsetOp = nullptr; |
+ if (NewAddr.Relocatable == nullptr) { |
+ OffsetOp = Ctx->getConstantInt32(NewAddr.Offset); |
+ } else { |
+ OffsetOp = |
+ Ctx->getConstantSym(NewAddr.Relocatable->getOffset() + NewAddr.Offset, |
+ NewAddr.Relocatable->getName(), |
+ NewAddr.Relocatable->getSuppressMangling()); |
+ } |
+ // Vanilla ICE load instructions should not use the segment registers, and |
+ // computeAddressOpt only works at the level of Variables and Constants, not |
+ // other X86OperandMem, so there should be no mention of segment |
+ // registers there either. |
+ static constexpr auto SegmentReg = |
+ X86OperandMem::SegmentRegisters::DefaultSegment; |
+ |
+ return X86OperandMem::create(Func, MemType, NewAddr.Base, OffsetOp, |
+ NewAddr.Index, NewAddr.Shift, SegmentReg); |
} |
/// Add a mock bounds check on the memory address before using it as a load or |
@@ -5361,35 +5441,11 @@ void TargetX86Base<TraitsType>::lowerLoad(const InstLoad *Load) { |
template <typename TraitsType> |
void TargetX86Base<TraitsType>::doAddressOptLoad() { |
Inst *Inst = Context.getCur(); |
- Variable *Dest = Inst->getDest(); |
Operand *Addr = Inst->getSrc(0); |
- Variable *Index = nullptr; |
- ConstantRelocatable *Relocatable = nullptr; |
- uint16_t Shift = 0; |
- int32_t Offset = 0; |
- // Vanilla ICE load instructions should not use the segment registers, and |
- // computeAddressOpt only works at the level of Variables and Constants, not |
- // other X86OperandMem, so there should be no mention of segment |
- // registers there either. |
- constexpr auto SegmentReg = X86OperandMem::SegmentRegisters::DefaultSegment; |
- auto *Base = llvm::dyn_cast<Variable>(Addr); |
- const bool ReserveSlot = Traits::Is64Bit && NeedSandboxing; |
- if (computeAddressOpt(Func, Inst, GotVar, ReserveSlot, Relocatable, Offset, |
- Base, Index, Shift)) { |
+ Variable *Dest = Inst->getDest(); |
+ if (auto *OptAddr = computeAddressOpt(Inst, Dest->getType(), Addr)) { |
Inst->setDeleted(); |
- Constant *OffsetOp = nullptr; |
- if (Relocatable == nullptr) { |
- OffsetOp = Ctx->getConstantInt32(Offset); |
- } else { |
- OffsetOp = Ctx->getConstantSym(Relocatable->getOffset() + Offset, |
- Relocatable->getName(), |
- Relocatable->getSuppressMangling()); |
- } |
- // The new mem operand is created without IsRebased being set, because |
- // computeAddressOpt() doesn't include GotVar in its final result. |
- Addr = X86OperandMem::create(Func, Dest->getType(), Base, OffsetOp, Index, |
- Shift, SegmentReg); |
- Context.insert<InstLoad>(Dest, Addr); |
+ Context.insert<InstLoad>(Dest, OptAddr); |
} |
} |
@@ -5686,35 +5742,11 @@ void TargetX86Base<TraitsType>::lowerStore(const InstStore *Inst) { |
template <typename TraitsType> |
void TargetX86Base<TraitsType>::doAddressOptStore() { |
auto *Inst = llvm::cast<InstStore>(Context.getCur()); |
- Operand *Data = Inst->getData(); |
Operand *Addr = Inst->getAddr(); |
- Variable *Index = nullptr; |
- ConstantRelocatable *Relocatable = nullptr; |
- uint16_t Shift = 0; |
- int32_t Offset = 0; |
- auto *Base = llvm::dyn_cast<Variable>(Addr); |
- // Vanilla ICE store instructions should not use the segment registers, and |
- // computeAddressOpt only works at the level of Variables and Constants, not |
- // other X86OperandMem, so there should be no mention of segment |
- // registers there either. |
- constexpr auto SegmentReg = X86OperandMem::SegmentRegisters::DefaultSegment; |
- const bool ReserveSlot = Traits::Is64Bit && NeedSandboxing; |
- if (computeAddressOpt(Func, Inst, GotVar, ReserveSlot, Relocatable, Offset, |
- Base, Index, Shift)) { |
+ Operand *Data = Inst->getData(); |
+ if (auto *OptAddr = computeAddressOpt(Inst, Data->getType(), Addr)) { |
Inst->setDeleted(); |
- Constant *OffsetOp = nullptr; |
- if (Relocatable == nullptr) { |
- OffsetOp = Ctx->getConstantInt32(Offset); |
- } else { |
- OffsetOp = Ctx->getConstantSym(Relocatable->getOffset() + Offset, |
- Relocatable->getName(), |
- Relocatable->getSuppressMangling()); |
- } |
- // The new mem operand is created without IsRebased being set, because |
- // computeAddressOpt() doesn't include GotVar in its final result. |
- Addr = X86OperandMem::create(Func, Data->getType(), Base, OffsetOp, Index, |
- Shift, SegmentReg); |
- auto *NewStore = Context.insert<InstStore>(Data, Addr); |
+ auto *NewStore = Context.insert<InstStore>(Data, OptAddr); |
if (Inst->getDest()) |
NewStore->setRmwBeacon(Inst->getRmwBeacon()); |
} |
@@ -5774,9 +5806,8 @@ void TargetX86Base<TraitsType>::lowerCaseCluster(const CaseCluster &Case, |
constexpr RelocOffsetT RelocOffset = 0; |
constexpr bool SuppressMangling = true; |
- const bool IsRebased = Ctx->getFlags().getUseNonsfi(); |
IceString MangledName = Ctx->mangleName(Func->getFunctionName()); |
- Variable *Base = IsRebased ? legalizeToReg(GotVar) : nullptr; |
+ constexpr Variable *NoBase = nullptr; |
Constant *Offset = Ctx->getConstantSym( |
RelocOffset, InstJumpTable::makeName(MangledName, JumpTable->getId()), |
SuppressMangling); |
@@ -5785,11 +5816,10 @@ void TargetX86Base<TraitsType>::lowerCaseCluster(const CaseCluster &Case, |
Variable *Target = nullptr; |
if (Traits::Is64Bit && NeedSandboxing) { |
- assert(Base == nullptr); |
assert(Index != nullptr && Index->getType() == IceType_i32); |
} |
- auto *TargetInMemory = X86OperandMem::create( |
- Func, PointerType, Base, Offset, Index, Shift, Segment, IsRebased); |
+ auto *TargetInMemory = X86OperandMem::create(Func, PointerType, NoBase, |
+ Offset, Index, Shift, Segment); |
_mov(Target, TargetInMemory); |
lowerIndirectJump(Target); |
@@ -6116,12 +6146,12 @@ void TargetX86Base<TraitsType>::lowerOther(const Inst *Instr) { |
/// Turn an i64 Phi instruction into a pair of i32 Phi instructions, to preserve |
/// integrity of liveness analysis. Undef values are also turned into zeroes, |
/// since loOperand() and hiOperand() don't expect Undef input. Also, in |
-/// Non-SFI mode, add a FakeUse(GotVar) for every pooled constant operand. |
+/// Non-SFI mode, add a FakeUse(RebasePtr) for every pooled constant operand. |
template <typename TraitsType> void TargetX86Base<TraitsType>::prelowerPhis() { |
if (Ctx->getFlags().getUseNonsfi()) { |
- assert(GotVar); |
+ assert(RebasePtr); |
CfgNode *Node = Context.getNode(); |
- uint32_t GotVarUseCount = 0; |
+ uint32_t RebasePtrUseCount = 0; |
for (Inst &I : Node->getPhis()) { |
auto *Phi = llvm::dyn_cast<InstPhi>(&I); |
if (Phi->isDeleted()) |
@@ -6132,12 +6162,12 @@ template <typename TraitsType> void TargetX86Base<TraitsType>::prelowerPhis() { |
// kinds of pooling. |
if (llvm::isa<ConstantRelocatable>(Src) || |
llvm::isa<ConstantFloat>(Src) || llvm::isa<ConstantDouble>(Src)) { |
- ++GotVarUseCount; |
+ ++RebasePtrUseCount; |
} |
} |
} |
- if (GotVarUseCount) { |
- Node->getInsts().push_front(InstFakeUse::create(Func, GotVar)); |
+ if (RebasePtrUseCount) { |
+ Node->getInsts().push_front(InstFakeUse::create(Func, RebasePtr)); |
} |
} |
if (Traits::Is64Bit) { |
@@ -6685,29 +6715,13 @@ Operand *TargetX86Base<TraitsType>::legalize(Operand *From, LegalMask Allowed, |
RegIndex = llvm::cast<Variable>( |
legalize(Index, Legal_Reg | Legal_Rematerializable)); |
} |
- // For Non-SFI mode, if the Offset field is a ConstantRelocatable, we |
- // replace either Base or Index with a legalized GotVar. At emission time, |
- // the ConstantRelocatable will be emitted with the @GOTOFF relocation. |
- bool IsRebased = false; |
- if (UseNonsfi && !Mem->getIsRebased() && Offset && |
- llvm::isa<ConstantRelocatable>(Offset)) { |
- assert(!(Allowed & Legal_AddrAbs)); |
- IsRebased = true; |
- if (RegBase == nullptr) { |
- RegBase = legalizeToReg(GotVar); |
- } else if (RegIndex == nullptr) { |
- RegIndex = legalizeToReg(GotVar); |
- } else { |
- llvm::report_fatal_error( |
- "Either Base or Index must be unused in Non-SFI mode"); |
- } |
- } |
+ |
if (Base != RegBase || Index != RegIndex) { |
Mem = X86OperandMem::create(Func, Ty, RegBase, Offset, RegIndex, Shift, |
- Mem->getSegmentRegister(), IsRebased); |
+ Mem->getSegmentRegister()); |
} |
- // For all Memory Operands, we do randomization/pooling here |
+ // For all Memory Operands, we do randomization/pooling here. |
From = randomizeOrPoolImmediate(Mem); |
if (!(Allowed & Legal_Mem)) { |
@@ -6746,24 +6760,21 @@ Operand *TargetX86Base<TraitsType>::legalize(Operand *From, LegalMask Allowed, |
} |
} |
- // If the operand is a ConstantRelocatable, and Legal_AddrAbs is not |
- // specified, and UseNonsfi is indicated, we need to add GotVar. |
if (auto *CR = llvm::dyn_cast<ConstantRelocatable>(Const)) { |
+ // If the operand is a ConstantRelocatable, and Legal_AddrAbs is not |
+ // specified, and UseNonsfi is indicated, we need to add RebasePtr. |
if (UseNonsfi && !(Allowed & Legal_AddrAbs)) { |
assert(Ty == IceType_i32); |
- Variable *RegBase = legalizeToReg(GotVar); |
Variable *NewVar = makeReg(Ty, RegNum); |
- static constexpr bool IsRebased = true; |
- auto *Mem = |
- Traits::X86OperandMem::create(Func, Ty, RegBase, CR, IsRebased); |
- _lea(NewVar, Mem); |
+ auto *Mem = Traits::X86OperandMem::create(Func, Ty, nullptr, CR); |
+ // LEAs are not automatically sandboxed, thus we explicitly invoke |
+ // _sandbox_mem_reference. |
+ _lea(NewVar, _sandbox_mem_reference(Mem)); |
From = NewVar; |
} |
- } |
- |
- // Convert a scalar floating point constant into an explicit memory |
- // operand. |
- if (isScalarFloatingType(Ty)) { |
+ } else if (isScalarFloatingType(Ty)) { |
+ // Convert a scalar floating point constant into an explicit memory |
+ // operand. |
if (auto *ConstFloat = llvm::dyn_cast<ConstantFloat>(Const)) { |
if (Utils::isPositiveZero(ConstFloat->getValue())) |
return makeZeroedRegister(Ty, RegNum); |
@@ -6771,19 +6782,19 @@ Operand *TargetX86Base<TraitsType>::legalize(Operand *From, LegalMask Allowed, |
if (Utils::isPositiveZero(ConstDouble->getValue())) |
return makeZeroedRegister(Ty, RegNum); |
} |
- Variable *Base = UseNonsfi ? legalizeToReg(GotVar) : nullptr; |
+ |
std::string Buffer; |
llvm::raw_string_ostream StrBuf(Buffer); |
llvm::cast<Constant>(From)->emitPoolLabel(StrBuf, Ctx); |
llvm::cast<Constant>(From)->setShouldBePooled(true); |
Constant *Offset = Ctx->getConstantSym(0, StrBuf.str(), true); |
- const bool IsRebased = Base != nullptr; |
- auto *Mem = X86OperandMem::create(Func, Ty, Base, Offset, IsRebased); |
+ auto *Mem = X86OperandMem::create(Func, Ty, nullptr, Offset); |
From = Mem; |
} |
+ |
bool NeedsReg = false; |
if (!(Allowed & Legal_Imm) && !isScalarFloatingType(Ty)) |
- // Immediate specifically not allowed |
+ // Immediate specifically not allowed. |
NeedsReg = true; |
if (!(Allowed & Legal_Mem) && isScalarFloatingType(Ty)) |
// On x86, FP constants are lowered to mem operands. |
@@ -6816,8 +6827,7 @@ Operand *TargetX86Base<TraitsType>::legalize(Operand *From, LegalMask Allowed, |
_lea(NewVar, Mem); |
From = NewVar; |
} else if ((!(Allowed & Legal_Mem) && !MustHaveRegister) || |
- (RegNum != Variable::NoRegister && RegNum != Var->getRegNum()) || |
- MustRematerialize) { |
+ (RegNum != Variable::NoRegister && RegNum != Var->getRegNum())) { |
From = copyToReg(From, RegNum); |
} |
return From; |
@@ -7097,11 +7107,9 @@ TargetX86Base<TraitsType>::randomizeOrPoolImmediate(Constant *Immediate, |
constexpr bool SuppressMangling = true; |
Constant *Symbol = |
Ctx->getConstantSym(Offset, Label_stream.str(), SuppressMangling); |
- const bool UseNonsfi = Ctx->getFlags().getUseNonsfi(); |
- Variable *Base = UseNonsfi ? legalizeToReg(GotVar) : nullptr; |
- const bool IsRebased = Base != nullptr; |
- X86OperandMem *MemOperand = X86OperandMem::create( |
- Func, Immediate->getType(), Base, Symbol, IsRebased); |
+ constexpr Variable *NoBase = nullptr; |
+ X86OperandMem *MemOperand = |
+ X86OperandMem::create(Func, Immediate->getType(), NoBase, Symbol); |
_mov(Reg, MemOperand); |
return Reg; |
} |
@@ -7207,11 +7215,9 @@ TargetX86Base<TraitsType>::randomizeOrPoolImmediate(X86OperandMem *MemOperand, |
constexpr bool SuppressMangling = true; |
Constant *Symbol = |
Ctx->getConstantSym(SymOffset, Label_stream.str(), SuppressMangling); |
- const bool UseNonsfi = Ctx->getFlags().getUseNonsfi(); |
- Variable *Base = UseNonsfi ? legalizeToReg(GotVar) : nullptr; |
- const bool IsRebased = Base != nullptr; |
+ constexpr Variable *NoBase = nullptr; |
X86OperandMem *SymbolOperand = X86OperandMem::create( |
- Func, MemOperand->getOffset()->getType(), Base, Symbol, IsRebased); |
+ Func, MemOperand->getOffset()->getType(), NoBase, Symbol); |
_mov(RegTemp, SymbolOperand); |
// If we have a base variable here, we should add the lea instruction |
// to add the value of the base variable to RegTemp. If there is no |