diff options
21 files changed, 179 insertions, 85 deletions
diff --git a/include/llvm/CodeGen/MachineInstrBuilder.h b/include/llvm/CodeGen/MachineInstrBuilder.h index c63487d19d..f57168b276 100644 --- a/include/llvm/CodeGen/MachineInstrBuilder.h +++ b/include/llvm/CodeGen/MachineInstrBuilder.h @@ -79,13 +79,14 @@ public: } const MachineInstrBuilder &addGlobalAddress(GlobalValue *GV, - int Offset = 0) const { + int64_t Offset = 0) const { MI->addOperand(MachineOperand::CreateGA(GV, Offset)); return *this; } - const MachineInstrBuilder &addExternalSymbol(const char *FnName) const{ - MI->addOperand(MachineOperand::CreateES(FnName, 0)); + const MachineInstrBuilder &addExternalSymbol(const char *FnName, + int64_t Offset = 0) const { + MI->addOperand(MachineOperand::CreateES(FnName, Offset)); return *this; } }; diff --git a/include/llvm/CodeGen/MachineOperand.h b/include/llvm/CodeGen/MachineOperand.h index f9d80c7fcc..e3cc814011 100644 --- a/include/llvm/CodeGen/MachineOperand.h +++ b/include/llvm/CodeGen/MachineOperand.h @@ -101,7 +101,7 @@ private: const char *SymbolName; // For MO_ExternalSymbol. GlobalValue *GV; // For MO_GlobalAddress. } Val; - int Offset; // An offset from the object. + int64_t Offset; // An offset from the object. } OffsetedInfo; } Contents; @@ -273,7 +273,7 @@ public: return Contents.OffsetedInfo.Val.GV; } - int getOffset() const { + int64_t getOffset() const { assert((isGlobal() || isSymbol() || isCPI()) && "Wrong MachineOperand accessor"); return Contents.OffsetedInfo.Offset; @@ -293,7 +293,7 @@ public: Contents.ImmVal = immVal; } - void setOffset(int Offset) { + void setOffset(int64_t Offset) { assert((isGlobal() || isSymbol() || isCPI()) && "Wrong MachineOperand accessor"); Contents.OffsetedInfo.Offset = Offset; @@ -382,13 +382,13 @@ public: Op.setIndex(Idx); return Op; } - static MachineOperand CreateGA(GlobalValue *GV, int Offset) { + static MachineOperand CreateGA(GlobalValue *GV, int64_t Offset) { MachineOperand Op(MachineOperand::MO_GlobalAddress); Op.Contents.OffsetedInfo.Val.GV = GV; Op.setOffset(Offset); return Op; } - static MachineOperand CreateES(const char *SymName, int Offset = 0) { + static MachineOperand CreateES(const char *SymName, int64_t Offset = 0) { MachineOperand Op(MachineOperand::MO_ExternalSymbol); Op.Contents.OffsetedInfo.Val.SymbolName = SymName; Op.setOffset(Offset); diff --git a/include/llvm/CodeGen/SelectionDAG.h b/include/llvm/CodeGen/SelectionDAG.h index d6a40a68a2..a6f9c1beed 100644 --- a/include/llvm/CodeGen/SelectionDAG.h +++ b/include/llvm/CodeGen/SelectionDAG.h @@ -255,9 +255,9 @@ public: return getConstantFP(Val, VT, true); } SDValue getGlobalAddress(const GlobalValue *GV, MVT VT, - int offset = 0, bool isTargetGA = false); + int64_t offset = 0, bool isTargetGA = false); SDValue getTargetGlobalAddress(const GlobalValue *GV, MVT VT, - int offset = 0) { + int64_t offset = 0) { return getGlobalAddress(GV, VT, offset, true); } SDValue getFrameIndex(int FI, MVT VT, bool isTarget = false); diff --git a/include/llvm/CodeGen/SelectionDAGNodes.h b/include/llvm/CodeGen/SelectionDAGNodes.h index 94c8dadd96..494783229a 100644 --- a/include/llvm/CodeGen/SelectionDAGNodes.h +++ b/include/llvm/CodeGen/SelectionDAGNodes.h @@ -1819,15 +1819,16 @@ public: class GlobalAddressSDNode : public SDNode { GlobalValue *TheGlobal; - int Offset; + int64_t Offset; virtual void ANCHOR(); // Out-of-line virtual method to give class a home. protected: friend class SelectionDAG; - GlobalAddressSDNode(bool isTarget, const GlobalValue *GA, MVT VT, int o = 0); + GlobalAddressSDNode(bool isTarget, const GlobalValue *GA, MVT VT, + int64_t o = 0); public: GlobalValue *getGlobal() const { return TheGlobal; } - int getOffset() const { return Offset; } + int64_t getOffset() const { return Offset; } static bool classof(const GlobalAddressSDNode *) { return true; } static bool classof(const SDNode *N) { diff --git a/include/llvm/Target/TargetLowering.h b/include/llvm/Target/TargetLowering.h index 5e5bdbe511..85e90af5ad 100644 --- a/include/llvm/Target/TargetLowering.h +++ b/include/llvm/Target/TargetLowering.h @@ -653,6 +653,11 @@ public: virtual SDValue getPICJumpTableRelocBase(SDValue Table, SelectionDAG &DAG) const; + /// isOffsetFoldingLegal - Return true if folding a constant offset + /// with the given GlobalAddress is legal. It is frequently not legal in + /// PIC relocation models. + virtual bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const; + //===--------------------------------------------------------------------===// // TargetLowering Optimization Methods // diff --git a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index 4b1945efe4..81058152eb 100644 --- a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -967,6 +967,13 @@ SDValue DAGCombiner::visitADD(SDNode *N) { // fold (add x, 0) -> x if (N1C && N1C->isNullValue()) return N0; + // fold (add Sym, c) -> Sym+c + if (GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(N0)) + if (!AfterLegalize && TLI.isOffsetFoldingLegal(GA) && N1C && + GA->getOpcode() == ISD::GlobalAddress) + return DAG.getGlobalAddress(GA->getGlobal(), VT, + GA->getOffset() + + (uint64_t)N1C->getSExtValue()); // fold ((c1-A)+c2) -> (c1+c2)-A if (N1C && N0.getOpcode() == ISD::SUB) if (ConstantSDNode *N0C = dyn_cast<ConstantSDNode>(N0.getOperand(0))) @@ -1133,6 +1140,21 @@ SDValue DAGCombiner::visitSUB(SDNode *N) { if (N1.getOpcode() == ISD::UNDEF) return N1; + // If the relocation model supports it, consider symbol offsets. + if (GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(N0)) + if (!AfterLegalize && TLI.isOffsetFoldingLegal(GA)) { + // fold (sub Sym, c) -> Sym-c + if (N1C && GA->getOpcode() == ISD::GlobalAddress) + return DAG.getGlobalAddress(GA->getGlobal(), VT, + GA->getOffset() - + (uint64_t)N1C->getSExtValue()); + // fold (sub Sym+c1, Sym+c2) -> c1-c2 + if (GlobalAddressSDNode *GB = dyn_cast<GlobalAddressSDNode>(N1)) + if (GA->getGlobal() == GB->getGlobal()) + return DAG.getConstant((uint64_t)GA->getOffset() - GB->getOffset(), + VT); + } + return SDValue(); } diff --git a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index 9cfb1a1a22..07819404e1 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -959,10 +959,15 @@ SDValue SelectionDAG::getConstantFP(double Val, MVT VT, bool isTarget) { } SDValue SelectionDAG::getGlobalAddress(const GlobalValue *GV, - MVT VT, int Offset, + MVT VT, int64_t Offset, bool isTargetGA) { unsigned Opc; + // Truncate (with sign-extension) the offset value to the pointer size. + unsigned BitWidth = VT.getSizeInBits(); + if (BitWidth < 64) + Offset = (Offset << (64 - BitWidth) >> (64 - BitWidth)); + const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GV); if (!GVar) { // If GV is an alias then use the aliasee for determining thread-localness. @@ -2017,6 +2022,7 @@ unsigned SelectionDAG::ComputeNumSignBits(SDValue Op, unsigned Depth) const{ bool SelectionDAG::isVerifiedDebugInfoDesc(SDValue Op) const { GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Op); if (!GA) return false; + if (GA->getOffset() != 0) return false; GlobalVariable *GV = dyn_cast<GlobalVariable>(GA->getGlobal()); if (!GV) return false; MachineModuleInfo *MMI = getMachineModuleInfo(); @@ -4726,7 +4732,7 @@ HandleSDNode::~HandleSDNode() { } GlobalAddressSDNode::GlobalAddressSDNode(bool isTarget, const GlobalValue *GA, - MVT VT, int o) + MVT VT, int64_t o) : SDNode(isa<GlobalVariable>(GA) && cast<GlobalVariable>(GA)->isThreadLocal() ? // Thread Local diff --git a/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/lib/CodeGen/SelectionDAG/TargetLowering.cpp index 479e1380c5..1e7e847b8a 100644 --- a/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -656,6 +656,23 @@ SDValue TargetLowering::getPICJumpTableRelocBase(SDValue Table, return Table; } +bool +TargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const { + // Assume that everything is safe in static mode. + if (getTargetMachine().getRelocationModel() == Reloc::Static) + return true; + + // In dynamic-no-pic mode, assume that known defined values are safe. + if (getTargetMachine().getRelocationModel() == Reloc::DynamicNoPIC && + GA && + !GA->getGlobal()->isDeclaration() && + !GA->getGlobal()->mayBeOverridden()) + return true; + + // Otherwise assume nothing is safe. + return false; +} + //===----------------------------------------------------------------------===// // Optimization Methods //===----------------------------------------------------------------------===// diff --git a/lib/Target/Alpha/AlphaISelLowering.cpp b/lib/Target/Alpha/AlphaISelLowering.cpp index 33445f0fa4..7878830735 100644 --- a/lib/Target/Alpha/AlphaISelLowering.cpp +++ b/lib/Target/Alpha/AlphaISelLowering.cpp @@ -764,3 +764,9 @@ AlphaTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, return sinkMBB; } + +bool +AlphaTargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const { + // The Alpha target isn't yet aware of offsets. + return false; +} diff --git a/lib/Target/Alpha/AlphaISelLowering.h b/lib/Target/Alpha/AlphaISelLowering.h index 0a78997b19..3e870aff88 100644 --- a/lib/Target/Alpha/AlphaISelLowering.h +++ b/lib/Target/Alpha/AlphaISelLowering.h @@ -95,6 +95,8 @@ namespace llvm { MachineBasicBlock *EmitInstrWithCustomInserter(MachineInstr *MI, MachineBasicBlock *BB); + virtual bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const; + private: // Helpers for custom lowering. void LowerVAARG(SDNode *N, SDValue &Chain, SDValue &DataPtr, diff --git a/lib/Target/CellSPU/SPUISelLowering.cpp b/lib/Target/CellSPU/SPUISelLowering.cpp index 086a25f1d8..659ba7530d 100644 --- a/lib/Target/CellSPU/SPUISelLowering.cpp +++ b/lib/Target/CellSPU/SPUISelLowering.cpp @@ -3058,3 +3058,9 @@ bool SPUTargetLowering::isLegalAddressImmediate(int64_t V, bool SPUTargetLowering::isLegalAddressImmediate(llvm::GlobalValue* GV) const { return false; } + +bool +SPUTargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const { + // The SPU target isn't yet aware of offsets. + return false; +} diff --git a/lib/Target/CellSPU/SPUISelLowering.h b/lib/Target/CellSPU/SPUISelLowering.h index e79b1363f2..54aac66571 100644 --- a/lib/Target/CellSPU/SPUISelLowering.h +++ b/lib/Target/CellSPU/SPUISelLowering.h @@ -139,6 +139,8 @@ namespace llvm { /// as the offset of the target addressing mode. virtual bool isLegalAddressImmediate(int64_t V, const Type *Ty) const; virtual bool isLegalAddressImmediate(GlobalValue *) const; + + virtual bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const; }; } diff --git a/lib/Target/Mips/MipsISelLowering.cpp b/lib/Target/Mips/MipsISelLowering.cpp index 3224d73d5f..8fdc4b799b 100644 --- a/lib/Target/Mips/MipsISelLowering.cpp +++ b/lib/Target/Mips/MipsISelLowering.cpp @@ -1094,3 +1094,9 @@ getRegClassForInlineAsmConstraint(const std::string &Constraint, } return std::vector<unsigned>(); } + +bool +MipsTargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const { + // The Mips target isn't yet aware of offsets. + return false; +} diff --git a/lib/Target/Mips/MipsISelLowering.h b/lib/Target/Mips/MipsISelLowering.h index b19ce58d2b..5704b7ef8e 100644 --- a/lib/Target/Mips/MipsISelLowering.h +++ b/lib/Target/Mips/MipsISelLowering.h @@ -118,6 +118,8 @@ namespace llvm { std::vector<unsigned> getRegClassForInlineAsmConstraint(const std::string &Constraint, MVT VT) const; + + virtual bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const; }; } diff --git a/lib/Target/Sparc/SparcISelLowering.cpp b/lib/Target/Sparc/SparcISelLowering.cpp index e81688e4e8..59e19d5466 100644 --- a/lib/Target/Sparc/SparcISelLowering.cpp +++ b/lib/Target/Sparc/SparcISelLowering.cpp @@ -996,3 +996,9 @@ getRegClassForInlineAsmConstraint(const std::string &Constraint, return std::vector<unsigned>(); } + +bool +SparcTargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const { + // The Sparc target isn't yet aware of offsets. + return false; +} diff --git a/lib/Target/Sparc/SparcISelLowering.h b/lib/Target/Sparc/SparcISelLowering.h index ea3171d027..a0e3c65344 100644 --- a/lib/Target/Sparc/SparcISelLowering.h +++ b/lib/Target/Sparc/SparcISelLowering.h @@ -70,6 +70,8 @@ namespace llvm { std::vector<unsigned> getRegClassForInlineAsmConstraint(const std::string &Constraint, MVT VT) const; + + virtual bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const; }; } // end namespace llvm diff --git a/lib/Target/X86/X86ISelDAGToDAG.cpp b/lib/Target/X86/X86ISelDAGToDAG.cpp index cf83e68192..6735f1d80b 100644 --- a/lib/Target/X86/X86ISelDAGToDAG.cpp +++ b/lib/Target/X86/X86ISelDAGToDAG.cpp @@ -759,6 +759,7 @@ void X86DAGToDAGISel::EmitFunctionEntryCode(Function &Fn, MachineFunction &MF) { /// addressing mode. bool X86DAGToDAGISel::MatchAddress(SDValue N, X86ISelAddressMode &AM, bool isRoot, unsigned Depth) { + bool is64Bit = Subtarget->is64Bit(); DOUT << "MatchAddress: "; DEBUG(AM.dump()); // Limit recursion. if (Depth > 5) @@ -768,7 +769,7 @@ bool X86DAGToDAGISel::MatchAddress(SDValue N, X86ISelAddressMode &AM, if (AM.isRIPRel) { if (!AM.ES && AM.JT != -1 && N.getOpcode() == ISD::Constant) { int64_t Val = cast<ConstantSDNode>(N)->getSExtValue(); - if (isInt32(AM.Disp + Val)) { + if (!is64Bit || isInt32(AM.Disp + Val)) { AM.Disp += Val; return false; } @@ -783,7 +784,7 @@ bool X86DAGToDAGISel::MatchAddress(SDValue N, X86ISelAddressMode &AM, default: break; case ISD::Constant: { int64_t Val = cast<ConstantSDNode>(N)->getSExtValue(); - if (isInt32(AM.Disp + Val)) { + if (!is64Bit || isInt32(AM.Disp + Val)) { AM.Disp += Val; return false; } @@ -791,10 +792,9 @@ bool X86DAGToDAGISel::MatchAddress(SDValue N, X86ISelAddressMode &AM, } case X86ISD::Wrapper: { -DOUT << "Wrapper: 64bit " << Subtarget->is64Bit(); -DOUT << " AM "; DEBUG(AM.dump()); DOUT << "\n"; -DOUT << "AlreadySelected " << AlreadySelected << "\n"; - bool is64Bit = Subtarget->is64Bit(); + DOUT << "Wrapper: 64bit " << is64Bit; + DOUT << " AM "; DEBUG(AM.dump()); DOUT << "\n"; + DOUT << "AlreadySelected " << AlreadySelected << "\n"; // Under X86-64 non-small code model, GV (and friends) are 64-bits. // Also, base and index reg must be 0 in order to use rip as base. if (is64Bit && (TM.getCodeModel() != CodeModel::Small || @@ -808,17 +808,21 @@ DOUT << "AlreadySelected " << AlreadySelected << "\n"; if (!AlreadySelected || (AM.Base.Reg.getNode() && AM.IndexReg.getNode())) { SDValue N0 = N.getOperand(0); if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(N0)) { - GlobalValue *GV = G->getGlobal(); - AM.GV = GV; - AM.Disp += G->getOffset(); - AM.isRIPRel = TM.symbolicAddressesAreRIPRel(); - return false; + if (!is64Bit || isInt32(AM.Disp + G->getOffset())) { + GlobalValue *GV = G->getGlobal(); + AM.GV = GV; + AM.Disp += G->getOffset(); + AM.isRIPRel = TM.symbolicAddressesAreRIPRel(); + return false; + } } else if (ConstantPoolSDNode *CP = dyn_cast<ConstantPoolSDNode>(N0)) { - AM.CP = CP->getConstVal(); - AM.Align = CP->getAlignment(); - AM.Disp += CP->getOffset(); - AM.isRIPRel = TM.symbolicAddressesAreRIPRel(); - return false; + if (!is64Bit || isInt32(AM.Disp + CP->getOffset())) { + AM.CP = CP->getConstVal(); + AM.Align = CP->getAlignment(); + AM.Disp += CP->getOffset(); + AM.isRIPRel = TM.symbolicAddressesAreRIPRel(); + return false; + } } else if (ExternalSymbolSDNode *S =dyn_cast<ExternalSymbolSDNode>(N0)) { AM.ES = S->getSymbol(); AM.isRIPRel = TM.symbolicAddressesAreRIPRel(); @@ -862,7 +866,7 @@ DOUT << "AlreadySelected " << AlreadySelected << "\n"; ConstantSDNode *AddVal = cast<ConstantSDNode>(ShVal.getNode()->getOperand(1)); uint64_t Disp = AM.Disp + (AddVal->getZExtValue() << Val); - if (isInt32(Disp)) + if (!is64Bit || isInt32(Disp)) AM.Disp = Disp; else AM.IndexReg = ShVal; @@ -905,7 +909,7 @@ DOUT << "AlreadySelected " << AlreadySelected << "\n"; cast<ConstantSDNode>(MulVal.getNode()->getOperand(1)); uint64_t Disp = AM.Disp + AddVal->getZExtValue() * CN->getZExtValue(); - if (isInt32(Disp)) + if (!is64Bit || isInt32(Disp)) AM.Disp = Disp; else Reg = N.getNode()->getOperand(0); @@ -944,7 +948,7 @@ DOUT << "AlreadySelected " << AlreadySelected << "\n"; // Address could not have picked a GV address for the displacement. AM.GV == NULL && // On x86-64, the resultant disp must fit in 32-bits. - isInt32(AM.Disp + CN->getSExtValue()) && + (!is64Bit || isInt32(AM.Disp + CN->getSExtValue())) && // Check to see if the LHS & C is zero. CurDAG->MaskedValueIsZero(N.getOperand(0), CN->getAPIntValue())) { AM.Disp += CN->getZExtValue(); @@ -1248,49 +1252,6 @@ SDNode *X86DAGToDAGISel::Select(SDValue N) { case X86ISD::GlobalBaseReg: return getGlobalBaseReg(); - case ISD::ADD: { - // Turn ADD X, c to MOV32ri X+c. This cannot be done with tblgen'd - // code and is matched first so to prevent it from being turned into - // LEA32r X+c. - // In 64-bit small code size mode, use LEA to take advantage of - // RIP-relative addressing. - if (TM.getCodeModel() != CodeModel::Small) - break; - MVT PtrVT = TLI.getPointerTy(); - SDValue N0 = N.getOperand(0); - SDValue N1 = N.getOperand(1); - if (N.getNode()->getValueType(0) == PtrVT && - N0.getOpcode() == X86ISD::Wrapper && - N1.getOpcode() == ISD::Constant) { - unsigned Offset = (unsigned)cast<ConstantSDNode>(N1)->getZExtValue(); - SDValue C(0, 0); - // TODO: handle ExternalSymbolSDNode. - if (GlobalAddressSDNode *G = - dyn_cast<GlobalAddressSDNode>(N0.getOperand(0))) { - C = CurDAG->getTargetGlobalAddress(G->getGlobal(), PtrVT, - G->getOffset() + Offset); - } else if (ConstantPoolSDNode *CP = - dyn_cast<ConstantPoolSDNode>(N0.getOperand(0))) { - C = CurDAG->getTargetConstantPool(CP->getConstVal(), PtrVT, - CP->getAlignment(), - CP->getOffset()+Offset); - } - - if (C.getNode()) { - if (Subtarget->is64Bit()) { - SDValue Ops[] = { CurDAG->getRegister(0, PtrVT), getI8Imm(1), - CurDAG->getRegister(0, PtrVT), C }; - return CurDAG->SelectNodeTo(N.getNode(), X86::LEA64r, - MVT::i64, Ops, 4); - } else - return CurDAG->SelectNodeTo(N.getNode(), X86::MOV32ri, PtrVT, C); - } - } - - // Other cases are handled by auto-generated code. - break; - } - case X86ISD::ATOMOR64_DAG: return SelectAtomic64(Node, X86::ATOMOR6432); case X86ISD::ATOMXOR64_DAG: diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index fa467693bc..c977dbe92b 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -1705,7 +1705,8 @@ SDValue X86TargetLowering::LowerCALL(SDValue Op, SelectionDAG &DAG) { // non-JIT mode. if (!Subtarget->GVRequiresExtraLoad(G->getGlobal(), getTargetMachine(), true)) - Callee = DAG.getTargetGlobalAddress(G->getGlobal(), getPointerTy()); + Callee = DAG.getTargetGlobalAddress(G->getGlobal(), getPointerTy(), + G->getOffset()); } else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) { Callee = DAG.getTargetExternalSymbol(S->getSymbol(), getPointerTy()); } else if (IsTailCall) { @@ -4390,12 +4391,24 @@ X86TargetLowering::LowerConstantPool(SDValue Op, SelectionDAG &DAG) { SDValue X86TargetLowering::LowerGlobalAddress(const GlobalValue *GV, + int64_t Offset, SelectionDAG &DAG) const { - SDValue Result = DAG.getTargetGlobalAddress(GV, getPointerTy()); + bool IsPic = getTargetMachine().getRelocationModel() == Reloc::PIC_; + bool ExtraLoadRequired = + Subtarget->GVRequiresExtraLoad(GV, getTargetMachine(), false); + + // Create the TargetGlobalAddress node, folding in the constant + // offset if it is legal. + SDValue Result; + if (!IsPic && !ExtraLoadRequired) { + Result = DAG.getTargetGlobalAddress(GV, getPointerTy(), Offset); + Offset = 0; + } else + Result = DAG.getTargetGlobalAddress(GV, getPointerTy(), 0); Result = DAG.getNode(X86ISD::Wrapper, getPointerTy(), Result); + // With PIC, the address is actually $g + Offset. - if (getTargetMachine().getRelocationModel() == Reloc::PIC_ && - !Subtarget->isPICStyleRIPRel()) { + if (IsPic && !Subtarget->isPICStyleRIPRel()) { Result = DAG.getNode(ISD::ADD, getPointerTy(), DAG.getNode(X86ISD::GlobalBaseReg, getPointerTy()), Result); @@ -4406,17 +4419,24 @@ X86TargetLowering::LowerGlobalAddress(const GlobalValue *GV, // the GlobalAddress must be in the base or index register of the address, not // the GV offset field. Platform check is inside GVRequiresExtraLoad() call // The same applies for external symbols during PIC codegen - if (Subtarget->GVRequiresExtraLoad(GV, getTargetMachine(), false)) + if (ExtraLoadRequired) Result = DAG.getLoad(getPointerTy(), DAG.getEntryNode(), Result, PseudoSourceValue::getGOT(), 0); + // If there was a non-zero offset that we didn't fold, create an explicit + // addition for it. + if (Offset != 0) + Result = DAG.getNode(ISD::ADD, getPointerTy(), Result, + DAG.getConstant(Offset, getPointerTy())); + return Result; } SDValue X86TargetLowering::LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) { const GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal(); - return LowerGlobalAddress(GV, DAG); + int64_t Offset = cast<GlobalAddressSDNode>(Op)->getOffset(); + return LowerGlobalAddress(GV, Offset, DAG); } // Lower ISD::GlobalTLSAddress using the "general dynamic" model, 32 bit @@ -7006,6 +7026,7 @@ bool X86TargetLowering::isGAPlusOffset(SDNode *N, if (N->getOpcode() == X86ISD::Wrapper) { if (isa<GlobalAddressSDNode>(N->getOperand(0))) { GA = cast<GlobalAddressSDNode>(N->getOperand(0))->getGlobal(); + Offset = cast<GlobalAddressSDNode>(N->getOperand(0))->getOffset(); return true; } } @@ -7448,7 +7469,7 @@ void X86TargetLowering::LowerAsmOperandForConstraint(SDValue Op, if (GA) { if (hasMemory) - Op = LowerGlobalAddress(GA->getGlobal(), DAG); + Op = LowerGlobalAddress(GA->getGlobal(), Offset, DAG); else Op = DAG.getTargetGlobalAddress(GA->getGlobal(), GA->getValueType(0), Offset); diff --git a/lib/Target/X86/X86ISelLowering.h b/lib/Target/X86/X86ISelLowering.h index b3d165432f..b76ba845e5 100644 --- a/lib/Target/X86/X86ISelLowering.h +++ b/lib/Target/X86/X86ISelLowering.h @@ -551,7 +551,8 @@ namespace llvm { SDValue LowerINSERT_VECTOR_ELT_SSE4(SDValue Op, SelectionDAG &DAG); SDValue LowerSCALAR_TO_VECTOR(SDValue Op, SelectionDAG &DAG); SDValue LowerConstantPool(SDValue Op, SelectionDAG &DAG); - SDValue LowerGlobalAddress(const GlobalValue *GV, SelectionDAG &DAG) const; + SDValue LowerGlobalAddress(const GlobalValue *GV, int64_t Offset, + SelectionDAG &DAG) const; SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG); SDValue LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG); SDValue LowerExternalSymbol(SDValue Op, SelectionDAG &DAG); diff --git a/lib/Target/X86/X86TargetMachine.cpp b/lib/Target/X86/X86TargetMachine.cpp index 923823b98c..ef4f897f5d 100644 --- a/lib/Target/X86/X86TargetMachine.cpp +++ b/lib/Target/X86/X86TargetMachine.cpp @@ -143,6 +143,15 @@ X86TargetMachine::X86TargetMachine(const Module &M, const std::string &FS, else setRelocationModel(Reloc::Static); } + + // ELF doesn't have a distinct dynamic-no-PIC model. Dynamic-no-PIC + // is defined as a model for code which may be used in static or + // dynamic executables but not necessarily a shared library. On ELF + // implement this by using the Static model. + if (Subtarget.isTargetELF() && + getRelocationModel() == Reloc::DynamicNoPIC) + setRelocationModel(Reloc::Static); + if (Subtarget.is64Bit()) { // No DynamicNoPIC support under X86-64. if (getRelocationModel() == Reloc::DynamicNoPIC) diff --git a/test/CodeGen/X86/ga-offset.ll b/test/CodeGen/X86/ga-offset.ll new file mode 100644 index 0000000000..cc93b4c2ee --- /dev/null +++ b/test/CodeGen/X86/ga-offset.ll @@ -0,0 +1,18 @@ +; RUN: llvm-as < %s | llc -march=x86 > %t +; RUN: not grep lea %t +; RUN: not grep add %t +; RUN: grep mov %t | count 1 +; RUN: llvm-as < %s | llc -march=x86-64 -relocation-model=static > %t +; RUN: not grep lea %t +; RUN: not grep add %t +; RUN: grep mov %t | count 1 + +; This store should fold to a single mov instruction. + +@ptr = global i32* null +@dst = global [131072 x i32] zeroinitializer + +define void @foo() nounwind { + store i32* getelementptr ([131072 x i32]* @dst, i32 0, i32 16), i32** @ptr + ret void +} |