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_GOT: O << "%got("; break;
|
||||||
case MipsII::MO_ABS_HI: O << "%hi("; break;
|
case MipsII::MO_ABS_HI: O << "%hi("; break;
|
||||||
case MipsII::MO_ABS_LO: O << "%lo("; 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()) {
|
switch (MO.getType()) {
|
||||||
|
|
|
@ -128,6 +128,11 @@ SelectAddr(SDValue Addr, SDValue &Offset, SDValue &Base) {
|
||||||
if ((Addr.getOpcode() == ISD::TargetExternalSymbol ||
|
if ((Addr.getOpcode() == ISD::TargetExternalSymbol ||
|
||||||
Addr.getOpcode() == ISD::TargetGlobalAddress))
|
Addr.getOpcode() == ISD::TargetGlobalAddress))
|
||||||
return false;
|
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.
|
// Operand is a result from an ADD.
|
||||||
|
@ -441,6 +446,18 @@ SDNode* MipsDAGToDAGISel::Select(SDNode *Node) {
|
||||||
return ResNode;
|
return ResNode;
|
||||||
// Other cases are autogenerated.
|
// Other cases are autogenerated.
|
||||||
break;
|
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
|
// Select the default instruction
|
||||||
|
|
|
@ -41,6 +41,10 @@ const char *MipsTargetLowering::getTargetNodeName(unsigned Opcode) const {
|
||||||
case MipsISD::Hi: return "MipsISD::Hi";
|
case MipsISD::Hi: return "MipsISD::Hi";
|
||||||
case MipsISD::Lo: return "MipsISD::Lo";
|
case MipsISD::Lo: return "MipsISD::Lo";
|
||||||
case MipsISD::GPRel: return "MipsISD::GPRel";
|
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::Ret: return "MipsISD::Ret";
|
||||||
case MipsISD::FPBrcond: return "MipsISD::FPBrcond";
|
case MipsISD::FPBrcond: return "MipsISD::FPBrcond";
|
||||||
case MipsISD::FPCmp: return "MipsISD::FPCmp";
|
case MipsISD::FPCmp: return "MipsISD::FPCmp";
|
||||||
|
@ -822,8 +826,60 @@ SDValue MipsTargetLowering::LowerBlockAddress(SDValue Op,
|
||||||
SDValue MipsTargetLowering::
|
SDValue MipsTargetLowering::
|
||||||
LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const
|
LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const
|
||||||
{
|
{
|
||||||
llvm_unreachable("TLS not implemented for MIPS.");
|
// If the relocation model is PIC, use the General Dynamic TLS Model,
|
||||||
return SDValue(); // Not reached
|
// 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::
|
SDValue MipsTargetLowering::
|
||||||
|
|
|
@ -40,6 +40,16 @@ namespace llvm {
|
||||||
// Handle gp_rel (small data/bss sections) relocation.
|
// Handle gp_rel (small data/bss sections) relocation.
|
||||||
GPRel,
|
GPRel,
|
||||||
|
|
||||||
|
// General Dynamic TLS
|
||||||
|
TlsGd,
|
||||||
|
|
||||||
|
// Local Exec TLS
|
||||||
|
TprelHi,
|
||||||
|
TprelLo,
|
||||||
|
|
||||||
|
// Thread Pointer
|
||||||
|
ThreadPointer,
|
||||||
|
|
||||||
// Floating Point Branch Conditional
|
// Floating Point Branch Conditional
|
||||||
FPBrcond,
|
FPBrcond,
|
||||||
|
|
||||||
|
|
|
@ -146,7 +146,21 @@ namespace MipsII {
|
||||||
/// MO_ABS_HI/LO - Represents the hi or low part of an absolute symbol
|
/// MO_ABS_HI/LO - Represents the hi or low part of an absolute symbol
|
||||||
/// address.
|
/// address.
|
||||||
MO_ABS_HI,
|
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>,
|
[SDTCisVT<0, i32>,
|
||||||
SDTCisSameAs<0, 1>]>;
|
SDTCisSameAs<0, 1>]>;
|
||||||
|
|
||||||
|
def SDT_MipsThreadPointer : SDTypeProfile<1, 0, [SDTCisPtrTy<0>]>;
|
||||||
|
|
||||||
// Call
|
// Call
|
||||||
def MipsJmpLink : SDNode<"MipsISD::JmpLink",SDT_MipsJmpLink,
|
def MipsJmpLink : SDNode<"MipsISD::JmpLink",SDT_MipsJmpLink,
|
||||||
[SDNPHasChain, SDNPOutGlue, SDNPOptInGlue,
|
[SDNPHasChain, SDNPOutGlue, SDNPOptInGlue,
|
||||||
|
@ -49,6 +51,16 @@ def MipsHi : SDNode<"MipsISD::Hi", SDTIntUnaryOp>;
|
||||||
def MipsLo : SDNode<"MipsISD::Lo", SDTIntUnaryOp>;
|
def MipsLo : SDNode<"MipsISD::Lo", SDTIntUnaryOp>;
|
||||||
def MipsGPRel : SDNode<"MipsISD::GPRel", 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
|
// Return
|
||||||
def MipsRet : SDNode<"MipsISD::Ret", SDT_MipsRet, [SDNPHasChain,
|
def MipsRet : SDNode<"MipsISD::Ret", SDT_MipsRet, [SDNPHasChain,
|
||||||
SDNPOptInGlue]>;
|
SDNPOptInGlue]>;
|
||||||
|
@ -353,6 +365,13 @@ class CondMov<bits<6> func, string instr_asm, PatLeaf MovCode>:
|
||||||
CPURegs:$cond), !strconcat(instr_asm, "\t$dst, $T, $cond"),
|
CPURegs:$cond), !strconcat(instr_asm, "\t$dst, $T, $cond"),
|
||||||
[], NoItinerary>;
|
[], 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
|
// Pseudo instructions
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -540,6 +559,8 @@ def MSUBU : MArithR<5, "msubu", MipsMSubu>;
|
||||||
// it is a real instruction.
|
// it is a real instruction.
|
||||||
def MUL : ArithR<0x1c, 0x02, "mul", mul, IIImul, 1>, Requires<[IsMips32]>;
|
def MUL : ArithR<0x1c, 0x02, "mul", mul, IIImul, 1>, Requires<[IsMips32]>;
|
||||||
|
|
||||||
|
def RDHWR : ReadHardware;
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Arbitrary patterns that map to one or more instructions
|
// 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)),
|
def : Pat<(add CPURegs:$gp, (MipsGPRel tconstpool:$in)),
|
||||||
(ADDiu CPURegs:$gp, 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
|
// wrapper_pic
|
||||||
class WrapperPICPat<SDNode node>:
|
class WrapperPICPat<SDNode node>:
|
||||||
Pat<(MipsWrapperPIC node:$in),
|
Pat<(MipsWrapperPIC node:$in),
|
||||||
|
|
|
@ -44,6 +44,11 @@ class AFPR<bits<5> num, string n, list<Register> subregs>
|
||||||
let SubRegIndices = [sub_fpeven, sub_fpodd];
|
let SubRegIndices = [sub_fpeven, sub_fpodd];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mips Hardware Registers
|
||||||
|
class HWR<bits<5> num, string n> : MipsReg<n> {
|
||||||
|
let Num = num;
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// Registers
|
// Registers
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -143,6 +148,9 @@ let Namespace = "Mips" in {
|
||||||
|
|
||||||
// Status flags register
|
// Status flags register
|
||||||
def FCR31 : Register<"31">;
|
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
|
// Hi/Lo Registers
|
||||||
def HILO : RegisterClass<"Mips", [i32], 32, [HI, LO]>;
|
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