forked from OSchip/llvm-project
This patch implements the thread local storage. Implemented are General
Dynamic, Initial Exec and Local Exec TLS models. Patch by Sasa Stankovic llvm-svn: 132322
This commit is contained in:
parent
4503e20ae6
commit
bf3c1251e0
|
@ -318,6 +318,10 @@ void MipsAsmPrinter::printOperand(const MachineInstr *MI, int opNum,
|
|||
case MipsII::MO_GOT: O << "%got("; break;
|
||||
case MipsII::MO_ABS_HI: O << "%hi("; break;
|
||||
case MipsII::MO_ABS_LO: O << "%lo("; break;
|
||||
case MipsII::MO_TLSGD: O << "%tlsgd("; break;
|
||||
case MipsII::MO_GOTTPREL: O << "%gottprel("; break;
|
||||
case MipsII::MO_TPREL_HI: O << "%tprel_hi("; break;
|
||||
case MipsII::MO_TPREL_LO: O << "%tprel_lo("; break;
|
||||
}
|
||||
|
||||
switch (MO.getType()) {
|
||||
|
|
|
@ -128,6 +128,11 @@ SelectAddr(SDValue Addr, SDValue &Offset, SDValue &Base) {
|
|||
if ((Addr.getOpcode() == ISD::TargetExternalSymbol ||
|
||||
Addr.getOpcode() == ISD::TargetGlobalAddress))
|
||||
return false;
|
||||
else if (Addr.getOpcode() == ISD::TargetGlobalTLSAddress) {
|
||||
Base = CurDAG->getRegister(Mips::GP, MVT::i32);
|
||||
Offset = Addr;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Operand is a result from an ADD.
|
||||
|
@ -441,6 +446,18 @@ SDNode* MipsDAGToDAGISel::Select(SDNode *Node) {
|
|||
return ResNode;
|
||||
// Other cases are autogenerated.
|
||||
break;
|
||||
|
||||
case MipsISD::ThreadPointer: {
|
||||
unsigned SrcReg = Mips::HWR29;
|
||||
unsigned DestReg = Mips::V1;
|
||||
SDNode *Rdhwr = CurDAG->getMachineNode(Mips::RDHWR, Node->getDebugLoc(),
|
||||
Node->getValueType(0), CurDAG->getRegister(SrcReg, MVT::i32));
|
||||
SDValue Chain = CurDAG->getCopyToReg(CurDAG->getEntryNode(), dl, DestReg,
|
||||
SDValue(Rdhwr, 0));
|
||||
SDValue ResNode = CurDAG->getCopyFromReg(Chain, dl, DestReg, MVT::i32);
|
||||
ReplaceUses(SDValue(Node, 0), ResNode);
|
||||
return ResNode.getNode();
|
||||
}
|
||||
}
|
||||
|
||||
// Select the default instruction
|
||||
|
|
|
@ -41,6 +41,10 @@ const char *MipsTargetLowering::getTargetNodeName(unsigned Opcode) const {
|
|||
case MipsISD::Hi: return "MipsISD::Hi";
|
||||
case MipsISD::Lo: return "MipsISD::Lo";
|
||||
case MipsISD::GPRel: return "MipsISD::GPRel";
|
||||
case MipsISD::TlsGd: return "MipsISD::TlsGd";
|
||||
case MipsISD::TprelHi: return "MipsISD::TprelHi";
|
||||
case MipsISD::TprelLo: return "MipsISD::TprelLo";
|
||||
case MipsISD::ThreadPointer: return "MipsISD::ThreadPointer";
|
||||
case MipsISD::Ret: return "MipsISD::Ret";
|
||||
case MipsISD::FPBrcond: return "MipsISD::FPBrcond";
|
||||
case MipsISD::FPCmp: return "MipsISD::FPCmp";
|
||||
|
@ -822,8 +826,60 @@ SDValue MipsTargetLowering::LowerBlockAddress(SDValue Op,
|
|||
SDValue MipsTargetLowering::
|
||||
LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const
|
||||
{
|
||||
llvm_unreachable("TLS not implemented for MIPS.");
|
||||
return SDValue(); // Not reached
|
||||
// If the relocation model is PIC, use the General Dynamic TLS Model,
|
||||
// otherwise use the Initial Exec or Local Exec TLS Model.
|
||||
// TODO: implement Local Dynamic TLS model
|
||||
|
||||
GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Op);
|
||||
DebugLoc dl = GA->getDebugLoc();
|
||||
const GlobalValue *GV = GA->getGlobal();
|
||||
EVT PtrVT = getPointerTy();
|
||||
|
||||
if (getTargetMachine().getRelocationModel() == Reloc::PIC_) {
|
||||
// General Dynamic TLS Model
|
||||
SDValue TGA = DAG.getTargetGlobalAddress(GV, dl, MVT::i32,
|
||||
0, MipsII::MO_TLSGD);
|
||||
SDValue Tlsgd = DAG.getNode(MipsISD::TlsGd, dl, MVT::i32, TGA);
|
||||
SDValue GP = DAG.getRegister(Mips::GP, MVT::i32);
|
||||
SDValue Argument = DAG.getNode(ISD::ADD, dl, MVT::i32, GP, Tlsgd);
|
||||
|
||||
ArgListTy Args;
|
||||
ArgListEntry Entry;
|
||||
Entry.Node = Argument;
|
||||
Entry.Ty = (const Type *) Type::getInt32Ty(*DAG.getContext());
|
||||
Args.push_back(Entry);
|
||||
std::pair<SDValue, SDValue> CallResult =
|
||||
LowerCallTo(DAG.getEntryNode(),
|
||||
(const Type *) Type::getInt32Ty(*DAG.getContext()),
|
||||
false, false, false, false,
|
||||
0, CallingConv::C, false, true,
|
||||
DAG.getExternalSymbol("__tls_get_addr", PtrVT), Args, DAG, dl);
|
||||
|
||||
return CallResult.first;
|
||||
} else {
|
||||
SDValue Offset;
|
||||
if (GV->isDeclaration()) {
|
||||
// Initial Exec TLS Model
|
||||
SDValue TGA = DAG.getTargetGlobalAddress(GV, dl, MVT::i32, 0,
|
||||
MipsII::MO_GOTTPREL);
|
||||
Offset = DAG.getLoad(MVT::i32, dl,
|
||||
DAG.getEntryNode(), TGA, MachinePointerInfo(),
|
||||
false, false, 0);
|
||||
} else {
|
||||
// Local Exec TLS Model
|
||||
SDVTList VTs = DAG.getVTList(MVT::i32);
|
||||
SDValue TGAHi = DAG.getTargetGlobalAddress(GV, dl, MVT::i32, 0,
|
||||
MipsII::MO_TPREL_HI);
|
||||
SDValue TGALo = DAG.getTargetGlobalAddress(GV, dl, MVT::i32, 0,
|
||||
MipsII::MO_TPREL_LO);
|
||||
SDValue Hi = DAG.getNode(MipsISD::TprelHi, dl, VTs, &TGAHi, 1);
|
||||
SDValue Lo = DAG.getNode(MipsISD::TprelLo, dl, MVT::i32, TGALo);
|
||||
Offset = DAG.getNode(ISD::ADD, dl, MVT::i32, Hi, Lo);
|
||||
}
|
||||
|
||||
SDValue ThreadPointer = DAG.getNode(MipsISD::ThreadPointer, dl, PtrVT);
|
||||
return DAG.getNode(ISD::ADD, dl, PtrVT, ThreadPointer, Offset);
|
||||
}
|
||||
}
|
||||
|
||||
SDValue MipsTargetLowering::
|
||||
|
|
|
@ -40,6 +40,16 @@ namespace llvm {
|
|||
// Handle gp_rel (small data/bss sections) relocation.
|
||||
GPRel,
|
||||
|
||||
// General Dynamic TLS
|
||||
TlsGd,
|
||||
|
||||
// Local Exec TLS
|
||||
TprelHi,
|
||||
TprelLo,
|
||||
|
||||
// Thread Pointer
|
||||
ThreadPointer,
|
||||
|
||||
// Floating Point Branch Conditional
|
||||
FPBrcond,
|
||||
|
||||
|
|
|
@ -146,7 +146,21 @@ namespace MipsII {
|
|||
/// MO_ABS_HI/LO - Represents the hi or low part of an absolute symbol
|
||||
/// address.
|
||||
MO_ABS_HI,
|
||||
MO_ABS_LO
|
||||
MO_ABS_LO,
|
||||
|
||||
/// MO_TLSGD - Represents the offset into the global offset table at which
|
||||
// the module ID and TSL block offset reside during execution (General
|
||||
// Dynamic TLS).
|
||||
MO_TLSGD,
|
||||
|
||||
/// MO_GOTTPREL - Represents the offset from the thread pointer (Initial
|
||||
// Exec TLS).
|
||||
MO_GOTTPREL,
|
||||
|
||||
/// MO_TPREL_HI/LO - Represents the hi and low part of the offset from
|
||||
// the thread pointer (Local Exec TLS).
|
||||
MO_TPREL_HI,
|
||||
MO_TPREL_LO
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,8 @@ def SDT_MipsDivRem : SDTypeProfile<0, 2,
|
|||
[SDTCisVT<0, i32>,
|
||||
SDTCisSameAs<0, 1>]>;
|
||||
|
||||
def SDT_MipsThreadPointer : SDTypeProfile<1, 0, [SDTCisPtrTy<0>]>;
|
||||
|
||||
// Call
|
||||
def MipsJmpLink : SDNode<"MipsISD::JmpLink",SDT_MipsJmpLink,
|
||||
[SDNPHasChain, SDNPOutGlue, SDNPOptInGlue,
|
||||
|
@ -49,6 +51,16 @@ def MipsHi : SDNode<"MipsISD::Hi", SDTIntUnaryOp>;
|
|||
def MipsLo : SDNode<"MipsISD::Lo", SDTIntUnaryOp>;
|
||||
def MipsGPRel : SDNode<"MipsISD::GPRel", SDTIntUnaryOp>;
|
||||
|
||||
// TlsGd node is used to handle General Dynamic TLS
|
||||
def MipsTlsGd : SDNode<"MipsISD::TlsGd", SDTIntUnaryOp>;
|
||||
|
||||
// TprelHi and TprelLo nodes are used to handle Local Exec TLS
|
||||
def MipsTprelHi : SDNode<"MipsISD::TprelHi", SDTIntUnaryOp>;
|
||||
def MipsTprelLo : SDNode<"MipsISD::TprelLo", SDTIntUnaryOp>;
|
||||
|
||||
// Thread pointer
|
||||
def MipsThreadPointer: SDNode<"MipsISD::ThreadPointer", SDT_MipsThreadPointer>;
|
||||
|
||||
// Return
|
||||
def MipsRet : SDNode<"MipsISD::Ret", SDT_MipsRet, [SDNPHasChain,
|
||||
SDNPOptInGlue]>;
|
||||
|
@ -353,6 +365,13 @@ class CondMov<bits<6> func, string instr_asm, PatLeaf MovCode>:
|
|||
CPURegs:$cond), !strconcat(instr_asm, "\t$dst, $T, $cond"),
|
||||
[], NoItinerary>;
|
||||
|
||||
// Read Hardware
|
||||
class ReadHardware: FR<0x1f, 0x3b, (outs CPURegs:$dst), (ins HWRegs:$src),
|
||||
"rdhwr\t$dst, $src", [], IIAlu> {
|
||||
let rs = 0;
|
||||
let shamt = 0;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Pseudo instructions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -540,6 +559,8 @@ def MSUBU : MArithR<5, "msubu", MipsMSubu>;
|
|||
// it is a real instruction.
|
||||
def MUL : ArithR<0x1c, 0x02, "mul", mul, IIImul, 1>, Requires<[IsMips32]>;
|
||||
|
||||
def RDHWR : ReadHardware;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Arbitrary patterns that map to one or more instructions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -592,6 +613,15 @@ def : Pat<(add CPURegs:$gp, (MipsGPRel tglobaladdr:$in)),
|
|||
def : Pat<(add CPURegs:$gp, (MipsGPRel tconstpool:$in)),
|
||||
(ADDiu CPURegs:$gp, tconstpool:$in)>;
|
||||
|
||||
// tlsgd
|
||||
def : Pat<(add CPURegs:$gp, (MipsTlsGd tglobaltlsaddr:$in)),
|
||||
(ADDiu CPURegs:$gp, tglobaltlsaddr:$in)>;
|
||||
|
||||
// tprel hi/lo
|
||||
def : Pat<(MipsTprelHi tglobaltlsaddr:$in), (LUi tglobaltlsaddr:$in)>;
|
||||
def : Pat<(add CPURegs:$hi, (MipsTprelLo tglobaltlsaddr:$lo)),
|
||||
(ADDiu CPURegs:$hi, tglobaltlsaddr:$lo)>;
|
||||
|
||||
// wrapper_pic
|
||||
class WrapperPICPat<SDNode node>:
|
||||
Pat<(MipsWrapperPIC node:$in),
|
||||
|
|
|
@ -44,6 +44,11 @@ class AFPR<bits<5> num, string n, list<Register> subregs>
|
|||
let SubRegIndices = [sub_fpeven, sub_fpodd];
|
||||
}
|
||||
|
||||
// Mips Hardware Registers
|
||||
class HWR<bits<5> num, string n> : MipsReg<n> {
|
||||
let Num = num;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Registers
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -143,6 +148,9 @@ let Namespace = "Mips" in {
|
|||
|
||||
// Status flags register
|
||||
def FCR31 : Register<"31">;
|
||||
|
||||
// Hardware register $29
|
||||
def HWR29 : Register<"29">;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -262,3 +270,5 @@ def CCR : RegisterClass<"Mips", [i32], 32, [FCR31]>;
|
|||
// Hi/Lo Registers
|
||||
def HILO : RegisterClass<"Mips", [i32], 32, [HI, LO]>;
|
||||
|
||||
// Hardware registers
|
||||
def HWRegs : RegisterClass<"Mips", [i32], 32, [HWR29]>;
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
; RUN: llc -march=mipsel -mcpu=mips2 < %s | FileCheck %s -check-prefix=PIC
|
||||
; RUN: llc -march=mipsel -mcpu=mips2 -relocation-model=static < %s \
|
||||
; RUN: | FileCheck %s -check-prefix=STATIC
|
||||
|
||||
|
||||
@t1 = thread_local global i32 0, align 4
|
||||
|
||||
define i32 @f1() nounwind {
|
||||
entry:
|
||||
%tmp = load i32* @t1, align 4
|
||||
ret i32 %tmp
|
||||
|
||||
; CHECK: f1:
|
||||
|
||||
; PIC: lw $25, %call16(__tls_get_addr)($gp)
|
||||
; PIC: addiu $4, $gp, %tlsgd(t1)
|
||||
; PIC: jalr $25
|
||||
; PIC: lw $2, 0($2)
|
||||
|
||||
; STATIC: rdhwr $3, $29
|
||||
; STATIC: lui $[[R0:[0-9]+]], %tprel_hi(t1)
|
||||
; STATIC: addiu $[[R1:[0-9]+]], $[[R0]], %tprel_lo(t1)
|
||||
; STATIC: addu $[[R2:[0-9]+]], $3, $[[R1]]
|
||||
; STATIC: lw $2, 0($[[R2]])
|
||||
}
|
||||
|
||||
|
||||
@t2 = external thread_local global i32
|
||||
|
||||
define i32 @f2() nounwind {
|
||||
entry:
|
||||
%tmp = load i32* @t2, align 4
|
||||
ret i32 %tmp
|
||||
|
||||
; CHECK: f2:
|
||||
|
||||
; PIC: lw $25, %call16(__tls_get_addr)($gp)
|
||||
; PIC: addiu $4, $gp, %tlsgd(t2)
|
||||
; PIC: jalr $25
|
||||
; PIC: lw $2, 0($2)
|
||||
|
||||
; STATIC: rdhwr $3, $29
|
||||
; STATIC: lw $[[R0:[0-9]+]], %gottprel(t2)($gp)
|
||||
; STATIC: addu $[[R1:[0-9]+]], $3, $[[R0]]
|
||||
; STATIC: lw $2, 0($[[R1]])
|
||||
}
|
Loading…
Reference in New Issue