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:
Bruno Cardoso Lopes 2011-05-31 02:53:58 +00:00
parent 4503e20ae6
commit bf3c1251e0
8 changed files with 190 additions and 3 deletions

View File

@ -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()) {

View File

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

View File

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

View File

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

View File

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

View File

@ -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),

View File

@ -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]>;

View File

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