Implement 'large' PIC model
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@76006 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Target/SystemZ/AsmPrinter/SystemZAsmPrinter.cpp b/lib/Target/SystemZ/AsmPrinter/SystemZAsmPrinter.cpp
index 1a911db..af3ce17 100644
--- a/lib/Target/SystemZ/AsmPrinter/SystemZAsmPrinter.cpp
+++ b/lib/Target/SystemZ/AsmPrinter/SystemZAsmPrinter.cpp
@@ -50,6 +50,7 @@
void printOperand(const MachineInstr *MI, int OpNum,
const char* Modifier = 0);
+ void printPCRelImmOperand(const MachineInstr *MI, int OpNum);
void printRIAddrOperand(const MachineInstr *MI, int OpNum,
const char* Modifier = 0);
void printRRIAddrOperand(const MachineInstr *MI, int OpNum,
@@ -186,6 +187,40 @@
assert(0 && "Should not happen");
}
+void SystemZAsmPrinter::printPCRelImmOperand(const MachineInstr *MI, int OpNum) {
+ const MachineOperand &MO = MI->getOperand(OpNum);
+ switch (MO.getType()) {
+ case MachineOperand::MO_GlobalAddress: {
+ const GlobalValue *GV = MO.getGlobal();
+ std::string Name = Mang->getValueName(GV);
+
+ O << Name;
+
+ // Assemble calls via PLT for externally visible symbols if PIC.
+ if (TM.getRelocationModel() == Reloc::PIC_ &&
+ !GV->hasHiddenVisibility() && !GV->hasProtectedVisibility() &&
+ !GV->hasLocalLinkage())
+ O << "@PLT";
+
+ printOffset(MO.getOffset());
+ return;
+ }
+ case MachineOperand::MO_ExternalSymbol: {
+ std::string Name(TAI->getGlobalPrefix());
+ Name += MO.getSymbolName();
+ O << Name;
+
+ if (TM.getRelocationModel() == Reloc::PIC_)
+ O << "@PLT";
+
+ return;
+ }
+ default:
+ assert(0 && "Not implemented yet!");
+ }
+}
+
+
void SystemZAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
const char* Modifier) {
const MachineOperand &MO = MI->getOperand(OpNum);
@@ -219,23 +254,31 @@
return;
case MachineOperand::MO_GlobalAddress: {
const GlobalValue *GV = MO.getGlobal();
-
std::string Name = Mang->getValueName(GV);
- assert(MO.getOffset() == 0 && "No offsets allowed!");
O << Name;
-
- return;
+ break;
}
case MachineOperand::MO_ExternalSymbol: {
std::string Name(TAI->getGlobalPrefix());
Name += MO.getSymbolName();
O << Name;
- return;
+ break;
}
default:
assert(0 && "Not implemented yet!");
}
+
+ switch (MO.getTargetFlags()) {
+ default:
+ assert(0 && "Unknown target flag on GV operand");
+ case SystemZII::MO_NO_FLAG:
+ break;
+ case SystemZII::MO_GOTENT: O << "@GOTENT"; break;
+ case SystemZII::MO_PLT: O << "@PLT"; break;
+ }
+
+ printOffset(MO.getOffset());
}
void SystemZAsmPrinter::printRIAddrOperand(const MachineInstr *MI, int OpNum,
diff --git a/lib/Target/SystemZ/SystemZISelLowering.cpp b/lib/Target/SystemZ/SystemZISelLowering.cpp
index 6dea471..ae1c8b7 100644
--- a/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -545,10 +545,38 @@
SelectionDAG &DAG) {
DebugLoc dl = Op.getDebugLoc();
GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
- SDValue GA = DAG.getTargetGlobalAddress(GV, getPointerTy());
+ int64_t Offset = cast<GlobalAddressSDNode>(Op)->getOffset();
- // FIXME: Verify stuff for constant globals entries
- return DAG.getNode(SystemZISD::PCRelativeWrapper, dl, getPointerTy(), GA);
+ bool IsPic = getTargetMachine().getRelocationModel() == Reloc::PIC_;
+ bool ExtraLoadRequired =
+ Subtarget.GVRequiresExtraLoad(GV, getTargetMachine(), false);
+
+ SDValue Result;
+ if (!IsPic && !ExtraLoadRequired) {
+ Result = DAG.getTargetGlobalAddress(GV, getPointerTy(), Offset);
+ Offset = 0;
+ } else {
+ unsigned char OpFlags = 0;
+ if (ExtraLoadRequired)
+ OpFlags = SystemZII::MO_GOTENT;
+
+ Result = DAG.getTargetGlobalAddress(GV, getPointerTy(), 0, OpFlags);
+ }
+
+ Result = DAG.getNode(SystemZISD::PCRelativeWrapper, dl,
+ getPointerTy(), Result);
+
+ if (ExtraLoadRequired)
+ Result = DAG.getLoad(getPointerTy(), dl, 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, dl, getPointerTy(), Result,
+ DAG.getConstant(Offset, getPointerTy()));
+
+ return Result;
}
diff --git a/lib/Target/SystemZ/SystemZInstrInfo.h b/lib/Target/SystemZ/SystemZInstrInfo.h
index 541c38b..812509a 100644
--- a/lib/Target/SystemZ/SystemZInstrInfo.h
+++ b/lib/Target/SystemZ/SystemZInstrInfo.h
@@ -23,6 +23,30 @@
class SystemZTargetMachine;
+/// SystemZII - This namespace holds all of the target specific flags that
+/// instruction info tracks.
+///
+namespace SystemZII {
+ enum {
+ //===------------------------------------------------------------------===//
+ // SystemZ Specific MachineOperand flags.
+
+ MO_NO_FLAG = 0,
+
+ /// MO_GOTENT - On a symbol operand this indicates that the immediate is
+ /// the offset to the location of the symbol name from the base of the GOT.
+ ///
+ /// SYMBOL_LABEL @GOTENT
+ MO_GOTENT = 1,
+
+ /// MO_PLT - On a symbol operand this indicates that the immediate is
+ /// offset to the PLT entry of symbol name from the current code location.
+ ///
+ /// SYMBOL_LABEL @PLT
+ MO_PLT = 2
+ };
+}
+
class SystemZInstrInfo : public TargetInstrInfoImpl {
const SystemZRegisterInfo RI;
SystemZTargetMachine &TM;
diff --git a/lib/Target/SystemZ/SystemZInstrInfo.td b/lib/Target/SystemZ/SystemZInstrInfo.td
index 1784331..b4e25e6 100644
--- a/lib/Target/SystemZ/SystemZInstrInfo.td
+++ b/lib/Target/SystemZ/SystemZInstrInfo.td
@@ -134,7 +134,7 @@
// All calls clobber the non-callee saved registers. Uses for argument
// registers are added manually.
let Defs = [R0D, R1D, R2D, R3D, R4D, R5D, R14D] in {
- def CALLi : Pseudo<(outs), (ins i64imm:$dst, variable_ops),
+ def CALLi : Pseudo<(outs), (ins imm_pcrel:$dst, variable_ops),
"brasl\t%r14, $dst", [(SystemZcall imm:$dst)]>;
def CALLr : Pseudo<(outs), (ins ADDR64:$dst, variable_ops),
"basr\t%r14, $dst", [(SystemZcall ADDR64:$dst)]>;
diff --git a/lib/Target/SystemZ/SystemZOperands.td b/lib/Target/SystemZ/SystemZOperands.td
index 8eccd3a..55afbed 100644
--- a/lib/Target/SystemZ/SystemZOperands.td
+++ b/lib/Target/SystemZ/SystemZOperands.td
@@ -244,6 +244,10 @@
let PrintMethod = "printS32ImmOperand";
}
+def imm_pcrel : Operand<i64> {
+ let PrintMethod = "printPCRelImmOperand";
+}
+
//===----------------------------------------------------------------------===//
// SystemZ Operand Definitions.
//===----------------------------------------------------------------------===//
diff --git a/lib/Target/SystemZ/SystemZSubtarget.cpp b/lib/Target/SystemZ/SystemZSubtarget.cpp
index 9c3262e..18a8e16 100644
--- a/lib/Target/SystemZ/SystemZSubtarget.cpp
+++ b/lib/Target/SystemZ/SystemZSubtarget.cpp
@@ -14,6 +14,7 @@
#include "SystemZSubtarget.h"
#include "SystemZ.h"
#include "SystemZGenSubtarget.inc"
+#include "llvm/GlobalValue.h"
#include "llvm/Target/TargetMachine.h"
using namespace llvm;
@@ -26,3 +27,21 @@
// Parse features string.
ParseSubtargetFeatures(FS, CPU);
}
+
+/// True if accessing the GV requires an extra load.
+bool SystemZSubtarget::GVRequiresExtraLoad(const GlobalValue* GV,
+ const TargetMachine& TM,
+ bool isDirectCall) const {
+ if (TM.getRelocationModel() == Reloc::PIC_) {
+ // Extra load is needed for all externally visible.
+ if (isDirectCall)
+ return false;
+
+ if (GV->hasLocalLinkage() || GV->hasHiddenVisibility())
+ return false;
+
+ return true;
+ }
+
+ return false;
+}
diff --git a/lib/Target/SystemZ/SystemZSubtarget.h b/lib/Target/SystemZ/SystemZSubtarget.h
index 41a3741..fd8212c 100644
--- a/lib/Target/SystemZ/SystemZSubtarget.h
+++ b/lib/Target/SystemZ/SystemZSubtarget.h
@@ -21,6 +21,7 @@
namespace llvm {
class Module;
class TargetMachine;
+class GlobalValue;
class SystemZSubtarget : public TargetSubtarget {
bool HasZ10Insts;
@@ -37,6 +38,9 @@
const std::string &CPU);
bool isZ10() const { return HasZ10Insts; }
+
+ bool GVRequiresExtraLoad(const GlobalValue* GV, const TargetMachine& TM,
+ bool isDirectCall) const;
};
} // End llvm namespace
diff --git a/lib/Target/SystemZ/SystemZTargetMachine.cpp b/lib/Target/SystemZ/SystemZTargetMachine.cpp
index e8aa6b5..4be8ea9 100644
--- a/lib/Target/SystemZ/SystemZTargetMachine.cpp
+++ b/lib/Target/SystemZ/SystemZTargetMachine.cpp
@@ -42,6 +42,9 @@
DataLayout("E-p:64:64:64-i8:8:16-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-f128:128:128-a0:16:16"),
InstrInfo(*this), TLInfo(*this),
FrameInfo(TargetFrameInfo::StackGrowsDown, 8, -160) {
+
+ if (getRelocationModel() == Reloc::Default)
+ setRelocationModel(Reloc::Static);
}
bool SystemZTargetMachine::addInstSelector(PassManagerBase &PM,