| Index: src/IceTargetLoweringX86BaseImpl.h
|
| diff --git a/src/IceTargetLoweringX86BaseImpl.h b/src/IceTargetLoweringX86BaseImpl.h
|
| index 0d4e6bb343405438dcebff08c1fa30af0aa78739..b5d8049bce004d077aef7ca2ceab7fa7765710bb 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) {
|
| + : TargetLowering(Func), NeedSandboxing(Ctx->getFlags().getUseSandboxing()) {
|
| static_assert(
|
| (Traits::InstructionSet::End - Traits::InstructionSet::Begin) ==
|
| (TargetInstructionSet::X86InstructionSet_End -
|
| @@ -325,7 +325,8 @@ TargetX86Base<TraitsType>::TargetX86Base(Cfg *Func)
|
|
|
| template <typename TraitsType>
|
| void TargetX86Base<TraitsType>::staticInit(const ClFlags &Flags) {
|
| - Traits::initRegisterSet(&TypeToRegisterSet, &RegisterAliases, &ScratchRegs);
|
| + Traits::initRegisterSet(Flags, &TypeToRegisterSet, &RegisterAliases,
|
| + &ScratchRegs);
|
| PcRelFixup = Traits::FK_PcRel;
|
| AbsFixup = Flags.getUseNonsfi() ? Traits::FK_Gotoff : Traits::FK_Abs;
|
| }
|
| @@ -336,6 +337,11 @@ template <typename TraitsType> void TargetX86Base<TraitsType>::translateO2() {
|
| if (!Traits::Is64Bit && Func->getContext()->getFlags().getUseNonsfi()) {
|
| GotVar = Func->makeVariable(IceType_i32);
|
| }
|
| +
|
| + if (NeedSandboxing) {
|
| + initSandbox();
|
| + }
|
| +
|
| genTargetHelperCalls();
|
| Func->dump("After target helper call insertion");
|
|
|
| @@ -456,8 +462,9 @@ template <typename TraitsType> void TargetX86Base<TraitsType>::translateO2() {
|
| Func->doNopInsertion();
|
|
|
| // Mark nodes that require sandbox alignment
|
| - if (Ctx->getFlags().getUseSandboxing())
|
| + if (NeedSandboxing) {
|
| Func->markNodesForSandboxing();
|
| + }
|
| }
|
|
|
| template <typename TraitsType> void TargetX86Base<TraitsType>::translateOm1() {
|
| @@ -466,6 +473,11 @@ template <typename TraitsType> void TargetX86Base<TraitsType>::translateOm1() {
|
| if (!Traits::Is64Bit && Func->getContext()->getFlags().getUseNonsfi()) {
|
| GotVar = Func->makeVariable(IceType_i32);
|
| }
|
| +
|
| + if (NeedSandboxing) {
|
| + initSandbox();
|
| + }
|
| +
|
| genTargetHelperCalls();
|
|
|
| // Do not merge Alloca instructions, and lay out the stack.
|
| @@ -508,7 +520,7 @@ template <typename TraitsType> void TargetX86Base<TraitsType>::translateOm1() {
|
| Func->doNopInsertion();
|
|
|
| // Mark nodes that require sandbox alignment
|
| - if (Ctx->getFlags().getUseSandboxing())
|
| + if (NeedSandboxing)
|
| Func->markNodesForSandboxing();
|
| }
|
|
|
| @@ -810,7 +822,11 @@ void TargetX86Base<TraitsType>::emitVariable(const Variable *Var) const {
|
| return;
|
| Ostream &Str = Ctx->getStrEmit();
|
| if (Var->hasReg()) {
|
| - Str << "%" << getRegName(Var->getRegNum(), Var->getType());
|
| + const bool Is64BitSandboxing = Traits::Is64Bit && NeedSandboxing;
|
| + const Type VarType = (Var->isRematerializable() && Is64BitSandboxing)
|
| + ? IceType_i64
|
| + : Var->getType();
|
| + Str << "%" << getRegName(Var->getRegNum(), VarType);
|
| return;
|
| }
|
| if (Var->mustHaveReg()) {
|
| @@ -923,7 +939,7 @@ TargetX86Base<TraitsType>::loOperand(Operand *Operand) {
|
| if (auto *Mem = llvm::dyn_cast<X86OperandMem>(Operand)) {
|
| auto *MemOperand = X86OperandMem::create(
|
| Func, IceType_i32, Mem->getBase(), Mem->getOffset(), Mem->getIndex(),
|
| - Mem->getShift(), Mem->getSegmentRegister(), Mem->getIsPIC());
|
| + Mem->getShift(), Mem->getSegmentRegister(), Mem->getIsRebased());
|
| // Test if we should randomize or pool the offset, if so randomize it or
|
| // pool it then create mem operand with the blinded/pooled constant.
|
| // Otherwise, return the mem operand as ordinary mem operand.
|
| @@ -963,7 +979,7 @@ TargetX86Base<TraitsType>::hiOperand(Operand *Operand) {
|
| }
|
| auto *MemOperand = X86OperandMem::create(
|
| Func, IceType_i32, Mem->getBase(), Offset, Mem->getIndex(),
|
| - Mem->getShift(), Mem->getSegmentRegister(), Mem->getIsPIC());
|
| + Mem->getShift(), Mem->getSegmentRegister(), Mem->getIsRebased());
|
| // Test if the Offset is an eligible i32 constants for randomization and
|
| // pooling. Blind/pool it if it is. Otherwise return as oridinary mem
|
| // operand.
|
| @@ -977,7 +993,7 @@ template <typename TraitsType>
|
| llvm::SmallBitVector
|
| TargetX86Base<TraitsType>::getRegisterSet(RegSetMask Include,
|
| RegSetMask Exclude) const {
|
| - return Traits::getRegisterSet(Include, Exclude);
|
| + return Traits::getRegisterSet(Ctx->getFlags(), Include, Exclude);
|
| }
|
|
|
| template <typename TraitsType>
|
| @@ -1037,35 +1053,38 @@ void TargetX86Base<TraitsType>::lowerAlloca(const InstAlloca *Inst) {
|
| llvm::dyn_cast<ConstantInteger32>(TotalSize)) {
|
| const uint32_t Value =
|
| Utils::applyAlignment(ConstantTotalSize->getValue(), Alignment);
|
| - if (!UseFramePointer) {
|
| + if (UseFramePointer) {
|
| + _sub_sp(Ctx->getConstantInt32(Value));
|
| + } else {
|
| // If we don't need a Frame Pointer, this alloca has a known offset to the
|
| // stack pointer. We don't need adjust the stack pointer, nor assign any
|
| // value to Dest, as Dest is rematerializable.
|
| assert(Dest->isRematerializable());
|
| FixedAllocaSizeBytes += Value;
|
| Context.insert<InstFakeDef>(Dest);
|
| - } else {
|
| - _sub(esp, Ctx->getConstantInt32(Value));
|
| }
|
| } else {
|
| // Non-constant sizes need to be adjusted to the next highest multiple of
|
| // the required alignment at runtime.
|
| - Variable *T = makeReg(Traits::WordType);
|
| - if (Traits::Is64Bit && TotalSize->getType() != IceType_i64) {
|
| + Variable *T = nullptr;
|
| + if (Traits::Is64Bit && TotalSize->getType() != IceType_i64 &&
|
| + !NeedSandboxing) {
|
| + T = makeReg(IceType_i64);
|
| _movzx(T, TotalSize);
|
| } else {
|
| + T = makeReg(IceType_i32);
|
| _mov(T, TotalSize);
|
| }
|
| _add(T, Ctx->getConstantInt32(Alignment - 1));
|
| _and(T, Ctx->getConstantInt32(-Alignment));
|
| - _sub(esp, T);
|
| + _sub_sp(T);
|
| }
|
| // Add enough to the returned address to account for the out args area.
|
| uint32_t OutArgsSize = maxOutArgsSizeBytes();
|
| if (OutArgsSize > 0) {
|
| Variable *T = makeReg(IceType_i32);
|
| auto *CalculateOperand = X86OperandMem::create(
|
| - Func, IceType_i32, esp, Ctx->getConstantInt(IceType_i32, OutArgsSize));
|
| + Func, IceType_void, esp, Ctx->getConstantInt(IceType_i32, OutArgsSize));
|
| _lea(T, CalculateOperand);
|
| _mov(Dest, T);
|
| } else {
|
| @@ -1086,8 +1105,8 @@ bool TargetX86Base<TraitsType>::optimizeScalarMul(Variable *Dest, Operand *Src0,
|
| if (Ctx->getFlags().getOptLevel() < Opt_1)
|
| return false;
|
| Type Ty = Dest->getType();
|
| - Variable *T = nullptr;
|
| if (Src1 == -1) {
|
| + Variable *T = nullptr;
|
| _mov(T, Src0);
|
| _neg(T);
|
| _mov(Dest, T);
|
| @@ -1098,6 +1117,7 @@ bool TargetX86Base<TraitsType>::optimizeScalarMul(Variable *Dest, Operand *Src0,
|
| return true;
|
| }
|
| if (Src1 == 1) {
|
| + Variable *T = nullptr;
|
| _mov(T, Src0);
|
| _mov(Dest, T);
|
| return true;
|
| @@ -1135,15 +1155,21 @@ bool TargetX86Base<TraitsType>::optimizeScalarMul(Variable *Dest, Operand *Src0,
|
| return false;
|
| }
|
| }
|
| - // Lea optimization only works for i32 type, not i1/i8/i16/i64.
|
| - if (Ty != IceType_i32 && (Count3 || Count5 || Count9))
|
| + // Lea optimization only works for i16 and i32 types, not i8.
|
| + if (Ty != IceType_i32 && !(Traits::Is64Bit && Ty == IceType_i64) &&
|
| + (Count3 || Count5 || Count9))
|
| return false;
|
| // Limit the number of lea/shl operations for a single multiply, to a
|
| // somewhat arbitrary choice of 3.
|
| constexpr uint32_t MaxOpsForOptimizedMul = 3;
|
| if (CountOps > MaxOpsForOptimizedMul)
|
| return false;
|
| - _mov(T, Src0);
|
| + Variable *T = makeReg(Traits::WordType);
|
| + if (typeWidthInBytes(Src0->getType()) < typeWidthInBytes(T->getType())) {
|
| + _movzx(T, Src0);
|
| + } else {
|
| + _mov(T, Src0);
|
| + }
|
| Constant *Zero = Ctx->getConstantZero(IceType_i32);
|
| for (uint32_t i = 0; i < Count9; ++i) {
|
| constexpr uint16_t Shift = 3; // log2(9-1)
|
| @@ -3543,7 +3569,7 @@ void TargetX86Base<TraitsType>::lowerIntrinsicCall(
|
| return;
|
| }
|
| case Intrinsics::NaClReadTP: {
|
| - if (Ctx->getFlags().getUseSandboxing()) {
|
| + if (NeedSandboxing) {
|
| Operand *Src =
|
| dispatchToConcrete(&ConcreteTarget::createNaClReadTPSrcOperand);
|
| Variable *Dest = Instr->getDest();
|
| @@ -3571,20 +3597,26 @@ void TargetX86Base<TraitsType>::lowerIntrinsicCall(
|
| return;
|
| }
|
| case Intrinsics::Stacksave: {
|
| - Variable *esp =
|
| - Func->getTarget()->getPhysicalRegister(getStackReg(), Traits::WordType);
|
| + if (!Traits::Is64Bit || !NeedSandboxing) {
|
| + Variable *esp = Func->getTarget()->getPhysicalRegister(getStackReg(),
|
| + Traits::WordType);
|
| + Variable *Dest = Instr->getDest();
|
| + _mov(Dest, esp);
|
| + return;
|
| + }
|
| + Variable *esp = Func->getTarget()->getPhysicalRegister(
|
| + Traits::RegisterSet::Reg_esp, IceType_i32);
|
| Variable *Dest = Instr->getDest();
|
| _mov(Dest, esp);
|
| +
|
| return;
|
| }
|
| case Intrinsics::Stackrestore: {
|
| Operand *Src = Instr->getArg(0);
|
| - const Type SrcTy = Src->getType();
|
| - Variable *esp = Func->getTarget()->getPhysicalRegister(
|
| - Traits::getGprForType(SrcTy, getStackReg()), SrcTy);
|
| - _redefined(_mov(esp, Src));
|
| + _mov_sp(Src);
|
| return;
|
| }
|
| +
|
| case Intrinsics::Trap:
|
| _ud2();
|
| return;
|
| @@ -4293,25 +4325,6 @@ void TargetX86Base<TraitsType>::lowerMemset(Operand *Dest, Operand *Val,
|
| lowerCall(Call);
|
| }
|
|
|
| -template <typename TraitsType>
|
| -void TargetX86Base<TraitsType>::lowerIndirectJump(Variable *JumpTarget) {
|
| - const bool NeedSandboxing = Ctx->getFlags().getUseSandboxing();
|
| - if (Traits::Is64Bit) {
|
| - Variable *T = makeReg(IceType_i64);
|
| - _movzx(T, JumpTarget);
|
| - JumpTarget = T;
|
| - }
|
| - if (NeedSandboxing) {
|
| - _bundle_lock();
|
| - const SizeT BundleSize =
|
| - 1 << Func->getAssembler<>()->getBundleAlignLog2Bytes();
|
| - _and(JumpTarget, Ctx->getConstantInt32(~(BundleSize - 1)));
|
| - }
|
| - _jmp(JumpTarget);
|
| - if (NeedSandboxing)
|
| - _bundle_unlock();
|
| -}
|
| -
|
| inline bool isAdd(const Inst *Inst) {
|
| if (auto *Arith = llvm::dyn_cast_or_null<const InstArithmetic>(Inst)) {
|
| return (Arith->getOp() == InstArithmetic::Add);
|
| @@ -4551,13 +4564,15 @@ inline bool matchOffsetBase(const VariablesMetadata *VMetadata,
|
| return false;
|
| // Compute the updated constant offset.
|
| if (Const0) {
|
| - int32_t MoreOffset = IsAdd ? Const0->getValue() : -Const0->getValue();
|
| + const int32_t MoreOffset =
|
| + IsAdd ? Const0->getValue() : -Const0->getValue();
|
| if (Utils::WouldOverflowAdd(NewOffset, MoreOffset))
|
| return false;
|
| NewOffset += MoreOffset;
|
| }
|
| if (Const1) {
|
| - int32_t MoreOffset = IsAdd ? Const1->getValue() : -Const1->getValue();
|
| + const int32_t MoreOffset =
|
| + IsAdd ? Const1->getValue() : -Const1->getValue();
|
| if (Utils::WouldOverflowAdd(NewOffset, MoreOffset))
|
| return false;
|
| NewOffset += MoreOffset;
|
| @@ -4586,6 +4601,7 @@ inline bool matchOffsetBase(const VariablesMetadata *VMetadata,
|
| // 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) {
|
| @@ -4610,6 +4626,7 @@ inline bool computeAddressOpt(Cfg *Func, const Inst *Instr, Variable *GotVar,
|
| const VariablesMetadata *VMetadata = Func->getVMetadata();
|
| const Inst *Reason = nullptr;
|
| do {
|
| + assert(!ReserveSlot || Base == nullptr || Index == nullptr);
|
| if (Reason) {
|
| dumpAddressOpt(Func, Relocatable, Offset, Base, Index, Shift, Reason);
|
| AddressWasOptimized = true;
|
| @@ -4631,7 +4648,8 @@ inline bool computeAddressOpt(Cfg *Func, const Inst *Instr, Variable *GotVar,
|
| // Transition from:
|
| // <Relocatable + Offset>(Base) to
|
| // <Relocatable + Offset>(Base, Index)
|
| - if (matchCombinedBaseIndex(VMetadata, Base, Index, Shift, Reason))
|
| + if (!ReserveSlot &&
|
| + matchCombinedBaseIndex(VMetadata, Base, Index, Shift, Reason))
|
| continue;
|
| // Recognize multiply/shift and update Shift amount.
|
| // Index becomes Index=Var<<Const && Const+Shift<=3 ==>
|
| @@ -4764,8 +4782,9 @@ void TargetX86Base<TraitsType>::doAddressOptLoad() {
|
| // registers there either.
|
| constexpr auto SegmentReg = X86OperandMem::SegmentRegisters::DefaultSegment;
|
| auto *Base = llvm::dyn_cast<Variable>(Addr);
|
| - if (computeAddressOpt(Func, Inst, GotVar, Relocatable, Offset, Base, Index,
|
| - Shift)) {
|
| + const bool ReserveSlot = Traits::Is64Bit && NeedSandboxing;
|
| + if (computeAddressOpt(Func, Inst, GotVar, ReserveSlot, Relocatable, Offset,
|
| + Base, Index, Shift)) {
|
| Inst->setDeleted();
|
| Constant *OffsetOp = nullptr;
|
| if (Relocatable == nullptr) {
|
| @@ -4775,7 +4794,7 @@ void TargetX86Base<TraitsType>::doAddressOptLoad() {
|
| Relocatable->getName(),
|
| Relocatable->getSuppressMangling());
|
| }
|
| - // The new mem operand is created without IsPIC being set, because
|
| + // 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);
|
| @@ -5069,8 +5088,9 @@ void TargetX86Base<TraitsType>::doAddressOptStore() {
|
| // other X86OperandMem, so there should be no mention of segment
|
| // registers there either.
|
| constexpr auto SegmentReg = X86OperandMem::SegmentRegisters::DefaultSegment;
|
| - if (computeAddressOpt(Func, Inst, GotVar, Relocatable, Offset, Base, Index,
|
| - Shift)) {
|
| + const bool ReserveSlot = Traits::Is64Bit && NeedSandboxing;
|
| + if (computeAddressOpt(Func, Inst, GotVar, ReserveSlot, Relocatable, Offset,
|
| + Base, Index, Shift)) {
|
| Inst->setDeleted();
|
| Constant *OffsetOp = nullptr;
|
| if (Relocatable == nullptr) {
|
| @@ -5080,7 +5100,7 @@ void TargetX86Base<TraitsType>::doAddressOptStore() {
|
| Relocatable->getName(),
|
| Relocatable->getSuppressMangling());
|
| }
|
| - // The new mem operand is created without IsPIC being set, because
|
| + // 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);
|
| @@ -5134,8 +5154,9 @@ void TargetX86Base<TraitsType>::lowerCaseCluster(const CaseCluster &Case,
|
|
|
| // Make sure the index is a register of the same width as the base
|
| Variable *Index;
|
| - if (RangeIndex->getType() != getPointerType()) {
|
| - Index = makeReg(getPointerType());
|
| + const Type PointerType = getPointerType();
|
| + if (RangeIndex->getType() != PointerType) {
|
| + Index = makeReg(PointerType);
|
| _movzx(Index, RangeIndex);
|
| } else {
|
| Index = legalizeToReg(RangeIndex);
|
| @@ -5143,18 +5164,24 @@ void TargetX86Base<TraitsType>::lowerCaseCluster(const CaseCluster &Case,
|
|
|
| constexpr RelocOffsetT RelocOffset = 0;
|
| constexpr bool SuppressMangling = true;
|
| - const bool IsPIC = Ctx->getFlags().getUseNonsfi();
|
| + const bool IsRebased = Ctx->getFlags().getUseNonsfi();
|
| IceString MangledName = Ctx->mangleName(Func->getFunctionName());
|
| - Variable *Base = IsPIC ? legalizeToReg(GotVar) : nullptr;
|
| + Variable *Base = IsRebased ? legalizeToReg(GotVar) : nullptr;
|
| Constant *Offset = Ctx->getConstantSym(
|
| RelocOffset, InstJumpTable::makeName(MangledName, JumpTable->getId()),
|
| SuppressMangling);
|
| - uint16_t Shift = typeWidthInBytesLog2(getPointerType());
|
| + uint16_t Shift = typeWidthInBytesLog2(PointerType);
|
| constexpr auto Segment = X86OperandMem::SegmentRegisters::DefaultSegment;
|
| - auto *TargetInMemory = X86OperandMem::create(
|
| - Func, getPointerType(), Base, Offset, Index, Shift, Segment, IsPIC);
|
| +
|
| 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);
|
| _mov(Target, TargetInMemory);
|
| +
|
| lowerIndirectJump(Target);
|
|
|
| if (DefaultTarget == nullptr)
|
| @@ -6037,22 +6064,25 @@ Operand *TargetX86Base<TraitsType>::legalize(Operand *From, LegalMask Allowed,
|
| Constant *Offset = Mem->getOffset();
|
| Variable *RegBase = nullptr;
|
| Variable *RegIndex = nullptr;
|
| + uint16_t Shift = Mem->getShift();
|
| if (Base) {
|
| RegBase = llvm::cast<Variable>(
|
| legalize(Base, Legal_Reg | Legal_Rematerializable));
|
| }
|
| if (Index) {
|
| + // TODO(jpp): perhaps we should only allow Legal_Reg if
|
| + // Base->isRematerializable.
|
| 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 NeedPIC = false;
|
| - if (UseNonsfi && !Mem->getIsPIC() && Offset &&
|
| + bool IsRebased = false;
|
| + if (UseNonsfi && !Mem->getIsRebased() && Offset &&
|
| llvm::isa<ConstantRelocatable>(Offset)) {
|
| assert(!(Allowed & Legal_AddrAbs));
|
| - NeedPIC = true;
|
| + IsRebased = true;
|
| if (RegBase == nullptr) {
|
| RegBase = legalizeToReg(GotVar);
|
| } else if (RegIndex == nullptr) {
|
| @@ -6063,9 +6093,8 @@ Operand *TargetX86Base<TraitsType>::legalize(Operand *From, LegalMask Allowed,
|
| }
|
| }
|
| if (Base != RegBase || Index != RegIndex) {
|
| - Mem = X86OperandMem::create(Func, Ty, RegBase, Offset, RegIndex,
|
| - Mem->getShift(), Mem->getSegmentRegister(),
|
| - NeedPIC);
|
| + Mem = X86OperandMem::create(Func, Ty, RegBase, Offset, RegIndex, Shift,
|
| + Mem->getSegmentRegister(), IsRebased);
|
| }
|
|
|
| // For all Memory Operands, we do randomization/pooling here
|
| @@ -6114,8 +6143,9 @@ Operand *TargetX86Base<TraitsType>::legalize(Operand *From, LegalMask Allowed,
|
| assert(Ty == IceType_i32);
|
| Variable *RegBase = legalizeToReg(GotVar);
|
| Variable *NewVar = makeReg(Ty, RegNum);
|
| - auto *Mem = Traits::X86OperandMem::create(Func, Ty, RegBase, CR);
|
| - Mem->setIsPIC();
|
| + static constexpr bool IsRebased = true;
|
| + auto *Mem =
|
| + Traits::X86OperandMem::create(Func, Ty, RegBase, CR, IsRebased);
|
| _lea(NewVar, Mem);
|
| From = NewVar;
|
| }
|
| @@ -6137,9 +6167,8 @@ Operand *TargetX86Base<TraitsType>::legalize(Operand *From, LegalMask Allowed,
|
| llvm::cast<Constant>(From)->emitPoolLabel(StrBuf, Ctx);
|
| llvm::cast<Constant>(From)->setShouldBePooled(true);
|
| Constant *Offset = Ctx->getConstantSym(0, StrBuf.str(), true);
|
| - auto *Mem = X86OperandMem::create(Func, Ty, Base, Offset);
|
| - if (UseNonsfi)
|
| - Mem->setIsPIC();
|
| + const bool IsRebased = Base != nullptr;
|
| + auto *Mem = X86OperandMem::create(Func, Ty, Base, Offset, IsRebased);
|
| From = Mem;
|
| }
|
| bool NeedsReg = false;
|
| @@ -6263,9 +6292,9 @@ TargetX86Base<TraitsType>::formMemoryOperand(Operand *Opnd, Type Ty,
|
| assert(llvm::isa<ConstantInteger32>(Offset) ||
|
| llvm::isa<ConstantRelocatable>(Offset));
|
| }
|
| - // Not completely sure whether it's OK to leave IsPIC unset when creating
|
| - // the mem operand. If DoLegalize is true, it will definitely be applied
|
| - // during the legalize() call, but perhaps not during the
|
| + // Not completely sure whether it's OK to leave IsRebased unset when
|
| + // creating the mem operand. If DoLegalize is true, it will definitely be
|
| + // applied during the legalize() call, but perhaps not during the
|
| // randomizeOrPoolImmediate() call. In any case, the emit routines will
|
| // assert that PIC legalization has been applied.
|
| Mem = X86OperandMem::create(Func, Ty, Base, Offset);
|
| @@ -6393,71 +6422,80 @@ TargetX86Base<TraitsType>::randomizeOrPoolImmediate(Constant *Immediate,
|
| // Immediates randomization/pooling off or paused
|
| return Immediate;
|
| }
|
| - if (Immediate->shouldBeRandomizedOrPooled(Ctx)) {
|
| - Ctx->statsUpdateRPImms();
|
| - if (Ctx->getFlags().getRandomizeAndPoolImmediatesOption() ==
|
| - RPI_Randomize) {
|
| - // blind the constant
|
| - // FROM:
|
| - // imm
|
| - // TO:
|
| - // insert: mov imm+cookie, Reg
|
| - // insert: lea -cookie[Reg], Reg
|
| - // => Reg
|
| - // If we have already assigned a phy register, we must come from
|
| - // advancedPhiLowering()=>lowerAssign(). In this case we should reuse the
|
| - // assigned register as this assignment is that start of its use-def
|
| - // chain. So we add RegNum argument here. Note we use 'lea' instruction
|
| - // instead of 'xor' to avoid affecting the flags.
|
| - Variable *Reg = makeReg(IceType_i32, RegNum);
|
| - auto *Integer = llvm::cast<ConstantInteger32>(Immediate);
|
| - uint32_t Value = Integer->getValue();
|
| - uint32_t Cookie = Func->getConstantBlindingCookie();
|
| - _mov(Reg, Ctx->getConstantInt(IceType_i32, Cookie + Value));
|
| - Constant *Offset = Ctx->getConstantInt(IceType_i32, 0 - Cookie);
|
| - _lea(Reg,
|
| - X86OperandMem::create(Func, IceType_i32, Reg, Offset, nullptr, 0));
|
| - if (Immediate->getType() != IceType_i32) {
|
| - Variable *TruncReg = makeReg(Immediate->getType(), RegNum);
|
| - _mov(TruncReg, Reg);
|
| - return TruncReg;
|
| - }
|
| - return Reg;
|
| - }
|
| - if (Ctx->getFlags().getRandomizeAndPoolImmediatesOption() == RPI_Pool) {
|
| - // pool the constant
|
| - // FROM:
|
| - // imm
|
| - // TO:
|
| - // insert: mov $label, Reg
|
| - // => Reg
|
| - assert(Ctx->getFlags().getRandomizeAndPoolImmediatesOption() == RPI_Pool);
|
| - Immediate->setShouldBePooled(true);
|
| - // if we have already assigned a phy register, we must come from
|
| - // advancedPhiLowering()=>lowerAssign(). In this case we should reuse the
|
| - // assigned register as this assignment is that start of its use-def
|
| - // chain. So we add RegNum argument here.
|
| - Variable *Reg = makeReg(Immediate->getType(), RegNum);
|
| - IceString Label;
|
| - llvm::raw_string_ostream Label_stream(Label);
|
| - Immediate->emitPoolLabel(Label_stream, Ctx);
|
| - constexpr RelocOffsetT Offset = 0;
|
| - 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;
|
| - X86OperandMem *MemOperand =
|
| - X86OperandMem::create(Func, Immediate->getType(), Base, Symbol);
|
| - if (UseNonsfi)
|
| - MemOperand->setIsPIC();
|
| - _mov(Reg, MemOperand);
|
| +
|
| + if (Traits::Is64Bit && NeedSandboxing) {
|
| + // Immediate randomization/pooling is currently disabled for x86-64
|
| + // sandboxing for it could generate invalid memory operands.
|
| + assert(false &&
|
| + "Constant pooling/randomization is disabled for x8664 sandbox.");
|
| + return Immediate;
|
| + }
|
| +
|
| + if (!Immediate->shouldBeRandomizedOrPooled(Ctx)) {
|
| + // the constant Immediate is not eligible for blinding/pooling
|
| + return Immediate;
|
| + }
|
| + Ctx->statsUpdateRPImms();
|
| + switch (Ctx->getFlags().getRandomizeAndPoolImmediatesOption()) {
|
| + default:
|
| + llvm::report_fatal_error("Unsupported -randomize-pool-immediates option");
|
| + case RPI_Randomize: {
|
| + // blind the constant
|
| + // FROM:
|
| + // imm
|
| + // TO:
|
| + // insert: mov imm+cookie, Reg
|
| + // insert: lea -cookie[Reg], Reg
|
| + // => Reg
|
| + // If we have already assigned a phy register, we must come from
|
| + // advancedPhiLowering()=>lowerAssign(). In this case we should reuse the
|
| + // assigned register as this assignment is that start of its use-def
|
| + // chain. So we add RegNum argument here. Note we use 'lea' instruction
|
| + // instead of 'xor' to avoid affecting the flags.
|
| + Variable *Reg = makeReg(IceType_i32, RegNum);
|
| + auto *Integer = llvm::cast<ConstantInteger32>(Immediate);
|
| + uint32_t Value = Integer->getValue();
|
| + uint32_t Cookie = Func->getConstantBlindingCookie();
|
| + _mov(Reg, Ctx->getConstantInt(IceType_i32, Cookie + Value));
|
| + Constant *Offset = Ctx->getConstantInt(IceType_i32, 0 - Cookie);
|
| + _lea(Reg, X86OperandMem::create(Func, IceType_i32, Reg, Offset));
|
| + if (Immediate->getType() == IceType_i32) {
|
| return Reg;
|
| }
|
| - assert("Unsupported -randomize-pool-immediates option" && false);
|
| + Variable *TruncReg = makeReg(Immediate->getType(), RegNum);
|
| + _mov(TruncReg, Reg);
|
| + return TruncReg;
|
| + }
|
| + case RPI_Pool: {
|
| + // pool the constant
|
| + // FROM:
|
| + // imm
|
| + // TO:
|
| + // insert: mov $label, Reg
|
| + // => Reg
|
| + assert(Ctx->getFlags().getRandomizeAndPoolImmediatesOption() == RPI_Pool);
|
| + Immediate->setShouldBePooled(true);
|
| + // if we have already assigned a phy register, we must come from
|
| + // advancedPhiLowering()=>lowerAssign(). In this case we should reuse the
|
| + // assigned register as this assignment is that start of its use-def
|
| + // chain. So we add RegNum argument here.
|
| + Variable *Reg = makeReg(Immediate->getType(), RegNum);
|
| + IceString Label;
|
| + llvm::raw_string_ostream Label_stream(Label);
|
| + Immediate->emitPoolLabel(Label_stream, Ctx);
|
| + constexpr RelocOffsetT Offset = 0;
|
| + 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);
|
| + _mov(Reg, MemOperand);
|
| + return Reg;
|
| + }
|
| }
|
| - // the constant Immediate is not eligible for blinding/pooling
|
| - return Immediate;
|
| }
|
|
|
| template <typename TraitsType>
|
| @@ -6471,107 +6509,116 @@ TargetX86Base<TraitsType>::randomizeOrPoolImmediate(X86OperandMem *MemOperand,
|
| return MemOperand;
|
| }
|
|
|
| + if (Traits::Is64Bit && NeedSandboxing) {
|
| + // Immediate randomization/pooling is currently disabled for x86-64
|
| + // sandboxing for it could generate invalid memory operands.
|
| + assert(false &&
|
| + "Constant pooling/randomization is disabled for x8664 sandbox.");
|
| + return MemOperand;
|
| + }
|
| +
|
| // If this memory operand is already a randomized one, we do not randomize it
|
| // again.
|
| if (MemOperand->getRandomized())
|
| return MemOperand;
|
|
|
| - if (auto *C = llvm::dyn_cast_or_null<Constant>(MemOperand->getOffset())) {
|
| - if (C->shouldBeRandomizedOrPooled(Ctx)) {
|
| - // The offset of this mem operand should be blinded or pooled
|
| - Ctx->statsUpdateRPImms();
|
| - if (Ctx->getFlags().getRandomizeAndPoolImmediatesOption() ==
|
| - RPI_Randomize) {
|
| - // blind the constant offset
|
| - // FROM:
|
| - // offset[base, index, shift]
|
| - // TO:
|
| - // insert: lea offset+cookie[base], RegTemp
|
| - // => -cookie[RegTemp, index, shift]
|
| - uint32_t Value =
|
| - llvm::dyn_cast<ConstantInteger32>(MemOperand->getOffset())
|
| - ->getValue();
|
| - uint32_t Cookie = Func->getConstantBlindingCookie();
|
| - Constant *Mask1 = Ctx->getConstantInt(
|
| - MemOperand->getOffset()->getType(), Cookie + Value);
|
| - Constant *Mask2 =
|
| - Ctx->getConstantInt(MemOperand->getOffset()->getType(), 0 - Cookie);
|
| -
|
| - X86OperandMem *TempMemOperand = X86OperandMem::create(
|
| - Func, MemOperand->getType(), MemOperand->getBase(), Mask1);
|
| - // If we have already assigned a physical register, we must come from
|
| - // advancedPhiLowering()=>lowerAssign(). In this case we should reuse
|
| - // the assigned register as this assignment is that start of its
|
| - // use-def chain. So we add RegNum argument here.
|
| - Variable *RegTemp = makeReg(MemOperand->getOffset()->getType(), RegNum);
|
| - _lea(RegTemp, TempMemOperand);
|
| -
|
| - X86OperandMem *NewMemOperand = X86OperandMem::create(
|
| - Func, MemOperand->getType(), RegTemp, Mask2, MemOperand->getIndex(),
|
| - MemOperand->getShift(), MemOperand->getSegmentRegister());
|
| -
|
| - // Label this memory operand as randomized, so we won't randomize it
|
| - // again in case we call legalize() multiple times on this memory
|
| - // operand.
|
| - NewMemOperand->setRandomized(true);
|
| - return NewMemOperand;
|
| - }
|
| - if (Ctx->getFlags().getRandomizeAndPoolImmediatesOption() == RPI_Pool) {
|
| - // pool the constant offset
|
| - // FROM:
|
| - // offset[base, index, shift]
|
| - // TO:
|
| - // insert: mov $label, RegTemp
|
| - // insert: lea [base, RegTemp], RegTemp
|
| - // =>[RegTemp, index, shift]
|
| - assert(Ctx->getFlags().getRandomizeAndPoolImmediatesOption() ==
|
| - RPI_Pool);
|
| - // Memory operand should never exist as source operands in phi lowering
|
| - // assignments, so there is no need to reuse any registers here. For
|
| - // phi lowering, we should not ask for new physical registers in
|
| - // general. However, if we do meet Memory Operand during phi lowering,
|
| - // we should not blind or pool the immediates for now.
|
| - if (RegNum != Variable::NoRegister)
|
| - return MemOperand;
|
| - Variable *RegTemp = makeReg(IceType_i32);
|
| - IceString Label;
|
| - llvm::raw_string_ostream Label_stream(Label);
|
| - MemOperand->getOffset()->emitPoolLabel(Label_stream, Ctx);
|
| - MemOperand->getOffset()->setShouldBePooled(true);
|
| - constexpr RelocOffsetT SymOffset = 0;
|
| - 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;
|
| - X86OperandMem *SymbolOperand = X86OperandMem::create(
|
| - Func, MemOperand->getOffset()->getType(), Base, Symbol);
|
| - if (UseNonsfi)
|
| - SymbolOperand->setIsPIC();
|
| - _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
|
| - // base variable, we won't need this lea instruction.
|
| - if (MemOperand->getBase()) {
|
| - X86OperandMem *CalculateOperand = X86OperandMem::create(
|
| - Func, MemOperand->getType(), MemOperand->getBase(), nullptr,
|
| - RegTemp, 0, MemOperand->getSegmentRegister());
|
| - _lea(RegTemp, CalculateOperand);
|
| - }
|
| - X86OperandMem *NewMemOperand = X86OperandMem::create(
|
| - Func, MemOperand->getType(), RegTemp, nullptr,
|
| - MemOperand->getIndex(), MemOperand->getShift(),
|
| - MemOperand->getSegmentRegister());
|
| - return NewMemOperand;
|
| - }
|
| - assert("Unsupported -randomize-pool-immediates option" && false);
|
| - }
|
| + auto *C = llvm::dyn_cast_or_null<Constant>(MemOperand->getOffset());
|
| +
|
| + if (C == nullptr) {
|
| + return MemOperand;
|
| }
|
| - // the offset is not eligible for blinding or pooling, return the original
|
| - // mem operand
|
| - return MemOperand;
|
| -}
|
|
|
| + if (!C->shouldBeRandomizedOrPooled(Ctx)) {
|
| + return MemOperand;
|
| + }
|
| +
|
| + // The offset of this mem operand should be blinded or pooled
|
| + Ctx->statsUpdateRPImms();
|
| + switch (Ctx->getFlags().getRandomizeAndPoolImmediatesOption()) {
|
| + default:
|
| + llvm::report_fatal_error("Unsupported -randomize-pool-immediates option");
|
| + case RPI_Randomize: {
|
| + // blind the constant offset
|
| + // FROM:
|
| + // offset[base, index, shift]
|
| + // TO:
|
| + // insert: lea offset+cookie[base], RegTemp
|
| + // => -cookie[RegTemp, index, shift]
|
| + uint32_t Value =
|
| + llvm::dyn_cast<ConstantInteger32>(MemOperand->getOffset())->getValue();
|
| + uint32_t Cookie = Func->getConstantBlindingCookie();
|
| + Constant *Mask1 =
|
| + Ctx->getConstantInt(MemOperand->getOffset()->getType(), Cookie + Value);
|
| + Constant *Mask2 =
|
| + Ctx->getConstantInt(MemOperand->getOffset()->getType(), 0 - Cookie);
|
| +
|
| + X86OperandMem *TempMemOperand = X86OperandMem::create(
|
| + Func, MemOperand->getType(), MemOperand->getBase(), Mask1);
|
| + // If we have already assigned a physical register, we must come from
|
| + // advancedPhiLowering()=>lowerAssign(). In this case we should reuse
|
| + // the assigned register as this assignment is that start of its
|
| + // use-def chain. So we add RegNum argument here.
|
| + Variable *RegTemp = makeReg(MemOperand->getOffset()->getType(), RegNum);
|
| + _lea(RegTemp, TempMemOperand);
|
| +
|
| + X86OperandMem *NewMemOperand = X86OperandMem::create(
|
| + Func, MemOperand->getType(), RegTemp, Mask2, MemOperand->getIndex(),
|
| + MemOperand->getShift(), MemOperand->getSegmentRegister(),
|
| + MemOperand->getIsRebased());
|
| +
|
| + // Label this memory operand as randomized, so we won't randomize it
|
| + // again in case we call legalize() multiple times on this memory
|
| + // operand.
|
| + NewMemOperand->setRandomized(true);
|
| + return NewMemOperand;
|
| + }
|
| + case RPI_Pool: {
|
| + // pool the constant offset
|
| + // FROM:
|
| + // offset[base, index, shift]
|
| + // TO:
|
| + // insert: mov $label, RegTemp
|
| + // insert: lea [base, RegTemp], RegTemp
|
| + // =>[RegTemp, index, shift]
|
| +
|
| + // Memory operand should never exist as source operands in phi lowering
|
| + // assignments, so there is no need to reuse any registers here. For
|
| + // phi lowering, we should not ask for new physical registers in
|
| + // general. However, if we do meet Memory Operand during phi lowering,
|
| + // we should not blind or pool the immediates for now.
|
| + if (RegNum != Variable::NoRegister)
|
| + return MemOperand;
|
| + Variable *RegTemp = makeReg(IceType_i32);
|
| + IceString Label;
|
| + llvm::raw_string_ostream Label_stream(Label);
|
| + MemOperand->getOffset()->emitPoolLabel(Label_stream, Ctx);
|
| + MemOperand->getOffset()->setShouldBePooled(true);
|
| + constexpr RelocOffsetT SymOffset = 0;
|
| + 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;
|
| + X86OperandMem *SymbolOperand = X86OperandMem::create(
|
| + Func, MemOperand->getOffset()->getType(), Base, Symbol, IsRebased);
|
| + _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
|
| + // base variable, we won't need this lea instruction.
|
| + if (MemOperand->getBase()) {
|
| + X86OperandMem *CalculateOperand = X86OperandMem::create(
|
| + Func, MemOperand->getType(), MemOperand->getBase(), nullptr, RegTemp,
|
| + 0, MemOperand->getSegmentRegister());
|
| + _lea(RegTemp, CalculateOperand);
|
| + }
|
| + X86OperandMem *NewMemOperand = X86OperandMem::create(
|
| + Func, MemOperand->getType(), RegTemp, nullptr, MemOperand->getIndex(),
|
| + MemOperand->getShift(), MemOperand->getSegmentRegister());
|
| + return NewMemOperand;
|
| + }
|
| + }
|
| +}
|
| } // end of namespace X86NAMESPACE
|
| } // end of namespace Ice
|
|
|
|
|