mirror of
https://github.com/RPCSX/llvm.git
synced 2024-11-29 06:30:39 +00:00
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:
parent
48e8b3cc58
commit
6fe326c713
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)]>;
|
||||
|
@ -244,6 +244,10 @@ def s32imm64 : Operand<i64> {
|
||||
let PrintMethod = "printS32ImmOperand";
|
||||
}
|
||||
|
||||
def imm_pcrel : Operand<i64> {
|
||||
let PrintMethod = "printPCRelImmOperand";
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// SystemZ Operand Definitions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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,
|
||||
|
27
test/CodeGen/SystemZ/10-FuncsPic.ll
Normal file
27
test/CodeGen/SystemZ/10-FuncsPic.ll
Normal 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
|
||||
}
|
29
test/CodeGen/SystemZ/10-GlobalsPic.ll
Normal file
29
test/CodeGen/SystemZ/10-GlobalsPic.ll
Normal 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
|
||||
}
|
Loading…
Reference in New Issue
Block a user