Index: lib/Target/X86/X86ISelDAGToDAG.cpp |
diff --git a/lib/Target/X86/X86ISelDAGToDAG.cpp b/lib/Target/X86/X86ISelDAGToDAG.cpp |
index 3ef7b2c7697bbeb6e8b95cfcce4a22d729ed6b47..152fd282503430b620971cad064461e652ef5646 100644 |
--- a/lib/Target/X86/X86ISelDAGToDAG.cpp |
+++ b/lib/Target/X86/X86ISelDAGToDAG.cpp |
@@ -82,6 +82,24 @@ namespace { |
JT != -1 || BlockAddr != nullptr; |
} |
+ // @LOCALMOD-BEGIN |
+ /// clearSymbolicDisplacement - Remove all sources of symbolic |
+ /// constant displacement from the addressing mode. This is |
+ /// needed when the symbolic constant is pulled out of the address |
+ /// computation, e.g. when |
+ /// ... DISP(%r15,%rax,1) ... |
+ /// is replaced with |
+ /// lea DISP(%rax),%tmp |
+ /// ... (%r15,%tmp,1) ... |
+ void clearSymbolicDisplacement() { |
+ GV = 0; |
+ CP = 0; |
+ BlockAddr = 0; |
+ ES = 0; |
+ JT = -1; |
+ } |
+ // @LOCALMOD-END |
+ |
bool hasBaseOrIndexReg() const { |
return BaseType == FrameIndexBase || |
IndexReg.getNode() != nullptr || Base_Reg.getNode() != nullptr; |
@@ -221,6 +239,10 @@ namespace { |
SDValue &Index, SDValue &Disp, |
SDValue &Segment, |
SDValue &NodeWithChain); |
+ // @LOCALMOD-BEGIN |
+ void LegalizeAddressingModeForNaCl(SDValue N, X86ISelAddressMode &AM); |
+ // @LOCALMOD-END |
+ |
bool TryFoldLoad(SDNode *P, SDValue N, |
SDValue &Base, SDValue &Scale, |
@@ -238,10 +260,15 @@ namespace { |
inline void getAddressOperands(X86ISelAddressMode &AM, SDValue &Base, |
SDValue &Scale, SDValue &Index, |
SDValue &Disp, SDValue &Segment) { |
+ |
+ // @LOCALMOD-BEGIN: NaCl64 pointers are 32-bit, but memory operands |
+ // are 64-bit (adds r15). |
+ EVT MemOpVT = Subtarget->is64Bit() ? MVT::i64 : MVT::i32; |
Base = (AM.BaseType == X86ISelAddressMode::FrameIndexBase) |
? CurDAG->getTargetFrameIndex(AM.Base_FrameIndex, |
- TLI->getPointerTy()) |
+ MemOpVT) |
: AM.Base_Reg; |
+ // @LOCALMOD-END |
Scale = getI8Imm(AM.Scale); |
Index = AM.IndexReg; |
// These are 32-bit even in 64-bit mode since RIP relative offset |
@@ -301,6 +328,20 @@ namespace { |
return getTargetMachine().getSubtargetImpl()->getInstrInfo(); |
} |
+ // @LOCALMOD-START |
+ // Determine when an addressing mode with a base register and an index |
+ // register can be selected (or not). The NaCl 64-bit sandbox could end |
+ // up adding an r15 base register for memory accesses late (after register |
+ // allocation), so having both a base and index register selected |
+ // now will make it hard to modify the address and base off of r15 later. |
+ // This only applies to memory accesses and not lea (distinguished by |
+ // selectingMemOp). |
+ bool selectingMemOp; |
+ bool RestrictUseOfBaseReg() { |
+ return selectingMemOp && Subtarget->isTargetNaCl64(); |
+ } |
+ // @LOCALMOD-END |
+ |
/// \brief Address-mode matching performs shift-of-and to and-of-shift |
/// reassociation in order to expose more scaled addressing |
/// opportunities. |
@@ -461,8 +502,7 @@ void X86DAGToDAGISel::PreprocessISelDAG() { |
SDNode *N = I++; // Preincrement iterator to avoid invalidation issues. |
if (OptLevel != CodeGenOpt::None && |
- // Only does this when target favors doesn't favor register indirect |
- // call. |
+ !Subtarget->isTargetNaCl() && // @LOCALMOD: We can't fold load/call |
((N->getOpcode() == X86ISD::CALL && !Subtarget->callRegIndirect()) || |
(N->getOpcode() == X86ISD::TC_RETURN && |
// Only does this if load can be folded into TC_RETURN. |
@@ -612,6 +652,18 @@ bool X86DAGToDAGISel::FoldOffsetIntoAddress(uint64_t Offset, |
if (AM.BaseType == X86ISelAddressMode::FrameIndexBase && |
!isDispSafeForFrameIndex(Val)) |
return true; |
+ // LOCALMOD-BEGIN |
+ // Do not fold large offsets into displacements. |
+ // Various constant folding and address-mode selections can result in |
+ // 32-bit operations (e.g. from GEP) getting folded into the displacement |
+ // and often results in a negative value in the index register |
+ // (see also LegalizeAddressModeForNaCl) |
+ else if (Subtarget->isTargetNaCl64() && |
+ (AM.BaseType == X86ISelAddressMode::RegBase || |
+ AM.BaseType == X86ISelAddressMode::FrameIndexBase) && |
+ (Val > 65535 || Val < -65536) && selectingMemOp) |
+ return true; |
+ // LOCALMOD-END |
} |
AM.Disp = Val; |
return false; |
@@ -621,6 +673,14 @@ bool X86DAGToDAGISel::FoldOffsetIntoAddress(uint64_t Offset, |
bool X86DAGToDAGISel::MatchLoadInAddress(LoadSDNode *N, X86ISelAddressMode &AM){ |
SDValue Address = N->getOperand(1); |
+ // @LOCALMOD-START |
+ // Disable this tls access optimization in Native Client, since |
+ // gs:0 (or fs:0 on X86-64) does not exactly contain its own address. |
+ if (Subtarget->isTargetNaCl()) { |
+ return true; |
+ } |
+ // @LOCALMOD-END |
+ |
// load gs:0 -> GS segment register. |
// load fs:0 -> FS segment register. |
// |
@@ -745,6 +805,8 @@ bool X86DAGToDAGISel::MatchAddress(SDValue N, X86ISelAddressMode &AM) { |
if (MatchAddressRecursively(N, AM, 0)) |
return true; |
+ |
+ if (!RestrictUseOfBaseReg()) { // @LOCALMOD |
// Post-processing: Convert lea(,%reg,2) to lea(%reg,%reg), which has |
// a smaller encoding and avoids a scaled-index. |
if (AM.Scale == 2 && |
@@ -753,7 +815,8 @@ bool X86DAGToDAGISel::MatchAddress(SDValue N, X86ISelAddressMode &AM) { |
AM.Base_Reg = AM.IndexReg; |
AM.Scale = 1; |
} |
- |
+ } // @LOCALMOD |
+ |
// Post-processing: Convert foo to foo(%rip), even in non-PIC mode, |
// because it has a smaller encoding. |
// TODO: Which other code models can use this? |
@@ -1101,6 +1164,8 @@ bool X86DAGToDAGISel::MatchAddressRecursively(SDValue N, X86ISelAddressMode &AM, |
// FALL THROUGH |
case ISD::MUL: |
case X86ISD::MUL_IMM: |
+ // @LOCALMOD |
+ if (!RestrictUseOfBaseReg()) { |
// X*[3,5,9] -> X+X*[2,4,8] |
if (AM.BaseType == X86ISelAddressMode::RegBase && |
AM.Base_Reg.getNode() == nullptr && |
@@ -1133,6 +1198,7 @@ bool X86DAGToDAGISel::MatchAddressRecursively(SDValue N, X86ISelAddressMode &AM, |
return false; |
} |
} |
+ } // @LOCALMOD |
break; |
case ISD::SUB: { |
@@ -1219,6 +1285,7 @@ bool X86DAGToDAGISel::MatchAddressRecursively(SDValue N, X86ISelAddressMode &AM, |
return false; |
AM = Backup; |
+ if (!RestrictUseOfBaseReg()) { // @LOCALMOD |
// If we couldn't fold both operands into the address at the same time, |
// see if we can just put each operand into a register and fold at least |
// the add. |
@@ -1231,6 +1298,7 @@ bool X86DAGToDAGISel::MatchAddressRecursively(SDValue N, X86ISelAddressMode &AM, |
AM.Scale = 1; |
return false; |
} |
+ } // @LOCALMOD |
N = Handle.getValue(); |
break; |
} |
@@ -1290,7 +1358,15 @@ bool X86DAGToDAGISel::MatchAddressRecursively(SDValue N, X86ISelAddressMode &AM, |
/// MatchAddressBase - Helper for MatchAddress. Add the specified node to the |
/// specified addressing mode without any further recursion. |
bool X86DAGToDAGISel::MatchAddressBase(SDValue N, X86ISelAddressMode &AM) { |
- // Is the base register already occupied? |
+ if (RestrictUseOfBaseReg()) { // @LOCALMOD |
+ if (AM.IndexReg.getNode() == 0) { |
+ AM.IndexReg = N; |
+ AM.Scale = 1; |
+ return false; |
+ } |
+ return true; |
+ } // @LOCALMOD |
+// Is the base register already occupied? |
if (AM.BaseType != X86ISelAddressMode::RegBase || AM.Base_Reg.getNode()) { |
// If so, check to see if the scale index register is set. |
if (!AM.IndexReg.getNode()) { |
@@ -1320,6 +1396,8 @@ bool X86DAGToDAGISel::SelectAddr(SDNode *Parent, SDValue N, SDValue &Base, |
SDValue &Scale, SDValue &Index, |
SDValue &Disp, SDValue &Segment) { |
X86ISelAddressMode AM; |
+ // @LOCALMOD |
+ selectingMemOp = true; |
if (Parent && |
// This list of opcodes are all the nodes that have an "addr:$ptr" operand |
@@ -1341,7 +1419,14 @@ bool X86DAGToDAGISel::SelectAddr(SDNode *Parent, SDValue N, SDValue &Base, |
if (MatchAddress(N, AM)) |
return false; |
- MVT VT = N.getSimpleValueType(); |
+ // @LOCALMOD-START |
+ if (Subtarget->isTargetNaCl64()) { |
+ LegalizeAddressingModeForNaCl(N, AM); |
+ } |
+ // @LOCALMOD-END |
+ |
+ MVT VT = Subtarget->is64Bit() ? MVT::i64 : MVT::i32; // @LOCALMOD |
+ |
if (AM.BaseType == X86ISelAddressMode::RegBase) { |
if (!AM.Base_Reg.getNode()) |
AM.Base_Reg = CurDAG->getRegister(0, VT); |
@@ -1351,6 +1436,27 @@ bool X86DAGToDAGISel::SelectAddr(SDNode *Parent, SDValue N, SDValue &Base, |
AM.IndexReg = CurDAG->getRegister(0, VT); |
getAddressOperands(AM, Base, Scale, Index, Disp, Segment); |
+ |
+ // @LOCALMOD-BEGIN |
+ // For Native Client 64-bit, zero-extend 32-bit pointers |
+ // to 64-bits for memory operations. Most of the time, this |
+ // won't generate any additional instructions because the backend |
+ // knows that operations on 32-bit registers implicitly zero-extends. |
+ // If we don't do this, there are a few corner cases where LLVM might |
+ // assume the upper bits won't be modified or used, but since we |
+ // always clear the upper bits, this is not a good assumption. |
+ // http://code.google.com/p/nativeclient/issues/detail?id=1564 |
+ if (Subtarget->isTargetNaCl64()) { |
+ assert(Base.getValueType() == MVT::i64 && "Unexpected base operand size"); |
+ |
+ if (Index.getValueType() != MVT::i64) { |
+ Index = CurDAG->getZExtOrTrunc(Index, SDLoc(Index), MVT::i64); |
+ // Insert the new node into the topological ordering. |
+ InsertDAGNode(*CurDAG, Parent ? SDValue(Parent, 0) : N, Index); |
+ } |
+ } |
+ // @LOCALMOD-END |
+ |
return true; |
} |
@@ -1438,7 +1544,13 @@ bool X86DAGToDAGISel::SelectLEA64_32Addr(SDValue N, SDValue &Base, |
RegisterSDNode *RN = dyn_cast<RegisterSDNode>(Base); |
if (RN && RN->getReg() == 0) |
Base = CurDAG->getRegister(0, MVT::i64); |
- else if (Base.getValueType() == MVT::i32 && !dyn_cast<FrameIndexSDNode>(Base)) { |
+ // @LOCALMOD-BEGIN: -- the commit in http://reviews.llvm.org/D4929 |
+ // to address: http://llvm.org/bugs/show_bug.cgi?id=20016 |
+ // break's NaCl's test/NaCl/X86/nacl64-addrmodes.ll |
+ // revert to checking N. |
+ // else if (Base.getValueType() == MVT::i32 && !dyn_cast<FrameIndexSDNode>(Base)) { |
+ else if (Base.getValueType() == MVT::i32 && !dyn_cast<FrameIndexSDNode>(N)) { |
+ // @LOCALMOD-END |
// Base could already be %rip, particularly in the x32 ABI. |
Base = SDValue(CurDAG->getMachineNode( |
TargetOpcode::SUBREG_TO_REG, DL, MVT::i64, |
@@ -1478,6 +1590,8 @@ bool X86DAGToDAGISel::SelectLEAAddr(SDValue N, |
SDValue Copy = AM.Segment; |
SDValue T = CurDAG->getRegister(0, MVT::i32); |
AM.Segment = T; |
+ // @LOCALMOD |
+ selectingMemOp = false; |
if (MatchAddress(N, AM)) |
return false; |
assert (T == AM.Segment); |
@@ -1541,7 +1655,8 @@ bool X86DAGToDAGISel::SelectTLSADDRAddr(SDValue N, SDValue &Base, |
AM.Base_Reg = CurDAG->getRegister(0, N.getValueType()); |
AM.SymbolFlags = GA->getTargetFlags(); |
- if (N.getValueType() == MVT::i32) { |
+ if (N.getValueType() == MVT::i32 && |
+ !Subtarget->isTargetNaCl64()) { // @LOCALMOD |
AM.Scale = 1; |
AM.IndexReg = CurDAG->getRegister(X86::EBX, MVT::i32); |
} else { |
@@ -1566,6 +1681,171 @@ bool X86DAGToDAGISel::TryFoldLoad(SDNode *P, SDValue N, |
N.getOperand(1), Base, Scale, Index, Disp, Segment); |
} |
+// @LOCALMOD-BEGIN |
+// LegalizeAddressingModeForNaCl - NaCl specific addressing fixes. This ensures |
+// two addressing mode invariants. |
+// |
+// case 1. Addressing using only a displacement (constant address references) |
+// is only legal when the displacement is positive. This is because, when |
+// later we replace |
+// movl 0xffffffff, %eax |
+// by |
+// movl 0xffffffff(%r15), %eax |
+// the displacement becomes a negative offset from %r15, making this a |
+// reference to the guard region below %r15 rather than to %r15 + 4GB - 1, |
+// as the programmer expected. To handle these cases we pull negative |
+// displacements out whenever there is no base or index register in the |
+// addressing mode. I.e., the above becomes |
+// movl $0xffffffff, %ebx |
+// movl %rbx, %rbx |
+// movl (%r15, %rbx, 1), %eax |
+// |
+// case 2. Because NaCl needs to zero the top 32-bits of the index, we can't |
+// allow the index register to be negative. However, if we are using a base |
+// frame index, global address or the constant pool, and AM.Disp > 0, then |
+// negative values of "index" may be expected to legally occur. |
+// To avoid this, we fold the displacement (and scale) back into the |
+// index. This results in a LEA before the current instruction. |
+// Unfortunately, this may add a requirement for an additional register. |
+// |
+// For example, this sandboxed code is broken if %eax is negative: |
+// |
+// movl %eax,%eax |
+// incl -30(%rbp,%rax,4) |
+// |
+// Instead, we now generate: |
+// leal -30(%rbp,%rax,4), %tmp |
+// movl %tmp,%tmp |
+// incl (%r15,%tmp,1) |
+// |
+// TODO(espindola): This might not be complete since the matcher can select |
+// any dag node to go in the index. This is also not how the rest of the |
+// matcher logic works, if the matcher selects something, it must be |
+// valid and not depend on further patching. A more desirable fix is |
+// probably to update the matching code to avoid assigning a register |
+// to a value that we cannot prove is positive. |
+// |
+// Note: Any changes to the testing logic need to be synchronized |
+// with the implementation of isLegalAddressingModeForNaCl() in |
+// X86FastISel.cpp. |
+void X86DAGToDAGISel::LegalizeAddressingModeForNaCl(SDValue N, |
+ X86ISelAddressMode &AM) { |
+ |
+ |
+ // RIP-relative addressing is always fine. |
+ if (AM.isRIPRelative()) |
+ return; |
+ |
+ SDLoc dl(N); |
+ // Case 1 above: |
+ if (!AM.hasBaseOrIndexReg() && !AM.hasSymbolicDisplacement() && AM.Disp < 0) { |
+ SDValue Imm = CurDAG->getTargetConstant(AM.Disp, MVT::i32); |
+ SDValue MovNode = |
+ SDValue(CurDAG->getMachineNode(X86::MOV32ri, dl, MVT::i32, Imm), 0); |
+ AM.IndexReg = MovNode; |
+ AM.Disp = 0; |
+ InsertDAGNode(*CurDAG, N, MovNode); |
+ return; |
+ } |
+ |
+ // MatchAddress wants to use the base register when there's only |
+ // one register and no scale. We need to use the index register instead. |
+ if (AM.BaseType == X86ISelAddressMode::RegBase && |
+ AM.Base_Reg.getNode() && |
+ !AM.IndexReg.getNode()) { |
+ AM.IndexReg = AM.Base_Reg; |
+ AM.setBaseReg(SDValue()); |
+ } |
+ |
+ // Case 2 above comprises two sub-cases: |
+ // sub-case 1: Prevent negative indexes |
+ |
+ // This is relevant only if there is an index register involved. |
+ if (!AM.IndexReg.getNode()) |
+ return; |
+ |
+ // There are two situations to deal with. The first is as described |
+ // above, which is essentially a potentially negative index into an |
+ // interior pointer to a stack-allocated structure. The second is a |
+ // potentially negative index into an interior pointer to a global |
+ // array. In this case, the global array will be a symbolic |
+ // displacement. In theory, we could recognize that it is an |
+ // interior pointer only when the concrete displacement AM.Disp is |
+ // nonzero, but there is at least one test case (aha.c in the LLVM |
+ // test suite) that incorrectly uses a negative index to dereference |
+ // a global array, so we conservatively apply the translation to all |
+ // global dereferences. |
+ bool HasSymbolic = AM.hasSymbolicDisplacement(); |
+ bool NeedsFixing1 = HasSymbolic || |
+ (AM.BaseType == X86ISelAddressMode::FrameIndexBase && AM.Disp > 0); |
+ |
+ // sub-case 2: Both index and base registers are being used. The |
+ // test for index register being used is done above, so we only need |
+ // to test for a base register being used. |
+ bool NeedsFixing2 = |
+ (AM.BaseType == X86ISelAddressMode::RegBase) && AM.Base_Reg.getNode(); |
+ |
+ if (!NeedsFixing1 && !NeedsFixing2) |
+ return; |
+ |
+ static const unsigned LogTable[] = { ~0u, 0, 1, ~0u, 2, ~0u, ~0u, ~0u, 3 }; |
+ assert(AM.Scale < sizeof(LogTable)/sizeof(LogTable[0])); |
+ unsigned ScaleLog = LogTable[AM.Scale]; |
+ assert(ScaleLog <= 3); |
+ SmallVector<SDNode*, 8> NewNodes; |
+ |
+ SDValue NewIndex = AM.IndexReg; |
+ if (ScaleLog > 0) { |
+ SDValue ShlCount = CurDAG->getConstant(ScaleLog, MVT::i8); |
+ NewNodes.push_back(ShlCount.getNode()); |
+ SDValue ShlNode = CurDAG->getNode(ISD::SHL, dl, N.getValueType(), |
+ NewIndex, ShlCount); |
+ NewNodes.push_back(ShlNode.getNode()); |
+ NewIndex = ShlNode; |
+ } |
+ if (AM.Disp > 0 || HasSymbolic) { |
+ // If the addressing mode has a potentially problematic |
+ // displacement, we pull it out into a new instruction node. If |
+ // it contains a symbolic displacement, we need to express it as a |
+ // Wrapper node to make LLVM work. |
+ SDValue Base, Scale, Index, Disp, Segment; |
+ getAddressOperands(AM, Base, Scale, Index, Disp, Segment); |
+ SDValue DispNode; |
+ if (HasSymbolic) |
+ DispNode = CurDAG->getNode(X86ISD::Wrapper, dl, N.getValueType(), Disp); |
+ else |
+ DispNode = CurDAG->getConstant(AM.Disp, N.getValueType()); |
+ NewNodes.push_back(DispNode.getNode()); |
+ |
+ SDValue AddNode = CurDAG->getNode(ISD::ADD, dl, N.getValueType(), |
+ NewIndex, DispNode); |
+ NewNodes.push_back(AddNode.getNode()); |
+ NewIndex = AddNode; |
+ } |
+ |
+ if (NeedsFixing2) { |
+ SDValue AddBase = CurDAG->getNode(ISD::ADD, dl, N.getValueType(), |
+ NewIndex, AM.Base_Reg); |
+ NewNodes.push_back(AddBase.getNode()); |
+ NewIndex = AddBase; |
+ AM.setBaseReg(SDValue()); |
+ } |
+ AM.Disp = 0; |
+ AM.clearSymbolicDisplacement(); |
+ AM.Scale = 1; |
+ AM.IndexReg = NewIndex; |
+ |
+ // Insert the new nodes into the topological ordering. |
+ for (unsigned i=0; i < NewNodes.size(); i++) { |
+ if (NewNodes[i]->getNodeId() == -1 || |
+ NewNodes[i]->getNodeId() > N.getNode()->getNodeId()) { |
+ CurDAG->RepositionNode(N.getNode(), NewNodes[i]); |
+ NewNodes[i]->setNodeId(N.getNode()->getNodeId()); |
+ } |
+ } |
+} |
+// @LOCALMOD-END |
+ |
/// getGlobalBaseReg - Return an SDNode that returns the value of |
/// the global base register. Output instructions required to |
/// initialize the global base register, if necessary. |