Implement 'large' PIC model

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@76006 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Anton Korobeynikov 2009-07-16 14:16:05 +00:00
parent 48e8b3cc58
commit 6fe326c713
10 changed files with 190 additions and 9 deletions

View 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,

View 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();
// 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;
}

View 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;

View 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)]>;

View File

@ -244,6 +244,10 @@ def s32imm64 : Operand<i64> {
let PrintMethod = "printS32ImmOperand";
}
def imm_pcrel : Operand<i64> {
let PrintMethod = "printPCRelImmOperand";
}
//===----------------------------------------------------------------------===//
// SystemZ Operand Definitions.
//===----------------------------------------------------------------------===//

View 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;
}

View 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

View 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,

View File

@ -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
}

View File

@ -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
}