Index: src/IceTargetLoweringX8664.cpp |
diff --git a/src/IceTargetLoweringX8664.cpp b/src/IceTargetLoweringX8664.cpp |
index 588432182e2302757c75dec5761c4ae92535ade8..aed9b30091d8498ee8e4ae82e593a9362ea2db84 100644 |
--- a/src/IceTargetLoweringX8664.cpp |
+++ b/src/IceTargetLoweringX8664.cpp |
@@ -294,10 +294,31 @@ void TargetX8664::emitGetIP(CfgNode *Node) { |
(void)Node; |
} |
+namespace { |
+bool isAssignedToRspOrRbp(const Variable *Var) { |
+ if (Var == nullptr) { |
+ return false; |
+ } |
+ |
+ if (Var->isRematerializable()) { |
+ return true; |
+ } |
+ |
+ if (!Var->hasReg()) { |
+ return false; |
+ } |
+ |
+ const int32_t RegNum = Var->getRegNum(); |
+ if ((RegNum == Traits::RegisterSet::Reg_rsp) || |
+ (RegNum == Traits::RegisterSet::Reg_rbp)) { |
+ return true; |
+ } |
+ |
+ return false; |
+} |
+} // end of anonymous namespace |
+ |
Traits::X86OperandMem *TargetX8664::_sandbox_mem_reference(X86OperandMem *Mem) { |
- // 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 |
- // %rbp to be 'truncated' to 32-bit before memory access. |
if (SandboxingType == ST_None) { |
return Mem; |
} |
@@ -307,25 +328,49 @@ Traits::X86OperandMem *TargetX8664::_sandbox_mem_reference(X86OperandMem *Mem) { |
"_sandbox_mem_reference not implemented for nonsfi"); |
} |
+ // In x86_64-nacl, all memory references are relative to a base register |
+ // (%r15, %rsp, %rbp, or %rip). |
+ |
Variable *Base = Mem->getBase(); |
Variable *Index = Mem->getIndex(); |
uint16_t Shift = 0; |
- Variable *ZeroReg = |
- getPhysicalRegister(Traits::RegisterSet::Reg_r15, IceType_i64); |
+ Variable *ZeroReg = RebasePtr; |
Constant *Offset = Mem->getOffset(); |
Variable *T = nullptr; |
+ bool AbsoluteAddress = false; |
+ if (Base == nullptr && Index == nullptr) { |
+ if (const auto *CR = llvm::dyn_cast<ConstantRelocatable>(Offset)) { |
+ if (CR->getName() != "") { |
+ // Mem is RIP-relative. There's no need to rebase it. |
+ return Mem; |
+ } |
+ } |
+ // Offset is an absolute address, so we need to emit |
+ // Offset(%r15) |
+ AbsoluteAddress = true; |
+ } |
+ |
if (Mem->getIsRebased()) { |
- // If Mem.IsRebased, then we don't need to update Mem to contain a reference |
- // to a valid base register (%r15, %rsp, or %rbp), but we still need to |
- // truncate Mem.Index (if any) to 32-bit. |
- assert(ZeroReg == Base || Base->isRematerializable()); |
- T = makeReg(IceType_i32); |
- _mov(T, Index); |
- Shift = Mem->getShift(); |
+ // If Mem.IsRebased, then we don't need to update Mem, as it's already been |
+ // updated to contain a reference to one of %rsp, %rbp, or %r15. |
+ // We don't return early because we still need to zero extend Index. |
+ assert(ZeroReg == Base || AbsoluteAddress || isAssignedToRspOrRbp(Base)); |
+ if (!AbsoluteAddress) { |
+ // If Mem is an absolute address, no need to update ZeroReg (which is |
+ // already set to %r15.) |
+ ZeroReg = Base; |
+ } |
+ if (Index != nullptr) { |
+ T = makeReg(IceType_i32); |
+ _mov(T, Index); |
+ Shift = Mem->getShift(); |
+ } |
} else { |
if (Base != nullptr) { |
- if (Base->isRematerializable()) { |
+ // If Base is a valid base pointer we don't need to use the RebasePtr. By |
+ // doing this we might save us the need to zero extend the memory operand. |
+ if (isAssignedToRspOrRbp(Base)) { |
ZeroReg = Base; |
} else { |
T = Base; |
@@ -334,11 +379,23 @@ Traits::X86OperandMem *TargetX8664::_sandbox_mem_reference(X86OperandMem *Mem) { |
if (Index != nullptr) { |
assert(!Index->isRematerializable()); |
+ // If Index is not nullptr, it is mandatory that T is a nullptr. |
+ // Otherwise, the lowering generated a memory operand with two registers. |
+ // Note that Base might still be non-nullptr, but it must be a valid |
+ // base register. |
if (T != nullptr) { |
llvm::report_fatal_error("memory reference contains base and index."); |
} |
- T = Index; |
- Shift = Mem->getShift(); |
+ // If the Index is not shifted, and it is a Valid Base, and the ZeroReg is |
+ // still RebasePtr, then we do ZeroReg = Index, and hopefully prevent the |
+ // need to zero-extend the memory operand (which may still happen -- see |
+ // NeedLea below.) |
+ if (Shift == 0 && isAssignedToRspOrRbp(Index) && ZeroReg == RebasePtr) { |
+ ZeroReg = Index; |
+ } else { |
+ T = Index; |
+ Shift = Mem->getShift(); |
+ } |
} |
} |
@@ -348,11 +405,13 @@ Traits::X86OperandMem *TargetX8664::_sandbox_mem_reference(X86OperandMem *Mem) { |
// needed to ensure the sandboxed memory operand will only use the lower |
// 32-bits of T+Offset. |
bool NeedsLea = false; |
- if (const auto *Offset = Mem->getOffset()) { |
- if (llvm::isa<ConstantRelocatable>(Offset)) { |
- NeedsLea = true; |
+ if (Offset != nullptr) { |
+ if (const auto *CR = llvm::dyn_cast<ConstantRelocatable>(Offset)) { |
+ NeedsLea = CR->getName() != "" || CR->getOffset() < 0; |
} else if (const auto *Imm = llvm::cast<ConstantInteger32>(Offset)) { |
NeedsLea = Imm->getValue() < 0; |
+ } else { |
+ llvm::report_fatal_error("Unexpected Offset type."); |
} |
} |
@@ -362,21 +421,20 @@ Traits::X86OperandMem *TargetX8664::_sandbox_mem_reference(X86OperandMem *Mem) { |
if (T->hasReg()) { |
RegNum = Traits::getGprForType(IceType_i64, T->getRegNum()); |
RegNum32 = Traits::getGprForType(IceType_i32, RegNum); |
- switch (RegNum) { |
- case Traits::RegisterSet::Reg_rsp: |
- case Traits::RegisterSet::Reg_rbp: |
- // Memory operands referencing rsp/rbp do not need to be sandboxed. |
- return Mem; |
- } |
+ // At this point, if T was assigned to rsp/rbp, then we would have already |
+ // made this the ZeroReg. |
+ assert(RegNum != Traits::RegisterSet::Reg_rsp); |
+ assert(RegNum != Traits::RegisterSet::Reg_rbp); |
} |
switch (T->getType()) { |
default: |
+ llvm::report_fatal_error("Mem pointer should be a 32-bit GPR."); |
case IceType_i64: |
// Even though "default:" would also catch T.Type == IceType_i64, an |
// explicit 'case IceType_i64' shows that memory operands are always |
// supposed to be 32-bits. |
- llvm::report_fatal_error("Mem pointer should be 32-bit."); |
+ llvm::report_fatal_error("Mem pointer should not be a 64-bit GPR."); |
case IceType_i32: { |
Variable *T64 = makeReg(IceType_i64, RegNum); |
auto *Movzx = _movzx(T64, T); |