Implement 'large' PIC model
authorAnton Korobeynikov <asl@math.spbu.ru>
Thu, 16 Jul 2009 14:16:05 +0000 (14:16 +0000)
committerAnton Korobeynikov <asl@math.spbu.ru>
Thu, 16 Jul 2009 14:16:05 +0000 (14:16 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@76006 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/SystemZ/AsmPrinter/SystemZAsmPrinter.cpp
lib/Target/SystemZ/SystemZISelLowering.cpp
lib/Target/SystemZ/SystemZInstrInfo.h
lib/Target/SystemZ/SystemZInstrInfo.td
lib/Target/SystemZ/SystemZOperands.td
lib/Target/SystemZ/SystemZSubtarget.cpp
lib/Target/SystemZ/SystemZSubtarget.h
lib/Target/SystemZ/SystemZTargetMachine.cpp
test/CodeGen/SystemZ/10-FuncsPic.ll [new file with mode: 0644]
test/CodeGen/SystemZ/10-GlobalsPic.ll [new file with mode: 0644]

index 1a911dbc1d68b4ce68d23ebb70e39ef47bd5ade8..af3ce1780da6bc3052144064ee6e0c11282a2ea6 100644 (file)
@@ -50,6 +50,7 @@ namespace {
 
     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 @@ void SystemZAsmPrinter::printMachineInstruction(const MachineInstr *MI) {
   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 @@ void SystemZAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
     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,
index 6dea471dd9589c53e2a65a8d337154204857e3a7..ae1c8b72e42c03c04de1428538014b69a90b8add 100644 (file)
@@ -545,10 +545,38 @@ SDValue SystemZTargetLowering::LowerGlobalAddress(SDValue Op,
                                                   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();
+
+  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()));
 
-  // FIXME: Verify stuff for constant globals entries
-  return DAG.getNode(SystemZISD::PCRelativeWrapper, dl, getPointerTy(), GA);
+  return Result;
 }
 
 
index 541c38bab795cb03b805e34bf096fc69397fab56..812509a0ce94ce836c5bdb714a02cb7144c93432 100644 (file)
@@ -23,6 +23,30 @@ namespace llvm {
 
 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;
index 1784331e3be3ffe2cafafd513ebb50d8f224565c..b4e25e6c3ada4a40f12c865159cb99972455a171 100644 (file)
@@ -134,7 +134,7 @@ let isCall = 1 in
   // 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)]>;
index 8eccd3a4edf9fbae96461c2adb0aa0b10fd9b1ad..55afbed8bc913b670c797366ba37e932a89f4cb7 100644 (file)
@@ -244,6 +244,10 @@ def s32imm64 : Operand<i64> {
   let PrintMethod = "printS32ImmOperand";
 }
 
+def imm_pcrel : Operand<i64> {
+  let PrintMethod = "printPCRelImmOperand";
+}
+
 //===----------------------------------------------------------------------===//
 // SystemZ Operand Definitions.
 //===----------------------------------------------------------------------===//
index 9c3262e7221024b41fd52e4ec50e44a9154f0767..18a8e1633dae03991ccf3e58bae18fa7c77ef101 100644 (file)
@@ -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 @@ SystemZSubtarget::SystemZSubtarget(const TargetMachine &TM, const Module &M,
   // 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;
+}
index 41a3741a3548bc10550230f8f69ddfcef6c1712e..fd8212c8727900b0f4c4a440a32554e5b041747c 100644 (file)
@@ -21,6 +21,7 @@
 namespace llvm {
 class Module;
 class TargetMachine;
+class GlobalValue;
 
 class SystemZSubtarget : public TargetSubtarget {
   bool HasZ10Insts;
@@ -37,6 +38,9 @@ public:
                                      const std::string &CPU);
 
   bool isZ10() const { return HasZ10Insts; }
+
+  bool GVRequiresExtraLoad(const GlobalValue* GV, const TargetMachine& TM,
+                           bool isDirectCall) const;
 };
 } // End llvm namespace
 
index e8aa6b573b3202e008485b6c93ce60e86028e595..4be8ea9936499f4613975e99d3e69bf9cc766e55 100644 (file)
@@ -42,6 +42,9 @@ SystemZTargetMachine::SystemZTargetMachine(const Module &M, const std::string &F
     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,
diff --git a/test/CodeGen/SystemZ/10-FuncsPic.ll b/test/CodeGen/SystemZ/10-FuncsPic.ll
new file mode 100644 (file)
index 0000000..a3fb4dc
--- /dev/null
@@ -0,0 +1,27 @@
+; RUN: llvm-as < %s | llc -relocation-model=pic | grep GOTENT | count 3
+; RUN: llvm-as < %s | llc -relocation-model=pic | grep PLT | count 1
+
+target 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"
+target triple = "s390x-linux"
+@ptr = external global void (...)*             ; <void (...)**> [#uses=2]
+
+define void @foo1() nounwind {
+entry:
+       store void (...)* @func, void (...)** @ptr
+       ret void
+}
+
+declare void @func(...)
+
+define void @foo2() nounwind {
+entry:
+       tail call void (...)* @func() nounwind
+       ret void
+}
+
+define void @foo3() nounwind {
+entry:
+       %tmp = load void (...)** @ptr           ; <void (...)*> [#uses=1]
+       tail call void (...)* %tmp() nounwind
+       ret void
+}
diff --git a/test/CodeGen/SystemZ/10-GlobalsPic.ll b/test/CodeGen/SystemZ/10-GlobalsPic.ll
new file mode 100644 (file)
index 0000000..434e922
--- /dev/null
@@ -0,0 +1,29 @@
+; RUN: llvm-as < %s | llc -relocation-model=pic | grep GOTENT | count 6
+
+target 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"
+target triple = "s390x-linux"
+@src = external global i32             ; <i32*> [#uses=2]
+@dst = external global i32             ; <i32*> [#uses=2]
+@ptr = external global i32*            ; <i32**> [#uses=2]
+
+define void @foo1() nounwind {
+entry:
+       %tmp = load i32* @src           ; <i32> [#uses=1]
+       store i32 %tmp, i32* @dst
+       ret void
+}
+
+define void @foo2() nounwind {
+entry:
+       store i32* @dst, i32** @ptr
+       ret void
+}
+
+define void @foo3() nounwind {
+entry:
+       %tmp = load i32* @src           ; <i32> [#uses=1]
+       %tmp1 = load i32** @ptr         ; <i32*> [#uses=1]
+       %arrayidx = getelementptr i32* %tmp1, i64 1             ; <i32*> [#uses=1]
+       store i32 %tmp, i32* %arrayidx
+       ret void
+}