Commit ac2388c3 by John Porto

Subzero. X86. Refactors Address Mode formation.

Refactors the Address Mode optimization interface. BUG= R=stichnot@chromium.org Review URL: https://codereview.chromium.org/1605103002 .
parent 6b80cf10
...@@ -270,7 +270,9 @@ TargetX8664Traits::Address TargetX8664Traits::X86OperandMem::toAsmAddress( ...@@ -270,7 +270,9 @@ TargetX8664Traits::Address TargetX8664Traits::X86OperandMem::toAsmAddress(
const bool NeedSandboxing = Target->needSandboxing(); const bool NeedSandboxing = Target->needSandboxing();
(void)NeedSandboxing; (void)NeedSandboxing;
assert(!NeedSandboxing || IsLeaAddr || assert(!NeedSandboxing || IsLeaAddr ||
(getBase()->getRegNum() == Traits::RegisterSet::Reg_r15)); (getBase()->getRegNum() == Traits::RegisterSet::Reg_r15) ||
(getBase()->getRegNum() == Traits::RegisterSet::Reg_rsp) ||
(getBase()->getRegNum() == Traits::RegisterSet::Reg_rbp));
return X8664::Traits::Address(getEncodedGPR(getBase()->getRegNum()), return X8664::Traits::Address(getEncodedGPR(getBase()->getRegNum()),
getEncodedGPR(getIndex()->getRegNum()), getEncodedGPR(getIndex()->getRegNum()),
X8664::Traits::ScaleFactor(getShift()), Disp, X8664::Traits::ScaleFactor(getShift()), Disp,
......
...@@ -245,8 +245,21 @@ void TargetLowering::staticInit(GlobalContext *Ctx) { ...@@ -245,8 +245,21 @@ void TargetLowering::staticInit(GlobalContext *Ctx) {
} }
} }
TargetLowering::SandboxType
TargetLowering::determineSandboxTypeFromFlags(const ClFlags &Flags) {
assert(!Flags.getUseSandboxing() || !Flags.getUseNonsfi());
if (Flags.getUseNonsfi()) {
return TargetLowering::ST_Nonsfi;
}
if (Flags.getUseSandboxing()) {
return TargetLowering::ST_NaCl;
}
return TargetLowering::ST_None;
}
TargetLowering::TargetLowering(Cfg *Func) TargetLowering::TargetLowering(Cfg *Func)
: Func(Func), Ctx(Func->getContext()), Context() {} : Func(Func), Ctx(Func->getContext()),
SandboxingType(determineSandboxTypeFromFlags(Ctx->getFlags())) {}
TargetLowering::AutoBundle::AutoBundle(TargetLowering *Target, TargetLowering::AutoBundle::AutoBundle(TargetLowering *Target,
InstBundleLock::Option Option) InstBundleLock::Option Option)
......
...@@ -455,6 +455,15 @@ protected: ...@@ -455,6 +455,15 @@ protected:
bool shouldOptimizeMemIntrins(); bool shouldOptimizeMemIntrins();
/// SandboxType enumerates all possible sandboxing strategies that
enum SandboxType {
ST_None,
ST_NaCl,
ST_Nonsfi,
};
static SandboxType determineSandboxTypeFromFlags(const ClFlags &Flags);
Cfg *Func; Cfg *Func;
GlobalContext *Ctx; GlobalContext *Ctx;
bool HasComputedFrame = false; bool HasComputedFrame = false;
...@@ -462,6 +471,7 @@ protected: ...@@ -462,6 +471,7 @@ protected:
SizeT NextLabelNumber = 0; SizeT NextLabelNumber = 0;
SizeT NextJumpTableNumber = 0; SizeT NextJumpTableNumber = 0;
LoweringContext Context; LoweringContext Context;
const SandboxType SandboxingType = ST_None;
// Runtime helper function names // Runtime helper function names
const static constexpr char *H_bitcast_16xi1_i16 = "__Sz_bitcast_16xi1_i16"; const static constexpr char *H_bitcast_16xi1_i16 = "__Sz_bitcast_16xi1_i16";
......
...@@ -274,7 +274,7 @@ std::array<uint32_t, NumVec128Args> Vec128ArgInitializer; ...@@ -274,7 +274,7 @@ std::array<uint32_t, NumVec128Args> Vec128ArgInitializer;
} // end of anonymous namespace } // end of anonymous namespace
TargetARM32::TargetARM32(Cfg *Func) TargetARM32::TargetARM32(Cfg *Func)
: TargetLowering(Func), NeedSandboxing(Ctx->getFlags().getUseSandboxing()), : TargetLowering(Func), NeedSandboxing(SandboxingType == ST_NaCl),
CPUFeatures(Func->getContext()->getFlags()) {} CPUFeatures(Func->getContext()->getFlags()) {}
void TargetARM32::staticInit(GlobalContext *Ctx) { void TargetARM32::staticInit(GlobalContext *Ctx) {
......
...@@ -137,6 +137,45 @@ void TargetX8632::_mov_sp(Operand *NewValue) { ...@@ -137,6 +137,45 @@ void TargetX8632::_mov_sp(Operand *NewValue) {
_redefined(_mov(esp, NewValue)); _redefined(_mov(esp, NewValue));
} }
Traits::X86OperandMem *TargetX8632::_sandbox_mem_reference(X86OperandMem *Mem) {
switch (SandboxingType) {
case ST_None:
case ST_NaCl:
return Mem;
case ST_Nonsfi: {
if (Mem->getIsRebased()) {
return Mem;
}
// For Non-SFI mode, if the Offset field is a ConstantRelocatable, we
// replace either Base or Index with a legalized RebasePtr. At emission
// time, the ConstantRelocatable will be emitted with the @GOTOFF
// relocation.
if (llvm::dyn_cast_or_null<ConstantRelocatable>(Mem->getOffset()) ==
nullptr) {
return Mem;
}
Variable *T;
uint16_t Shift = 0;
if (Mem->getIndex() == nullptr) {
T = Mem->getBase();
} else if (Mem->getBase() == nullptr) {
T = Mem->getIndex();
Shift = Mem->getShift();
} else {
llvm::report_fatal_error(
"Either Base or Index must be unused in Non-SFI mode");
}
Variable *RebasePtrR = legalizeToReg(RebasePtr);
static constexpr bool IsRebased = true;
return Traits::X86OperandMem::create(
Func, Mem->getType(), RebasePtrR, Mem->getOffset(), T, Shift,
Traits::X86OperandMem::DefaultSegment, IsRebased);
}
}
llvm::report_fatal_error("Unhandled sandboxing type: " +
std::to_string(SandboxingType));
}
void TargetX8632::_sub_sp(Operand *Adjustment) { void TargetX8632::_sub_sp(Operand *Adjustment) {
Variable *esp = getPhysicalRegister(Traits::RegisterSet::Reg_esp); Variable *esp = getPhysicalRegister(Traits::RegisterSet::Reg_esp);
_sub(esp, Adjustment); _sub(esp, Adjustment);
...@@ -215,6 +254,47 @@ void TargetX8632::lowerIndirectJump(Variable *JumpTarget) { ...@@ -215,6 +254,47 @@ void TargetX8632::lowerIndirectJump(Variable *JumpTarget) {
_jmp(JumpTarget); _jmp(JumpTarget);
} }
void TargetX8632::initRebasePtr() {
if (SandboxingType == ST_Nonsfi) {
RebasePtr = Func->makeVariable(IceType_i32);
}
}
void TargetX8632::initSandbox() {
if (SandboxingType != ST_Nonsfi) {
return;
}
// Insert the RebasePtr 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<Traits::Insts::GetIP>(RebasePtr);
}
bool TargetX8632::legalizeOptAddrForSandbox(OptAddr *Addr) {
if (Addr->Relocatable == nullptr || SandboxingType != ST_Nonsfi) {
return true;
}
if (Addr->Base == RebasePtr || Addr->Index == RebasePtr) {
return true;
}
if (Addr->Base == nullptr) {
Addr->Base = RebasePtr;
return true;
}
if (Addr->Index == nullptr) {
Addr->Index = RebasePtr;
Addr->Shift = 0;
return true;
}
return false;
}
Inst *TargetX8632::emitCallToTarget(Operand *CallTarget, Variable *ReturnReg) { Inst *TargetX8632::emitCallToTarget(Operand *CallTarget, Variable *ReturnReg) {
std::unique_ptr<AutoBundle> Bundle; std::unique_ptr<AutoBundle> Bundle;
if (NeedSandboxing) { if (NeedSandboxing) {
......
...@@ -48,15 +48,15 @@ public: ...@@ -48,15 +48,15 @@ public:
protected: protected:
void _add_sp(Operand *Adjustment); void _add_sp(Operand *Adjustment);
void _mov_sp(Operand *NewValue); void _mov_sp(Operand *NewValue);
Traits::X86OperandMem *_sandbox_mem_reference(X86OperandMem *) { Traits::X86OperandMem *_sandbox_mem_reference(X86OperandMem *Mem);
llvm::report_fatal_error("sandbox mem reference for x86-32.");
}
void _sub_sp(Operand *Adjustment); void _sub_sp(Operand *Adjustment);
void _link_bp(); void _link_bp();
void _unlink_bp(); void _unlink_bp();
void _push_reg(Variable *Reg); void _push_reg(Variable *Reg);
void initSandbox() {} void initRebasePtr();
void initSandbox();
bool legalizeOptAddrForSandbox(OptAddr *Addr);
void emitSandboxedReturn(); void emitSandboxedReturn();
void lowerIndirectJump(Variable *JumpTarget); void lowerIndirectJump(Variable *JumpTarget);
void emitGetIP(CfgNode *Node); void emitGetIP(CfgNode *Node);
......
...@@ -298,34 +298,49 @@ Traits::X86OperandMem *TargetX8664::_sandbox_mem_reference(X86OperandMem *Mem) { ...@@ -298,34 +298,49 @@ Traits::X86OperandMem *TargetX8664::_sandbox_mem_reference(X86OperandMem *Mem) {
// In x86_64-nacl, all memory references are relative to %r15 (i.e., %rzp.) // In x86_64-nacl, all memory references are relative to %r15 (i.e., %rzp.)
// NaCl sandboxing also requires that any registers that are not %rsp and // NaCl sandboxing also requires that any registers that are not %rsp and
// %rbp to be 'truncated' to 32-bit before memory access. // %rbp to be 'truncated' to 32-bit before memory access.
assert(NeedSandboxing); if (SandboxingType == ST_None) {
return Mem;
}
if (SandboxingType == ST_Nonsfi) {
llvm::report_fatal_error(
"_sandbox_mem_reference not implemented for nonsfi");
}
Variable *Base = Mem->getBase(); Variable *Base = Mem->getBase();
Variable *Index = Mem->getIndex(); Variable *Index = Mem->getIndex();
uint16_t Shift = 0; uint16_t Shift = 0;
Variable *r15 = Variable *ZeroReg =
getPhysicalRegister(Traits::RegisterSet::Reg_r15, IceType_i64); getPhysicalRegister(Traits::RegisterSet::Reg_r15, IceType_i64);
Constant *Offset = Mem->getOffset(); Constant *Offset = Mem->getOffset();
Variable *T = nullptr; Variable *T = nullptr;
if (Mem->getIsRebased()) { if (Mem->getIsRebased()) {
// If Mem.IsRebased, then we don't need to update Mem to contain a reference // If Mem.IsRebased, then we don't need to update Mem to contain a reference
// to %r15, but we still need to truncate Mem.Index (if any) to 32-bit. // to a valid base register (%r15, %rsp, or %rbp), but we still need to
assert(r15 == Base); // truncate Mem.Index (if any) to 32-bit.
T = Index; assert(ZeroReg == Base || Base->isRematerializable());
T = makeReg(IceType_i32);
_mov(T, Index);
Shift = Mem->getShift(); Shift = Mem->getShift();
} else if (Base != nullptr && Index != nullptr) { } else {
// Another approach could be to emit an if (Base != nullptr) {
// if (Base->isRematerializable()) {
// lea Mem, %T ZeroReg = Base;
// } else {
// And then update Mem.Base = r15, Mem.Index = T, Mem.Shift = 0
llvm::report_fatal_error("memory reference contains base and index.");
} else if (Base != nullptr) {
T = Base; T = Base;
} else if (Index != nullptr) { }
}
if (Index != nullptr) {
assert(!Index->isRematerializable());
if (T != nullptr) {
llvm::report_fatal_error("memory reference contains base and index.");
}
T = Index; T = Index;
Shift = Mem->getShift(); Shift = Mem->getShift();
} }
}
// NeedsLea is a flags indicating whether Mem needs to be materialized to a // NeedsLea is a flags indicating whether Mem needs to be materialized to a
// GPR prior to being used. A LEA is needed if Mem.Offset is a constant // GPR prior to being used. A LEA is needed if Mem.Offset is a constant
...@@ -399,7 +414,7 @@ Traits::X86OperandMem *TargetX8664::_sandbox_mem_reference(X86OperandMem *Mem) { ...@@ -399,7 +414,7 @@ Traits::X86OperandMem *TargetX8664::_sandbox_mem_reference(X86OperandMem *Mem) {
static constexpr bool IsRebased = true; static constexpr bool IsRebased = true;
return Traits::X86OperandMem::create( return Traits::X86OperandMem::create(
Func, Mem->getType(), r15, Offset, T, Shift, Func, Mem->getType(), ZeroReg, Offset, T, Shift,
Traits::X86OperandMem::DefaultSegment, IsRebased); Traits::X86OperandMem::DefaultSegment, IsRebased);
} }
...@@ -427,8 +442,23 @@ void TargetX8664::_sub_sp(Operand *Adjustment) { ...@@ -427,8 +442,23 @@ void TargetX8664::_sub_sp(Operand *Adjustment) {
_add(rsp, r15); _add(rsp, r15);
} }
void TargetX8664::initRebasePtr() {
switch (SandboxingType) {
case ST_Nonsfi:
// Probably no implementation is needed, but error to be safe for now.
llvm::report_fatal_error(
"initRebasePtr() is not yet implemented on x32-nonsfi.");
case ST_NaCl:
RebasePtr = getPhysicalRegister(Traits::RegisterSet::Reg_r15, IceType_i64);
break;
case ST_None:
// nothing.
break;
}
}
void TargetX8664::initSandbox() { void TargetX8664::initSandbox() {
assert(NeedSandboxing); assert(SandboxingType == ST_NaCl);
Context.init(Func->getEntryNode()); Context.init(Func->getEntryNode());
Context.setInsertPoint(Context.getCur()); Context.setInsertPoint(Context.getCur());
Variable *r15 = Variable *r15 =
...@@ -437,6 +467,45 @@ void TargetX8664::initSandbox() { ...@@ -437,6 +467,45 @@ void TargetX8664::initSandbox() {
Context.insert<InstFakeUse>(r15); Context.insert<InstFakeUse>(r15);
} }
namespace {
bool isRematerializable(const Variable *Var) {
return Var != nullptr && Var->isRematerializable();
}
} // end of anonymous namespace
bool TargetX8664::legalizeOptAddrForSandbox(OptAddr *Addr) {
if (SandboxingType == ST_Nonsfi) {
llvm::report_fatal_error("Nonsfi not yet implemented for x8664.");
}
if (isRematerializable(Addr->Base)) {
if (Addr->Index == RebasePtr) {
Addr->Index = nullptr;
Addr->Shift = 0;
}
return true;
}
if (isRematerializable(Addr->Index)) {
if (Addr->Base == RebasePtr) {
Addr->Base = nullptr;
}
return true;
}
assert(Addr->Base != RebasePtr && Addr->Index != RebasePtr);
if (Addr->Base == nullptr) {
return true;
}
if (Addr->Index == nullptr) {
return true;
}
return false;
}
void TargetX8664::lowerIndirectJump(Variable *JumpTarget) { void TargetX8664::lowerIndirectJump(Variable *JumpTarget) {
std::unique_ptr<AutoBundle> Bundler; std::unique_ptr<AutoBundle> Bundler;
......
...@@ -55,7 +55,9 @@ protected: ...@@ -55,7 +55,9 @@ protected:
void _unlink_bp(); void _unlink_bp();
void _push_reg(Variable *Reg); void _push_reg(Variable *Reg);
void initRebasePtr();
void initSandbox(); void initSandbox();
bool legalizeOptAddrForSandbox(OptAddr *Addr);
void emitSandboxedReturn(); void emitSandboxedReturn();
void lowerIndirectJump(Variable *JumpTarget); void lowerIndirectJump(Variable *JumpTarget);
void emitGetIP(CfgNode *Node); void emitGetIP(CfgNode *Node);
......
...@@ -194,7 +194,17 @@ protected: ...@@ -194,7 +194,17 @@ protected:
void postLower() override; void postLower() override;
/// Initializes the RebasePtr member variable -- if so required by
/// SandboxingType for the concrete Target.
void initRebasePtr() {
assert(SandboxingType != ST_None);
dispatchToConcrete(&Traits::ConcreteTarget::initRebasePtr);
}
/// Emit code that initializes the value of the RebasePtr near the start of
/// the function -- if so required by SandboxingType for the concrete type.
void initSandbox() { void initSandbox() {
assert(SandboxingType != ST_None);
dispatchToConcrete(&Traits::ConcreteTarget::initSandbox); dispatchToConcrete(&Traits::ConcreteTarget::initSandbox);
} }
...@@ -225,6 +235,25 @@ protected: ...@@ -225,6 +235,25 @@ protected:
Type ReturnType); Type ReturnType);
uint32_t getCallStackArgumentsSizeBytes(const InstCall *Instr) override; uint32_t getCallStackArgumentsSizeBytes(const InstCall *Instr) override;
void genTargetHelperCallFor(Inst *Instr) override; void genTargetHelperCallFor(Inst *Instr) override;
/// OptAddr wraps all the possible operands that an x86 address might have.
struct OptAddr {
Variable *Base = nullptr;
Variable *Index = nullptr;
uint16_t Shift = 0;
int32_t Offset = 0;
ConstantRelocatable *Relocatable = nullptr;
};
/// Legalizes Addr w.r.t. SandboxingType. The exact type of legalization
/// varies for different <Target, SandboxingType> tuples.
bool legalizeOptAddrForSandbox(OptAddr *Addr) {
return dispatchToConcrete(
&Traits::ConcreteTarget::legalizeOptAddrForSandbox, std::move(Addr));
}
// Builds information for a canonical address expresion:
// <Relocatable + Offset>(Base, Index, Shift)
X86OperandMem *computeAddressOpt(const Inst *Instr, Type MemType,
Operand *Addr);
void doAddressOptLoad() override; void doAddressOptLoad() override;
void doAddressOptStore() override; void doAddressOptStore() override;
void doMockBoundsCheck(Operand *Opnd) override; void doMockBoundsCheck(Operand *Opnd) override;
...@@ -322,7 +351,7 @@ protected: ...@@ -322,7 +351,7 @@ protected:
Legal_Imm = 1 << 1, Legal_Imm = 1 << 1,
Legal_Mem = 1 << 2, // includes [eax+4*ecx] as well as [esp+12] Legal_Mem = 1 << 2, // includes [eax+4*ecx] as well as [esp+12]
Legal_Rematerializable = 1 << 3, Legal_Rematerializable = 1 << 3,
Legal_AddrAbs = 1 << 4, // ConstantRelocatable doesn't have to add GotVar Legal_AddrAbs = 1 << 4, // ConstantRelocatable doesn't have to add RebasePtr
Legal_Default = ~(Legal_Rematerializable | Legal_AddrAbs) Legal_Default = ~(Legal_Rematerializable | Legal_AddrAbs)
// TODO(stichnot): Figure out whether this default works for x86-64. // TODO(stichnot): Figure out whether this default works for x86-64.
}; };
...@@ -410,9 +439,7 @@ protected: ...@@ -410,9 +439,7 @@ protected:
template <typename... T> template <typename... T>
AutoMemorySandboxer(typename Traits::TargetLowering *Target, T... Args) AutoMemorySandboxer(typename Traits::TargetLowering *Target, T... Args)
: Target(Target), : Target(Target), MemOperand(Target->SandboxingType == ST_None
MemOperand(
(!Traits::Is64Bit || !Target->Ctx->getFlags().getUseSandboxing())
? nullptr ? nullptr
: findMemoryReference(Args...)) { : findMemoryReference(Args...)) {
if (MemOperand != nullptr) { if (MemOperand != nullptr) {
...@@ -932,9 +959,9 @@ protected: ...@@ -932,9 +959,9 @@ protected:
RegisterAliases; RegisterAliases;
llvm::SmallBitVector RegsUsed; llvm::SmallBitVector RegsUsed;
std::array<VarList, IceType_NUM> PhysicalRegisters; std::array<VarList, IceType_NUM> PhysicalRegisters;
// GotVar is a Variable that holds the GlobalOffsetTable address for Non-SFI // RebasePtr is a Variable that holds the Rebasing pointer (if any) for the
// mode. // current sandboxing type.
Variable *GotVar = nullptr; Variable *RebasePtr = nullptr;
/// Randomize a given immediate operand /// Randomize a given immediate operand
Operand *randomizeOrPoolImmediate(Constant *Immediate, Operand *randomizeOrPoolImmediate(Constant *Immediate,
...@@ -1002,10 +1029,6 @@ private: ...@@ -1002,10 +1029,6 @@ private:
/// Optimizations for idiom recognition. /// Optimizations for idiom recognition.
bool lowerOptimizeFcmpSelect(const InstFcmp *Fcmp, const InstSelect *Select); bool lowerOptimizeFcmpSelect(const InstFcmp *Fcmp, const InstSelect *Select);
/// Emit code that initializes the value of the GotVar near the start of the
/// function. (This code is emitted only in Non-SFI mode.)
void initGotVarIfNeeded();
/// Complains loudly if invoked because the cpu can handle 64-bit types /// Complains loudly if invoked because the cpu can handle 64-bit types
/// natively. /// natively.
template <typename T = Traits> template <typename T = Traits>
......
...@@ -360,7 +360,7 @@ void TargetX86Base<TraitsType>::initNodeForLowering(CfgNode *Node) { ...@@ -360,7 +360,7 @@ void TargetX86Base<TraitsType>::initNodeForLowering(CfgNode *Node) {
template <typename TraitsType> template <typename TraitsType>
TargetX86Base<TraitsType>::TargetX86Base(Cfg *Func) TargetX86Base<TraitsType>::TargetX86Base(Cfg *Func)
: TargetLowering(Func), NeedSandboxing(Ctx->getFlags().getUseSandboxing()) { : TargetLowering(Func), NeedSandboxing(SandboxingType == ST_NaCl) {
static_assert( static_assert(
(Traits::InstructionSet::End - Traits::InstructionSet::Begin) == (Traits::InstructionSet::End - Traits::InstructionSet::Begin) ==
(TargetInstructionSet::X86InstructionSet_End - (TargetInstructionSet::X86InstructionSet_End -
...@@ -390,12 +390,8 @@ void TargetX86Base<TraitsType>::staticInit(GlobalContext *Ctx) { ...@@ -390,12 +390,8 @@ void TargetX86Base<TraitsType>::staticInit(GlobalContext *Ctx) {
template <typename TraitsType> void TargetX86Base<TraitsType>::translateO2() { template <typename TraitsType> void TargetX86Base<TraitsType>::translateO2() {
TimerMarker T(TimerStack::TT_O2, Func); TimerMarker T(TimerStack::TT_O2, Func);
if (!Traits::Is64Bit && Func->getContext()->getFlags().getUseNonsfi()) { if (SandboxingType != ST_None) {
GotVar = Func->makeVariable(IceType_i32); initRebasePtr();
}
if (NeedSandboxing) {
initSandbox();
} }
genTargetHelperCalls(); genTargetHelperCalls();
...@@ -466,7 +462,9 @@ template <typename TraitsType> void TargetX86Base<TraitsType>::translateO2() { ...@@ -466,7 +462,9 @@ template <typename TraitsType> void TargetX86Base<TraitsType>::translateO2() {
Func->genCode(); Func->genCode();
if (Func->hasError()) if (Func->hasError())
return; return;
initGotVarIfNeeded(); if (SandboxingType != ST_None) {
initSandbox();
}
Func->dump("After x86 codegen"); Func->dump("After x86 codegen");
// Register allocation. This requires instruction renumbering and full // Register allocation. This requires instruction renumbering and full
...@@ -526,12 +524,8 @@ template <typename TraitsType> void TargetX86Base<TraitsType>::translateO2() { ...@@ -526,12 +524,8 @@ template <typename TraitsType> void TargetX86Base<TraitsType>::translateO2() {
template <typename TraitsType> void TargetX86Base<TraitsType>::translateOm1() { template <typename TraitsType> void TargetX86Base<TraitsType>::translateOm1() {
TimerMarker T(TimerStack::TT_Om1, Func); TimerMarker T(TimerStack::TT_Om1, Func);
if (!Traits::Is64Bit && Func->getContext()->getFlags().getUseNonsfi()) { if (SandboxingType != ST_None) {
GotVar = Func->makeVariable(IceType_i32); initRebasePtr();
}
if (NeedSandboxing) {
initSandbox();
} }
genTargetHelperCalls(); genTargetHelperCalls();
...@@ -556,7 +550,9 @@ template <typename TraitsType> void TargetX86Base<TraitsType>::translateOm1() { ...@@ -556,7 +550,9 @@ template <typename TraitsType> void TargetX86Base<TraitsType>::translateOm1() {
Func->genCode(); Func->genCode();
if (Func->hasError()) if (Func->hasError())
return; return;
initGotVarIfNeeded(); if (SandboxingType != ST_None) {
initSandbox();
}
Func->dump("After initial x8632 codegen"); Func->dump("After initial x8632 codegen");
regAlloc(RAK_InfOnly); regAlloc(RAK_InfOnly);
...@@ -1381,23 +1377,6 @@ TargetX86Base<TraitsType>::getRegisterSet(RegSetMask Include, ...@@ -1381,23 +1377,6 @@ TargetX86Base<TraitsType>::getRegisterSet(RegSetMask Include,
} }
template <typename TraitsType> 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) { void TargetX86Base<TraitsType>::lowerAlloca(const InstAlloca *Inst) {
// Conservatively require the stack to be aligned. Some stack adjustment // Conservatively require the stack to be aligned. Some stack adjustment
// operations implemented below assume that the stack is aligned before the // operations implemented below assume that the stack is aligned before the
...@@ -4968,18 +4947,49 @@ void TargetX86Base<TraitsType>::lowerMemset(Operand *Dest, Operand *Val, ...@@ -4968,18 +4947,49 @@ void TargetX86Base<TraitsType>::lowerMemset(Operand *Dest, Operand *Val,
lowerCall(Call); lowerCall(Call);
} }
inline bool isAdd(const Inst *Inst) { 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)) { if (auto *Arith = llvm::dyn_cast_or_null<const InstArithmetic>(Inst)) {
return (Arith->getOp() == InstArithmetic::Add); return (Arith->getOp() == InstArithmetic::Add);
} }
return false; return false;
} }
};
inline void dumpAddressOpt(const Cfg *Func, void AddressOptimizer::dumpAddressOpt(
const ConstantRelocatable *Relocatable, const ConstantRelocatable *const Relocatable, int32_t Offset,
int32_t Offset, const Variable *Base, const Variable *Base, const Variable *Index, uint16_t Shift,
const Variable *Index, uint16_t Shift, const Inst *Reason) const {
const Inst *Reason) {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
if (!Func->isVerbose(IceV_AddrOpt)) if (!Func->isVerbose(IceV_AddrOpt))
...@@ -5002,14 +5012,14 @@ inline void dumpAddressOpt(const Cfg *Func, ...@@ -5002,14 +5012,14 @@ inline void dumpAddressOpt(const Cfg *Func,
<< ", Relocatable=" << Relocatable << "\n"; << ", Relocatable=" << Relocatable << "\n";
} }
inline bool matchAssign(const VariablesMetadata *VMetadata, Variable *GotVar, const Inst *AddressOptimizer::matchAssign(Variable **Var,
Variable *&Var, ConstantRelocatable *&Relocatable, ConstantRelocatable **Relocatable,
int32_t &Offset, const Inst *&Reason) { int32_t *Offset) {
// Var originates from Var=SrcVar ==> set Var:=SrcVar // Var originates from Var=SrcVar ==> set Var:=SrcVar
if (Var == nullptr) if (*Var == nullptr)
return false; return nullptr;
if (const Inst *VarAssign = VMetadata->getSingleDefinition(Var)) { if (const Inst *VarAssign = VMetadata->getSingleDefinition(*Var)) {
assert(!VMetadata->isMultiDef(Var)); assert(!VMetadata->isMultiDef(*Var));
if (llvm::isa<InstAssign>(VarAssign)) { if (llvm::isa<InstAssign>(VarAssign)) {
Operand *SrcOp = VarAssign->getSrc(0); Operand *SrcOp = VarAssign->getSrc(0);
assert(SrcOp); assert(SrcOp);
...@@ -5017,88 +5027,86 @@ inline bool matchAssign(const VariablesMetadata *VMetadata, Variable *GotVar, ...@@ -5017,88 +5027,86 @@ inline bool matchAssign(const VariablesMetadata *VMetadata, Variable *GotVar,
if (!VMetadata->isMultiDef(SrcVar) && if (!VMetadata->isMultiDef(SrcVar) &&
// TODO: ensure SrcVar stays single-BB // TODO: ensure SrcVar stays single-BB
true) { true) {
Var = SrcVar; *Var = SrcVar;
Reason = VarAssign; return VarAssign;
return true;
} }
} else if (auto *Const = llvm::dyn_cast<ConstantInteger32>(SrcOp)) { } else if (auto *Const = llvm::dyn_cast<ConstantInteger32>(SrcOp)) {
int32_t MoreOffset = Const->getValue(); int32_t MoreOffset = Const->getValue();
if (Utils::WouldOverflowAdd(Offset, MoreOffset)) if (Utils::WouldOverflowAdd(*Offset, MoreOffset))
return false; return nullptr;
Var = nullptr; *Var = nullptr;
Offset += MoreOffset; Offset += MoreOffset;
Reason = VarAssign; return VarAssign;
return true;
} else if (auto *AddReloc = llvm::dyn_cast<ConstantRelocatable>(SrcOp)) { } else if (auto *AddReloc = llvm::dyn_cast<ConstantRelocatable>(SrcOp)) {
if (Relocatable == nullptr) { if (*Relocatable == nullptr) {
Var = GotVar; // It is always safe to fold a relocatable through assignment -- the
Relocatable = AddReloc; // assignment frees a slot in the address operand that can be used to
Reason = VarAssign; // hold the Sandbox Pointer -- if any.
return true; *Var = nullptr;
*Relocatable = AddReloc;
return VarAssign;
} }
} }
} }
} }
return false; return nullptr;
} }
inline bool matchCombinedBaseIndex(const VariablesMetadata *VMetadata, const Inst *AddressOptimizer::matchCombinedBaseIndex(Variable **Base,
Variable *&Base, Variable *&Index, Variable **Index,
uint16_t &Shift, const Inst *&Reason) { uint16_t *Shift) {
// Index==nullptr && Base is Base=Var1+Var2 ==> // Index==nullptr && Base is Base=Var1+Var2 ==>
// set Base=Var1, Index=Var2, Shift=0 // set Base=Var1, Index=Var2, Shift=0
if (Base == nullptr) if (*Base == nullptr)
return false; return nullptr;
if (Index != nullptr) if (*Index != nullptr)
return false; return nullptr;
auto *BaseInst = VMetadata->getSingleDefinition(Base); auto *BaseInst = VMetadata->getSingleDefinition(*Base);
if (BaseInst == nullptr) if (BaseInst == nullptr)
return false; return nullptr;
assert(!VMetadata->isMultiDef(Base)); assert(!VMetadata->isMultiDef(*Base));
if (BaseInst->getSrcSize() < 2) if (BaseInst->getSrcSize() < 2)
return false; return nullptr;
if (auto *Var1 = llvm::dyn_cast<Variable>(BaseInst->getSrc(0))) { if (auto *Var1 = llvm::dyn_cast<Variable>(BaseInst->getSrc(0))) {
if (VMetadata->isMultiDef(Var1)) if (VMetadata->isMultiDef(Var1))
return false; return nullptr;
if (auto *Var2 = llvm::dyn_cast<Variable>(BaseInst->getSrc(1))) { if (auto *Var2 = llvm::dyn_cast<Variable>(BaseInst->getSrc(1))) {
if (VMetadata->isMultiDef(Var2)) if (VMetadata->isMultiDef(Var2))
return false; return nullptr;
if (isAdd(BaseInst) && if (isAdd(BaseInst) &&
// TODO: ensure Var1 and Var2 stay single-BB // TODO: ensure Var1 and Var2 stay single-BB
true) { true) {
Base = Var1; *Base = Var1;
Index = Var2; *Index = Var2;
Shift = 0; // should already have been 0 *Shift = 0; // should already have been 0
Reason = BaseInst; return BaseInst;
return true;
} }
} }
} }
return false; return nullptr;
} }
inline bool matchShiftedIndex(const VariablesMetadata *VMetadata, const Inst *AddressOptimizer::matchShiftedIndex(Variable **Index,
Variable *&Index, uint16_t &Shift, uint16_t *Shift) {
const Inst *&Reason) {
// Index is Index=Var*Const && log2(Const)+Shift<=3 ==> // Index is Index=Var*Const && log2(Const)+Shift<=3 ==>
// Index=Var, Shift+=log2(Const) // Index=Var, Shift+=log2(Const)
if (Index == nullptr) if (*Index == nullptr)
return false; return nullptr;
auto *IndexInst = VMetadata->getSingleDefinition(Index); auto *IndexInst = VMetadata->getSingleDefinition(*Index);
if (IndexInst == nullptr) if (IndexInst == nullptr)
return false; return nullptr;
assert(!VMetadata->isMultiDef(Index)); assert(!VMetadata->isMultiDef(*Index));
if (IndexInst->getSrcSize() < 2) if (IndexInst->getSrcSize() < 2)
return false; return nullptr;
if (auto *ArithInst = llvm::dyn_cast<InstArithmetic>(IndexInst)) { if (auto *ArithInst = llvm::dyn_cast<InstArithmetic>(IndexInst)) {
if (auto *Var = llvm::dyn_cast<Variable>(ArithInst->getSrc(0))) { if (auto *Var = llvm::dyn_cast<Variable>(ArithInst->getSrc(0))) {
if (auto *Const = if (auto *Const =
llvm::dyn_cast<ConstantInteger32>(ArithInst->getSrc(1))) { llvm::dyn_cast<ConstantInteger32>(ArithInst->getSrc(1))) {
if (VMetadata->isMultiDef(Var) || Const->getType() != IceType_i32) if (VMetadata->isMultiDef(Var) || Const->getType() != IceType_i32)
return false; return nullptr;
switch (ArithInst->getOp()) { switch (ArithInst->getOp()) {
default: default:
return false; return nullptr;
case InstArithmetic::Mul: { case InstArithmetic::Mul: {
uint32_t Mult = Const->getValue(); uint32_t Mult = Const->getValue();
uint32_t LogMult; uint32_t LogMult;
...@@ -5116,13 +5124,12 @@ inline bool matchShiftedIndex(const VariablesMetadata *VMetadata, ...@@ -5116,13 +5124,12 @@ inline bool matchShiftedIndex(const VariablesMetadata *VMetadata,
LogMult = 3; LogMult = 3;
break; break;
default: default:
return false; return nullptr;
} }
if (Shift + LogMult <= 3) { if (*Shift + LogMult <= 3) {
Index = Var; *Index = Var;
Shift += LogMult; *Shift += LogMult;
Reason = IndexInst; return IndexInst;
return true;
} }
} }
case InstArithmetic::Shl: { case InstArithmetic::Shl: {
...@@ -5134,43 +5141,40 @@ inline bool matchShiftedIndex(const VariablesMetadata *VMetadata, ...@@ -5134,43 +5141,40 @@ inline bool matchShiftedIndex(const VariablesMetadata *VMetadata,
case 3: case 3:
break; break;
default: default:
return false; return nullptr;
} }
if (Shift + ShiftAmount <= 3) { if (*Shift + ShiftAmount <= 3) {
Index = Var; *Index = Var;
Shift += ShiftAmount; *Shift += ShiftAmount;
Reason = IndexInst; return IndexInst;
return true;
} }
} }
} }
} }
} }
} }
return false; return nullptr;
} }
inline bool matchOffsetBase(const VariablesMetadata *VMetadata, const Inst *AddressOptimizer::matchOffsetBase(Variable **Base,
Variable *GotVar, Variable *&Base, ConstantRelocatable **Relocatable,
Variable *&BaseOther, int32_t *Offset) {
ConstantRelocatable *&Relocatable, int32_t &Offset,
const Inst *&Reason) {
// Base is Base=Var+Const || Base is Base=Const+Var ==> // Base is Base=Var+Const || Base is Base=Const+Var ==>
// set Base=Var, Offset+=Const // set Base=Var, Offset+=Const
// Base is Base=Var-Const ==> // Base is Base=Var-Const ==>
// set Base=Var, Offset-=Const // set Base=Var, Offset-=Const
if (Base == nullptr) { if (*Base == nullptr) {
return false; return nullptr;
} }
const Inst *BaseInst = VMetadata->getSingleDefinition(Base); const Inst *BaseInst = VMetadata->getSingleDefinition(*Base);
if (BaseInst == nullptr) { 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 (auto *ArithInst = llvm::dyn_cast<const InstArithmetic>(BaseInst)) {
if (ArithInst->getOp() != InstArithmetic::Add && if (ArithInst->getOp() != InstArithmetic::Add &&
ArithInst->getOp() != InstArithmetic::Sub) ArithInst->getOp() != InstArithmetic::Sub)
return false; return nullptr;
bool IsAdd = ArithInst->getOp() == InstArithmetic::Add; bool IsAdd = ArithInst->getOp() == InstArithmetic::Add;
Operand *Src0 = ArithInst->getSrc(0); Operand *Src0 = ArithInst->getSrc(0);
Operand *Src1 = ArithInst->getSrc(1); Operand *Src1 = ArithInst->getSrc(1);
...@@ -5181,74 +5185,55 @@ inline bool matchOffsetBase(const VariablesMetadata *VMetadata, ...@@ -5181,74 +5185,55 @@ inline bool matchOffsetBase(const VariablesMetadata *VMetadata,
auto *Reloc0 = llvm::dyn_cast<ConstantRelocatable>(Src0); auto *Reloc0 = llvm::dyn_cast<ConstantRelocatable>(Src0);
auto *Reloc1 = llvm::dyn_cast<ConstantRelocatable>(Src1); auto *Reloc1 = llvm::dyn_cast<ConstantRelocatable>(Src1);
Variable *NewBase = nullptr; Variable *NewBase = nullptr;
int32_t NewOffset = Offset; int32_t NewOffset = *Offset;
ConstantRelocatable *NewRelocatable = Relocatable; ConstantRelocatable *NewRelocatable = *Relocatable;
if (Var0 && Var1) if (Var0 && Var1)
// TODO(sehr): merge base/index splitting into here. // TODO(sehr): merge base/index splitting into here.
return false; return nullptr;
if (!IsAdd && Var1) if (!IsAdd && Var1)
return false; return nullptr;
if (Var0) if (Var0)
NewBase = Var0; NewBase = Var0;
else if (Var1) else if (Var1)
NewBase = Var1; NewBase = Var1;
// Don't know how to add/subtract two relocatables. // Don't know how to add/subtract two relocatables.
if ((Relocatable && (Reloc0 || Reloc1)) || (Reloc0 && Reloc1)) if ((*Relocatable && (Reloc0 || Reloc1)) || (Reloc0 && Reloc1))
return false; return nullptr;
// Don't know how to subtract a relocatable. // Don't know how to subtract a relocatable.
if (!IsAdd && Reloc1) if (!IsAdd && Reloc1)
return false; return nullptr;
// Incorporate ConstantRelocatables. // Incorporate ConstantRelocatables.
if (Reloc0) if (Reloc0)
NewRelocatable = Reloc0; NewRelocatable = Reloc0;
else if (Reloc1) else if (Reloc1)
NewRelocatable = Reloc1; NewRelocatable = Reloc1;
if ((Reloc0 || Reloc1) && BaseOther && GotVar)
return false;
// Compute the updated constant offset. // Compute the updated constant offset.
if (Const0) { if (Const0) {
const int32_t MoreOffset = const int32_t MoreOffset =
IsAdd ? Const0->getValue() : -Const0->getValue(); IsAdd ? Const0->getValue() : -Const0->getValue();
if (Utils::WouldOverflowAdd(NewOffset, MoreOffset)) if (Utils::WouldOverflowAdd(NewOffset, MoreOffset))
return false; return nullptr;
NewOffset += MoreOffset; NewOffset += MoreOffset;
} }
if (Const1) { if (Const1) {
const int32_t MoreOffset = const int32_t MoreOffset =
IsAdd ? Const1->getValue() : -Const1->getValue(); IsAdd ? Const1->getValue() : -Const1->getValue();
if (Utils::WouldOverflowAdd(NewOffset, MoreOffset)) if (Utils::WouldOverflowAdd(NewOffset, MoreOffset))
return false; return nullptr;
NewOffset += MoreOffset; NewOffset += MoreOffset;
} }
// Update the computed address parameters once we are sure optimization *Base = NewBase;
// is valid. *Offset = NewOffset;
if ((Reloc0 || Reloc1) && GotVar) { *Relocatable = NewRelocatable;
assert(BaseOther == nullptr); return BaseInst;
BaseOther = GotVar;
}
Base = NewBase;
Offset = NewOffset;
Relocatable = NewRelocatable;
Reason = BaseInst;
return true;
} }
return false; return nullptr;
} }
// Builds information for a canonical address expresion: template <typename TypeTraits>
// <Relocatable + Offset>(Base, Index, Shift) typename TargetX86Base<TypeTraits>::X86OperandMem *
// On entry: TargetX86Base<TypeTraits>::computeAddressOpt(const Inst *Instr, Type MemType,
// Relocatable == null, Operand *Addr) {
// 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;
Func->resetCurrentNode(); Func->resetCurrentNode();
if (Func->isVerbose(IceV_AddrOpt)) { if (Func->isVerbose(IceV_AddrOpt)) {
OstreamLocker L(Func->getContext()); OstreamLocker L(Func->getContext());
...@@ -5256,70 +5241,138 @@ inline bool computeAddressOpt(Cfg *Func, const Inst *Instr, Variable *GotVar, ...@@ -5256,70 +5241,138 @@ inline bool computeAddressOpt(Cfg *Func, const Inst *Instr, Variable *GotVar,
Str << "\nStarting computeAddressOpt for instruction:\n "; Str << "\nStarting computeAddressOpt for instruction:\n ";
Instr->dumpDecorated(Func); 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 // 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 // don't go further. Alternatively (?), never consider a transformation that
// would change a variable that is currently *not* live across basic block // would change a variable that is currently *not* live across basic block
// boundaries into one that *is*. // boundaries into one that *is*.
if (Func->getVMetadata()->isMultiBlock(Base) /* || Base->getUseCount() > 1*/) if (Func->getVMetadata()->isMultiBlock(
return AddressWasOptimized; NewAddr.Base) /* || Base->getUseCount() > 1*/)
return nullptr;
AddressOptimizer AddrOpt(Func);
const bool MockBounds = Func->getContext()->getFlags().getMockBoundsCheck(); const bool MockBounds = Func->getContext()->getFlags().getMockBoundsCheck();
const VariablesMetadata *VMetadata = Func->getVMetadata();
const Inst *Reason = nullptr; 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 { 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) { 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; AddressWasOptimized = true;
Reason = nullptr; Reason = nullptr;
SkipLastFolding = nullptr;
memset(&Skip, 0, sizeof(Skip));
} }
NewAddrCheckpoint = NewAddr;
// Update Base and Index to follow through assignments to definitions. // 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 // Assignments of Base from a Relocatable or ConstantInt32 can result
// in Base becoming nullptr. To avoid code duplication in this loop we // in Base becoming nullptr. To avoid code duplication in this loop we
// prefer that Base be non-nullptr if possible. // prefer that Base be non-nullptr if possible.
if ((Base == nullptr) && (Index != nullptr) && Shift == 0) if ((NewAddr.Base == nullptr) && (NewAddr.Index != nullptr) &&
std::swap(Base, Index); NewAddr.Shift == 0) {
std::swap(NewAddr.Base, NewAddr.Index);
}
continue; 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; continue;
}
if (!MockBounds) { if (!MockBounds) {
// Transition from: // Transition from:
// <Relocatable + Offset>(Base) to // <Relocatable + Offset>(Base) to
// <Relocatable + Offset>(Base, Index) // <Relocatable + Offset>(Base, Index)
if (!ReserveSlot && if (!Skip.CombinedBaseIndex &&
matchCombinedBaseIndex(VMetadata, Base, Index, Shift, Reason)) (Reason = AddrOpt.matchCombinedBaseIndex(
&NewAddr.Base, &NewAddr.Index, &NewAddr.Shift))) {
SkipLastFolding = &Skip.CombinedBaseIndex;
continue; continue;
}
// Recognize multiply/shift and update Shift amount. // Recognize multiply/shift and update Shift amount.
// Index becomes Index=Var<<Const && Const+Shift<=3 ==> // Index becomes Index=Var<<Const && Const+Shift<=3 ==>
// Index=Var, Shift+=Const // Index=Var, Shift+=Const
// Index becomes Index=Const*Var && log2(Const)+Shift<=3 ==> // Index becomes Index=Const*Var && log2(Const)+Shift<=3 ==>
// Index=Var, Shift+=log2(Const) // Index=Var, Shift+=log2(Const)
if (matchShiftedIndex(VMetadata, Index, Shift, Reason)) if ((Reason =
AddrOpt.matchShiftedIndex(&NewAddr.Index, &NewAddr.Shift))) {
continue; continue;
}
// If Shift is zero, the choice of Base and Index was purely arbitrary. // If Shift is zero, the choice of Base and Index was purely arbitrary.
// Recognize multiply/shift and set Shift amount. // Recognize multiply/shift and set Shift amount.
// Shift==0 && Base is Base=Var*Const && log2(Const)+Shift<=3 ==> // Shift==0 && Base is Base=Var*Const && log2(Const)+Shift<=3 ==>
// swap(Index,Base) // swap(Index,Base)
// Similar for Base=Const*Var and Base=Var<<Const // Similar for Base=Const*Var and Base=Var<<Const
if (Shift == 0 && matchShiftedIndex(VMetadata, Base, Shift, Reason)) { if (NewAddr.Shift == 0 &&
std::swap(Base, Index); (Reason = AddrOpt.matchShiftedIndex(&NewAddr.Base, &NewAddr.Shift))) {
std::swap(NewAddr.Base, NewAddr.Index);
continue; continue;
} }
} }
// Update Offset to reflect additions/subtractions with constants and // Update Offset to reflect additions/subtractions with constants and
// relocatables. // relocatables.
// TODO: consider overflow issues with respect to Offset. // TODO: consider overflow issues with respect to Offset.
if (matchOffsetBase(VMetadata, GotVar, Base, Index, Relocatable, Offset, if (!Skip.OffsetFromBase &&
Reason)) (Reason = AddrOpt.matchOffsetBase(&NewAddr.Base, &NewAddr.Relocatable,
&NewAddr.Offset))) {
SkipLastFolding = &Skip.OffsetFromBase;
continue; 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; continue;
}
// TODO(sehr, stichnot): Handle updates of Index with Shift != 0. // TODO(sehr, stichnot): Handle updates of Index with Shift != 0.
// Index is Index=Var+Const ==> // Index is Index=Var+Const ==>
// set Index=Var, Offset+=(Const<<Shift) // set Index=Var, Offset+=(Const<<Shift)
...@@ -5329,13 +5382,40 @@ inline bool computeAddressOpt(Cfg *Func, const Inst *Instr, Variable *GotVar, ...@@ -5329,13 +5382,40 @@ inline bool computeAddressOpt(Cfg *Func, const Inst *Instr, Variable *GotVar,
// set Index=Var, Offset-=(Const<<Shift) // set Index=Var, Offset-=(Const<<Shift)
break; break;
} while (Reason); } while (Reason);
// Undo any addition of GotVar. It will be added back when the mem operand is
// legalized. if (!AddressWasOptimized) {
if (Base == GotVar) return nullptr;
Base = nullptr; }
if (Index == GotVar)
Index = nullptr; // Undo any addition of RebasePtr. It will be added back when the mem
return AddressWasOptimized; // 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 /// Add a mock bounds check on the memory address before using it as a load or
...@@ -5413,35 +5493,11 @@ void TargetX86Base<TraitsType>::lowerLoad(const InstLoad *Load) { ...@@ -5413,35 +5493,11 @@ void TargetX86Base<TraitsType>::lowerLoad(const InstLoad *Load) {
template <typename TraitsType> template <typename TraitsType>
void TargetX86Base<TraitsType>::doAddressOptLoad() { void TargetX86Base<TraitsType>::doAddressOptLoad() {
Inst *Inst = Context.getCur(); Inst *Inst = Context.getCur();
Variable *Dest = Inst->getDest();
Operand *Addr = Inst->getSrc(0); Operand *Addr = Inst->getSrc(0);
Variable *Index = nullptr; Variable *Dest = Inst->getDest();
ConstantRelocatable *Relocatable = nullptr; if (auto *OptAddr = computeAddressOpt(Inst, Dest->getType(), Addr)) {
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)) {
Inst->setDeleted(); Inst->setDeleted();
Constant *OffsetOp = nullptr; Context.insert<InstLoad>(Dest, OptAddr);
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);
} }
} }
...@@ -5738,35 +5794,11 @@ void TargetX86Base<TraitsType>::lowerStore(const InstStore *Inst) { ...@@ -5738,35 +5794,11 @@ void TargetX86Base<TraitsType>::lowerStore(const InstStore *Inst) {
template <typename TraitsType> template <typename TraitsType>
void TargetX86Base<TraitsType>::doAddressOptStore() { void TargetX86Base<TraitsType>::doAddressOptStore() {
auto *Inst = llvm::cast<InstStore>(Context.getCur()); auto *Inst = llvm::cast<InstStore>(Context.getCur());
Operand *Data = Inst->getData();
Operand *Addr = Inst->getAddr(); Operand *Addr = Inst->getAddr();
Variable *Index = nullptr; Operand *Data = Inst->getData();
ConstantRelocatable *Relocatable = nullptr; if (auto *OptAddr = computeAddressOpt(Inst, Data->getType(), Addr)) {
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)) {
Inst->setDeleted(); Inst->setDeleted();
Constant *OffsetOp = nullptr; auto *NewStore = Context.insert<InstStore>(Data, OptAddr);
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);
if (Inst->getDest()) if (Inst->getDest())
NewStore->setRmwBeacon(Inst->getRmwBeacon()); NewStore->setRmwBeacon(Inst->getRmwBeacon());
} }
...@@ -5826,9 +5858,8 @@ void TargetX86Base<TraitsType>::lowerCaseCluster(const CaseCluster &Case, ...@@ -5826,9 +5858,8 @@ void TargetX86Base<TraitsType>::lowerCaseCluster(const CaseCluster &Case,
constexpr RelocOffsetT RelocOffset = 0; constexpr RelocOffsetT RelocOffset = 0;
constexpr bool SuppressMangling = true; constexpr bool SuppressMangling = true;
const bool IsRebased = Ctx->getFlags().getUseNonsfi();
IceString MangledName = Ctx->mangleName(Func->getFunctionName()); IceString MangledName = Ctx->mangleName(Func->getFunctionName());
Variable *Base = IsRebased ? legalizeToReg(GotVar) : nullptr; constexpr Variable *NoBase = nullptr;
Constant *Offset = Ctx->getConstantSym( Constant *Offset = Ctx->getConstantSym(
RelocOffset, InstJumpTable::makeName(MangledName, JumpTable->getId()), RelocOffset, InstJumpTable::makeName(MangledName, JumpTable->getId()),
SuppressMangling); SuppressMangling);
...@@ -5837,11 +5868,10 @@ void TargetX86Base<TraitsType>::lowerCaseCluster(const CaseCluster &Case, ...@@ -5837,11 +5868,10 @@ void TargetX86Base<TraitsType>::lowerCaseCluster(const CaseCluster &Case,
Variable *Target = nullptr; Variable *Target = nullptr;
if (Traits::Is64Bit && NeedSandboxing) { if (Traits::Is64Bit && NeedSandboxing) {
assert(Base == nullptr);
assert(Index != nullptr && Index->getType() == IceType_i32); assert(Index != nullptr && Index->getType() == IceType_i32);
} }
auto *TargetInMemory = X86OperandMem::create( auto *TargetInMemory = X86OperandMem::create(Func, PointerType, NoBase,
Func, PointerType, Base, Offset, Index, Shift, Segment, IsRebased); Offset, Index, Shift, Segment);
_mov(Target, TargetInMemory); _mov(Target, TargetInMemory);
lowerIndirectJump(Target); lowerIndirectJump(Target);
...@@ -6168,12 +6198,12 @@ void TargetX86Base<TraitsType>::lowerOther(const Inst *Instr) { ...@@ -6168,12 +6198,12 @@ void TargetX86Base<TraitsType>::lowerOther(const Inst *Instr) {
/// Turn an i64 Phi instruction into a pair of i32 Phi instructions, to preserve /// 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, /// integrity of liveness analysis. Undef values are also turned into zeroes,
/// since loOperand() and hiOperand() don't expect Undef input. Also, in /// 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() { template <typename TraitsType> void TargetX86Base<TraitsType>::prelowerPhis() {
if (Ctx->getFlags().getUseNonsfi()) { if (Ctx->getFlags().getUseNonsfi()) {
assert(GotVar); assert(RebasePtr);
CfgNode *Node = Context.getNode(); CfgNode *Node = Context.getNode();
uint32_t GotVarUseCount = 0; uint32_t RebasePtrUseCount = 0;
for (Inst &I : Node->getPhis()) { for (Inst &I : Node->getPhis()) {
auto *Phi = llvm::dyn_cast<InstPhi>(&I); auto *Phi = llvm::dyn_cast<InstPhi>(&I);
if (Phi->isDeleted()) if (Phi->isDeleted())
...@@ -6184,12 +6214,12 @@ template <typename TraitsType> void TargetX86Base<TraitsType>::prelowerPhis() { ...@@ -6184,12 +6214,12 @@ template <typename TraitsType> void TargetX86Base<TraitsType>::prelowerPhis() {
// kinds of pooling. // kinds of pooling.
if (llvm::isa<ConstantRelocatable>(Src) || if (llvm::isa<ConstantRelocatable>(Src) ||
llvm::isa<ConstantFloat>(Src) || llvm::isa<ConstantDouble>(Src)) { llvm::isa<ConstantFloat>(Src) || llvm::isa<ConstantDouble>(Src)) {
++GotVarUseCount; ++RebasePtrUseCount;
} }
} }
} }
if (GotVarUseCount) { if (RebasePtrUseCount) {
Node->getInsts().push_front(InstFakeUse::create(Func, GotVar)); Node->getInsts().push_front(InstFakeUse::create(Func, RebasePtr));
} }
} }
if (Traits::Is64Bit) { if (Traits::Is64Bit) {
...@@ -6737,29 +6767,13 @@ Operand *TargetX86Base<TraitsType>::legalize(Operand *From, LegalMask Allowed, ...@@ -6737,29 +6767,13 @@ Operand *TargetX86Base<TraitsType>::legalize(Operand *From, LegalMask Allowed,
RegIndex = llvm::cast<Variable>( RegIndex = llvm::cast<Variable>(
legalize(Index, Legal_Reg | Legal_Rematerializable)); 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) { if (Base != RegBase || Index != RegIndex) {
Mem = X86OperandMem::create(Func, Ty, RegBase, Offset, RegIndex, Shift, 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); From = randomizeOrPoolImmediate(Mem);
if (!(Allowed & Legal_Mem)) { if (!(Allowed & Legal_Mem)) {
...@@ -6798,24 +6812,21 @@ Operand *TargetX86Base<TraitsType>::legalize(Operand *From, LegalMask Allowed, ...@@ -6798,24 +6812,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 (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)) { if (UseNonsfi && !(Allowed & Legal_AddrAbs)) {
assert(Ty == IceType_i32); assert(Ty == IceType_i32);
Variable *RegBase = legalizeToReg(GotVar);
Variable *NewVar = makeReg(Ty, RegNum); Variable *NewVar = makeReg(Ty, RegNum);
static constexpr bool IsRebased = true; auto *Mem = Traits::X86OperandMem::create(Func, Ty, nullptr, CR);
auto *Mem = // LEAs are not automatically sandboxed, thus we explicitly invoke
Traits::X86OperandMem::create(Func, Ty, RegBase, CR, IsRebased); // _sandbox_mem_reference.
_lea(NewVar, Mem); _lea(NewVar, _sandbox_mem_reference(Mem));
From = NewVar; From = NewVar;
} }
} } else if (isScalarFloatingType(Ty)) {
// Convert a scalar floating point constant into an explicit memory // Convert a scalar floating point constant into an explicit memory
// operand. // operand.
if (isScalarFloatingType(Ty)) {
if (auto *ConstFloat = llvm::dyn_cast<ConstantFloat>(Const)) { if (auto *ConstFloat = llvm::dyn_cast<ConstantFloat>(Const)) {
if (Utils::isPositiveZero(ConstFloat->getValue())) if (Utils::isPositiveZero(ConstFloat->getValue()))
return makeZeroedRegister(Ty, RegNum); return makeZeroedRegister(Ty, RegNum);
...@@ -6823,19 +6834,19 @@ Operand *TargetX86Base<TraitsType>::legalize(Operand *From, LegalMask Allowed, ...@@ -6823,19 +6834,19 @@ Operand *TargetX86Base<TraitsType>::legalize(Operand *From, LegalMask Allowed,
if (Utils::isPositiveZero(ConstDouble->getValue())) if (Utils::isPositiveZero(ConstDouble->getValue()))
return makeZeroedRegister(Ty, RegNum); return makeZeroedRegister(Ty, RegNum);
} }
Variable *Base = UseNonsfi ? legalizeToReg(GotVar) : nullptr;
std::string Buffer; std::string Buffer;
llvm::raw_string_ostream StrBuf(Buffer); llvm::raw_string_ostream StrBuf(Buffer);
llvm::cast<Constant>(From)->emitPoolLabel(StrBuf, Ctx); llvm::cast<Constant>(From)->emitPoolLabel(StrBuf, Ctx);
llvm::cast<Constant>(From)->setShouldBePooled(true); llvm::cast<Constant>(From)->setShouldBePooled(true);
Constant *Offset = Ctx->getConstantSym(0, StrBuf.str(), true); Constant *Offset = Ctx->getConstantSym(0, StrBuf.str(), true);
const bool IsRebased = Base != nullptr; auto *Mem = X86OperandMem::create(Func, Ty, nullptr, Offset);
auto *Mem = X86OperandMem::create(Func, Ty, Base, Offset, IsRebased);
From = Mem; From = Mem;
} }
bool NeedsReg = false; bool NeedsReg = false;
if (!(Allowed & Legal_Imm) && !isScalarFloatingType(Ty)) if (!(Allowed & Legal_Imm) && !isScalarFloatingType(Ty))
// Immediate specifically not allowed // Immediate specifically not allowed.
NeedsReg = true; NeedsReg = true;
if (!(Allowed & Legal_Mem) && isScalarFloatingType(Ty)) if (!(Allowed & Legal_Mem) && isScalarFloatingType(Ty))
// On x86, FP constants are lowered to mem operands. // On x86, FP constants are lowered to mem operands.
...@@ -6868,8 +6879,7 @@ Operand *TargetX86Base<TraitsType>::legalize(Operand *From, LegalMask Allowed, ...@@ -6868,8 +6879,7 @@ Operand *TargetX86Base<TraitsType>::legalize(Operand *From, LegalMask Allowed,
_lea(NewVar, Mem); _lea(NewVar, Mem);
From = NewVar; From = NewVar;
} else if ((!(Allowed & Legal_Mem) && !MustHaveRegister) || } else if ((!(Allowed & Legal_Mem) && !MustHaveRegister) ||
(RegNum != Variable::NoRegister && RegNum != Var->getRegNum()) || (RegNum != Variable::NoRegister && RegNum != Var->getRegNum())) {
MustRematerialize) {
From = copyToReg(From, RegNum); From = copyToReg(From, RegNum);
} }
return From; return From;
...@@ -7149,11 +7159,9 @@ TargetX86Base<TraitsType>::randomizeOrPoolImmediate(Constant *Immediate, ...@@ -7149,11 +7159,9 @@ TargetX86Base<TraitsType>::randomizeOrPoolImmediate(Constant *Immediate,
constexpr bool SuppressMangling = true; constexpr bool SuppressMangling = true;
Constant *Symbol = Constant *Symbol =
Ctx->getConstantSym(Offset, Label_stream.str(), SuppressMangling); Ctx->getConstantSym(Offset, Label_stream.str(), SuppressMangling);
const bool UseNonsfi = Ctx->getFlags().getUseNonsfi(); constexpr Variable *NoBase = nullptr;
Variable *Base = UseNonsfi ? legalizeToReg(GotVar) : nullptr; X86OperandMem *MemOperand =
const bool IsRebased = Base != nullptr; X86OperandMem::create(Func, Immediate->getType(), NoBase, Symbol);
X86OperandMem *MemOperand = X86OperandMem::create(
Func, Immediate->getType(), Base, Symbol, IsRebased);
_mov(Reg, MemOperand); _mov(Reg, MemOperand);
return Reg; return Reg;
} }
...@@ -7259,11 +7267,9 @@ TargetX86Base<TraitsType>::randomizeOrPoolImmediate(X86OperandMem *MemOperand, ...@@ -7259,11 +7267,9 @@ TargetX86Base<TraitsType>::randomizeOrPoolImmediate(X86OperandMem *MemOperand,
constexpr bool SuppressMangling = true; constexpr bool SuppressMangling = true;
Constant *Symbol = Constant *Symbol =
Ctx->getConstantSym(SymOffset, Label_stream.str(), SuppressMangling); Ctx->getConstantSym(SymOffset, Label_stream.str(), SuppressMangling);
const bool UseNonsfi = Ctx->getFlags().getUseNonsfi(); constexpr Variable *NoBase = nullptr;
Variable *Base = UseNonsfi ? legalizeToReg(GotVar) : nullptr;
const bool IsRebased = Base != nullptr;
X86OperandMem *SymbolOperand = X86OperandMem::create( X86OperandMem *SymbolOperand = X86OperandMem::create(
Func, MemOperand->getOffset()->getType(), Base, Symbol, IsRebased); Func, MemOperand->getOffset()->getType(), NoBase, Symbol);
_mov(RegTemp, SymbolOperand); _mov(RegTemp, SymbolOperand);
// If we have a base variable here, we should add the lea instruction // 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 // to add the value of the base variable to RegTemp. If there is no
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment