Index: lib/Target/X86/X86FastISel.cpp |
diff --git a/lib/Target/X86/X86FastISel.cpp b/lib/Target/X86/X86FastISel.cpp |
index d43d1bce17704253d904eb25fb6294f666389ef3..c2fb20a17129953a47c1f2b77d64505b7ae4229a 100644 |
--- a/lib/Target/X86/X86FastISel.cpp |
+++ b/lib/Target/X86/X86FastISel.cpp |
@@ -39,8 +39,14 @@ |
#include "llvm/IR/Operator.h" |
#include "llvm/Support/ErrorHandling.h" |
#include "llvm/Target/TargetOptions.h" |
+#include "llvm/ADT/Statistic.h" // @LOCALMOD |
using namespace llvm; |
+// @LOCALMOD-BEGIN |
+#define DEBUG_TYPE "isel" |
+STATISTIC(NumFastIselNaClFailures, "Number of instructions fast isel failed on for NaCl illegality"); |
+// @LOCALMOD-END |
+ |
namespace { |
class X86FastISel final : public FastISel { |
@@ -501,6 +507,85 @@ bool X86FastISel::X86FastEmitExtend(ISD::NodeType Opc, EVT DstVT, |
return true; |
} |
+/// @LOCALMOD-BEGIN |
+/// isLegalAddressingModeForNaCl - Determine if the addressing mode is |
+/// legal for NaCl translation. If not, the caller is expected to |
+/// reject the instruction for fast-ISel code generation. |
+/// |
+/// The logic for the test is translated from the corresponding logic |
+/// in X86DAGToDAGISel::LegalizeAddressingModeForNaCl(). It can't be |
+/// used directly due to the X86AddressMode vs X86ISelAddressMode |
+/// types. As such, any changes to isLegalAddressingModeForNaCl() and |
+/// X86DAGToDAGISel::LegalizeAddressingModeForNaCl() need to be |
+/// synchronized. The original conditions are indicated in comments. |
+static bool isLegalAddressingModeForNaCl(const X86Subtarget *Subtarget, |
+ const X86AddressMode &AM) { |
+ if (Subtarget->isTargetNaCl64()) { |
+ // Return true (i.e., is legal) if the equivalent of |
+ // X86ISelAddressMode::isRIPRelative() is true. |
+ if (AM.BaseType == X86AddressMode::RegBase && |
+ AM.Base.Reg == X86::RIP) |
+ return true; |
+ |
+ // Check for the equivalent of |
+ // (!AM.hasBaseOrIndexReg() && |
+ // !AM.hasSymbolicDisplacement() && |
+ // AM.Disp < 0) |
+ if (!((AM.BaseType == X86AddressMode::RegBase && AM.Base.Reg) || |
+ AM.IndexReg) && |
+ !AM.GV && |
+ AM.Disp < 0) { |
+ ++NumFastIselNaClFailures; |
+ return false; |
+ } |
+ |
+ // At this point in the LegalizeAddressingModeForNaCl() code, it |
+ // normalizes an addressing mode with a base register and no index |
+ // register into an equivalent mode with an index register and no |
+ // base register. Since we don't modify AM, we may have to check |
+ // both the base and index register fields in the remainder of the |
+ // tests. |
+ |
+ // Check for the equivalent of |
+ // ((AM.BaseType == X86ISelAddressMode::FrameIndexBase || AM.GV || AM.CP) && |
+ // AM.IndexReg.getNode() && |
+ // AM.Disp > 0) |
+ // Note: X86AddressMode doesn't have a CP analogue |
+ if ((AM.BaseType == X86AddressMode::FrameIndexBase || AM.GV) && |
+ ((AM.BaseType == X86AddressMode::RegBase && AM.Base.Reg) || |
+ AM.IndexReg) && |
+ AM.Disp > 0) { |
+ ++NumFastIselNaClFailures; |
+ return false; |
+ } |
+ |
+ // Check for the equivalent of |
+ // ((AM.BaseType == X86ISelAddressMode::RegBase) && |
+ // AM.Base_Reg.getNode() && |
+ // AM.IndexReg.getNode()) |
+ if ((AM.BaseType == X86AddressMode::RegBase) && |
+ AM.Base.Reg && |
+ AM.IndexReg) { |
+ ++NumFastIselNaClFailures; |
+ return false; |
+ } |
+ |
+ // See X86DAGToDAGISel::FoldOffsetIntoAddress(). |
+ // Check for the equivalent of |
+ // ((AM.BaseType == X86ISelAddressMode::RegBase || |
+ // AM.BaseType == X86ISelAddressMode::FrameIndexBase) && |
+ // (Val > 65535 || Val < -65536)) |
+ if ((AM.BaseType == X86AddressMode::RegBase || |
+ AM.BaseType == X86AddressMode::FrameIndexBase) && |
+ (AM.Disp > 65535 || AM.Disp < -65536)) { |
+ ++NumFastIselNaClFailures; |
+ return false; |
+ } |
+ } |
+ |
+ return true; |
+} |
+ |
bool X86FastISel::handleConstantAddresses(const Value *V, X86AddressMode &AM) { |
// Handle constant address. |
if (const GlobalValue *GV = dyn_cast<GlobalValue>(V)) { |
@@ -566,6 +651,14 @@ bool X86FastISel::handleConstantAddresses(const Value *V, X86AddressMode &AM) { |
if (Subtarget->isPICStyleRIPRel()) |
StubAM.Base.Reg = X86::RIP; |
+ // @LOCALMOD-BEGIN |
+ } else if (Subtarget->isTargetNaCl64()) { |
+ Opc = X86::MOV32rm; |
+ RC = &X86::GR32RegClass; |
+ |
+ if (Subtarget->isPICStyleRIPRel()) |
+ StubAM.Base.Reg = X86::RIP; |
+ // @LOCALMOD-END |
} else { |
Opc = X86::MOV32rm; |
RC = &X86::GR32RegClass; |
@@ -593,6 +686,21 @@ bool X86FastISel::handleConstantAddresses(const Value *V, X86AddressMode &AM) { |
// If all else fails, try to materialize the value in a register. |
if (!AM.GV || !Subtarget->isPICStyleRIPRel()) { |
+ // @LOCALMOD-START |
+ if (Subtarget->isTargetNaCl64()) { |
+ // We are about use a register in an addressing mode. However, x86-64 |
+ // NaCl does not allow arbitrary r+r addressing. One of the regs must |
+ // be %r15 (inserted by the NaClRewritePass). Check that we will only |
+ // end up with one reg defined after this. |
+ if ((AM.Base.Reg == 0) && (AM.IndexReg == 0)) { |
+ // Put into index register so that the NaCl rewrite pass will |
+ // convert this to a 64-bit address. |
+ AM.IndexReg = getRegForValue(V); |
+ return AM.IndexReg != 0; |
+ } |
+ return false; |
+ } |
+ // @LOCALMOD-END |
if (AM.Base.Reg == 0) { |
AM.Base.Reg = getRegForValue(V); |
return AM.Base.Reg != 0; |
@@ -609,6 +717,16 @@ bool X86FastISel::handleConstantAddresses(const Value *V, X86AddressMode &AM) { |
/// X86SelectAddress - Attempt to fill in an address from the given value. |
/// |
+/// @LOCALMOD-BEGIN |
+/// All "return v;" statements must be converted to |
+/// "return (v) && isLegalAddressingModeForNaCl(Subtarget, AM);" |
+/// except that "return false;" can of course be left unchanged. |
+/// |
+/// Since X86SelectAddress() recursively builds up the AM result |
+/// object, there is a risk that an intermediate result could be |
+/// rejected in a situation where the final result was in fact legal, |
+/// though it is hard to imagine this happening. |
+/// @LOCALMOD-END |
bool X86FastISel::X86SelectAddress(const Value *V, X86AddressMode &AM) { |
SmallVector<const Value *, 32> GEPs; |
redo_gep: |
@@ -660,7 +778,7 @@ redo_gep: |
if (SI != FuncInfo.StaticAllocaMap.end()) { |
AM.BaseType = X86AddressMode::FrameIndexBase; |
AM.Base.FrameIndex = SI->second; |
- return true; |
+ return isLegalAddressingModeForNaCl(Subtarget, AM); // @LOCALMOD |
} |
break; |
} |
@@ -746,7 +864,7 @@ redo_gep: |
V = GEP; |
goto redo_gep; |
} else if (X86SelectAddress(U->getOperand(0), AM)) { |
- return true; |
+ return isLegalAddressingModeForNaCl(Subtarget, AM); // @LOCALMOD |
} |
// If we couldn't merge the gep value into this addr mode, revert back to |
@@ -756,7 +874,7 @@ redo_gep: |
for (SmallVectorImpl<const Value *>::reverse_iterator |
I = GEPs.rbegin(), E = GEPs.rend(); I != E; ++I) |
if (handleConstantAddresses(*I, AM)) |
- return true; |
+ return isLegalAddressingModeForNaCl(Subtarget, AM); // @LOCALMOD |
return false; |
unsupported_gep: |
@@ -765,7 +883,11 @@ redo_gep: |
} |
} |
- return handleConstantAddresses(V, AM); |
+ // @LOCALMOD-START |
+ if (handleConstantAddresses(V, AM)) |
+ return isLegalAddressingModeForNaCl(Subtarget, AM); |
+ return false; |
+ // @LOCALMOD-END |
} |
/// X86SelectCallAddress - Attempt to fill in an address from the given value. |
@@ -1029,10 +1151,15 @@ bool X86FastISel::X86SelectRet(const Instruction *I) { |
unsigned Reg = X86MFInfo->getSRetReturnReg(); |
assert(Reg && |
"SRetReturnReg should have been set in LowerFormalArguments()!"); |
- unsigned RetReg = Subtarget->is64Bit() ? X86::RAX : X86::EAX; |
+ // @LOCALMOD-BEGIN -- Ensure that the register classes match. |
+ // At this point, SRetReturnReg is EDI, because PointerTy() for NaCl |
+ // is i32. We then copy to EAX instead of RAX. Alternatively, we could |
+ // have zero-extended EDI to RDI then copy to RAX, but this has a smaller |
+ // encoding (2 bytes vs 3 bytes). |
+ unsigned CopyTo = Subtarget->isTarget64BitLP64() ? X86::RAX : X86::EAX; |
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(TargetOpcode::COPY), |
- RetReg).addReg(Reg); |
- RetRegs.push_back(RetReg); |
+ CopyTo).addReg(Reg); |
+ // @LOCALMOD-END |
} |
// Now emit the RET. |
@@ -2107,6 +2234,7 @@ bool X86FastISel::TryEmitSmallMemcpy(X86AddressMode DestAM, |
else if (Len >= 2) |
VT = MVT::i16; |
else { |
+ assert(Len == 1); |
VT = MVT::i8; |
} |
@@ -2144,14 +2272,14 @@ bool X86FastISel::fastLowerIntrinsicCall(const IntrinsicInst *II) { |
case MVT::i64: Opc = X86::MOV64rm; RC = &X86::GR64RegClass; break; |
} |
- // This needs to be set before we call getFrameRegister, otherwise we get |
- // the wrong frame register. |
+ // This needs to be set before we call getPtrSizedFrameRegister, otherwise |
+ // we get the wrong frame register. |
MachineFrameInfo *MFI = FuncInfo.MF->getFrameInfo(); |
MFI->setFrameAddressIsTaken(true); |
const X86RegisterInfo *RegInfo = static_cast<const X86RegisterInfo *>( |
TM.getSubtargetImpl()->getRegisterInfo()); |
- unsigned FrameReg = RegInfo->getFrameRegister(*(FuncInfo.MF)); |
+ unsigned FrameReg = RegInfo->getPtrSizedFrameRegister(*(FuncInfo.MF)); |
assert(((FrameReg == X86::RBP && VT == MVT::i64) || |
(FrameReg == X86::EBP && VT == MVT::i32)) && |
"Invalid Frame Register!"); |
@@ -2900,13 +3028,32 @@ bool X86FastISel::fastLowerCall(CallLoweringInfo &CLI) { |
MachineInstrBuilder MIB; |
if (CalleeOp) { |
// Register-indirect call. |
- unsigned CallOpc = Is64Bit ? X86::CALL64r : X86::CALL32r; |
+ unsigned CallOpc; |
+ if (Subtarget->is64Bit()) { |
+ // @LOCALMOD-BEGIN: zero extend the register like in the non-O0 case: |
+ // http://reviews.llvm.org/D5355 |
+ // TODO: upstream this for x32 also (add a test). |
+ if (Subtarget->isTarget64BitILP32()) { |
+ unsigned CalleeOp32 = CalleeOp; |
+ CalleeOp = createResultReg(&X86::GR64RegClass); |
+ BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, |
+ TII.get(TargetOpcode::SUBREG_TO_REG), CalleeOp) |
+ .addImm(0).addReg(CalleeOp32).addImm(X86::sub_32bit); |
+ } |
+ // @LOCALMOD-END |
+ CallOpc = X86::CALL64r; |
+ } else |
+ CallOpc = X86::CALL32r; |
MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(CallOpc)) |
.addReg(CalleeOp); |
} else { |
// Direct call. |
assert(GV && "Not a direct call"); |
- unsigned CallOpc = Is64Bit ? X86::CALL64pcrel32 : X86::CALLpcrel32; |
+ unsigned CallOpc; |
+ if (Subtarget->is64Bit()) |
+ CallOpc = Subtarget->isTargetNaCl() ? X86::NACL_CG_CALL64pcrel32 : X86::CALL64pcrel32; // @LOCALMOD |
+ else |
+ CallOpc = X86::CALLpcrel32; |
// See if we need any target-specific flags on the GV operand. |
unsigned char OpFlags = 0; |