mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-11-02 07:11:49 +00:00
ARM TLS: implement "general dynamic", "initial exec" and "local exec" models.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@36506 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
b1df8f2750
commit
64f4fa5e0e
@ -134,10 +134,14 @@ namespace {
|
||||
} else
|
||||
O << Name;
|
||||
if (ACPV->hasModifier()) O << "(" << ACPV->getModifier() << ")";
|
||||
if (ACPV->getPCAdjustment() != 0)
|
||||
if (ACPV->getPCAdjustment() != 0) {
|
||||
O << "-(" << TAI->getPrivateGlobalPrefix() << "PC"
|
||||
<< utostr(ACPV->getLabelId())
|
||||
<< "+" << (unsigned)ACPV->getPCAdjustment() << ")";
|
||||
<< "+" << (unsigned)ACPV->getPCAdjustment();
|
||||
if (ACPV->mustAddCurrentAddress())
|
||||
O << "-.";
|
||||
O << ")";
|
||||
}
|
||||
O << "\n";
|
||||
|
||||
// If the constant pool value is a extern weak symbol, remember to emit
|
||||
@ -869,9 +873,13 @@ bool ARMAsmPrinter::doFinalization(Module &M) {
|
||||
SwitchToDataSection(SectionName.c_str());
|
||||
} else {
|
||||
if (C->isNullValue() && !NoZerosInBSS && TAI->getBSSSection())
|
||||
SwitchToDataSection(TAI->getBSSSection(), I);
|
||||
SwitchToDataSection(I->isThreadLocal() ? TAI->getTLSBSSSection() :
|
||||
TAI->getBSSSection(), I);
|
||||
else if (!I->isConstant())
|
||||
SwitchToDataSection(TAI->getDataSection(), I);
|
||||
SwitchToDataSection(I->isThreadLocal() ? TAI->getTLSDataSection() :
|
||||
TAI->getDataSection(), I);
|
||||
else if (I->isThreadLocal())
|
||||
SwitchToDataSection(TAI->getTLSDataSection());
|
||||
else {
|
||||
// Read-only data.
|
||||
bool HasReloc = C->ContainsRelocations();
|
||||
|
@ -20,18 +20,20 @@ using namespace llvm;
|
||||
ARMConstantPoolValue::ARMConstantPoolValue(GlobalValue *gv, unsigned id,
|
||||
ARMCP::ARMCPKind k,
|
||||
unsigned char PCAdj,
|
||||
const char *Modif)
|
||||
const char *Modif,
|
||||
bool AddCA)
|
||||
: MachineConstantPoolValue((const Type*)gv->getType()),
|
||||
GV(gv), S(NULL), LabelId(id), Kind(k), PCAdjust(PCAdj),
|
||||
Modifier(Modif) {}
|
||||
Modifier(Modif), AddCurrentAddress(AddCA) {}
|
||||
|
||||
ARMConstantPoolValue::ARMConstantPoolValue(const char *s, unsigned id,
|
||||
ARMCP::ARMCPKind k,
|
||||
unsigned char PCAdj,
|
||||
const char *Modif)
|
||||
const char *Modif,
|
||||
bool AddCA)
|
||||
: MachineConstantPoolValue((const Type*)Type::Int32Ty),
|
||||
GV(NULL), S(s), LabelId(id), Kind(k), PCAdjust(PCAdj),
|
||||
Modifier(Modif) {}
|
||||
Modifier(Modif), AddCurrentAddress(AddCA) {}
|
||||
|
||||
ARMConstantPoolValue::ARMConstantPoolValue(GlobalValue *gv,
|
||||
ARMCP::ARMCPKind k,
|
||||
@ -78,6 +80,11 @@ void ARMConstantPoolValue::print(std::ostream &O) const {
|
||||
if (isNonLazyPointer()) O << "$non_lazy_ptr";
|
||||
else if (isStub()) O << "$stub";
|
||||
if (Modifier) O << "(" << Modifier << ")";
|
||||
if (PCAdjust != 0) O << "-(LPIC" << LabelId << "+"
|
||||
<< (unsigned)PCAdjust << ")";
|
||||
if (PCAdjust != 0) {
|
||||
O << "-(LPIC" << LabelId << "+"
|
||||
<< (unsigned)PCAdjust;
|
||||
if (AddCurrentAddress)
|
||||
O << "-.";
|
||||
O << ")";
|
||||
}
|
||||
}
|
||||
|
@ -37,14 +37,17 @@ class ARMConstantPoolValue : public MachineConstantPoolValue {
|
||||
unsigned char PCAdjust; // Extra adjustment if constantpool is pc relative.
|
||||
// 8 for ARM, 4 for Thumb.
|
||||
const char *Modifier; // GV modifier i.e. (&GV(modifier)-(LPIC+8))
|
||||
bool AddCurrentAddress;
|
||||
|
||||
public:
|
||||
ARMConstantPoolValue(GlobalValue *gv, unsigned id,
|
||||
ARMCP::ARMCPKind Kind = ARMCP::CPValue,
|
||||
unsigned char PCAdj = 0, const char *Modifier = NULL);
|
||||
unsigned char PCAdj = 0, const char *Modifier = NULL,
|
||||
bool AddCurrentAddress = false);
|
||||
ARMConstantPoolValue(const char *s, unsigned id,
|
||||
ARMCP::ARMCPKind Kind = ARMCP::CPValue,
|
||||
unsigned char PCAdj = 0, const char *Modifier = NULL);
|
||||
unsigned char PCAdj = 0, const char *Modifier = NULL,
|
||||
bool AddCurrentAddress = false);
|
||||
ARMConstantPoolValue(GlobalValue *GV, ARMCP::ARMCPKind Kind,
|
||||
const char *Modifier);
|
||||
|
||||
@ -53,6 +56,7 @@ public:
|
||||
const char *getSymbol() const { return S; }
|
||||
const char *getModifier() const { return Modifier; }
|
||||
bool hasModifier() const { return Modifier != NULL; }
|
||||
bool mustAddCurrentAddress() const { return AddCurrentAddress; }
|
||||
unsigned getLabelId() const { return LabelId; }
|
||||
bool isNonLazyPointer() const { return Kind == ARMCP::CPNonLazyPtr; }
|
||||
bool isStub() const { return Kind == ARMCP::CPStub; }
|
||||
|
@ -186,6 +186,7 @@ ARMTargetLowering::ARMTargetLowering(TargetMachine &TM)
|
||||
setOperationAction(ISD::GlobalAddress, MVT::i32, Custom);
|
||||
setOperationAction(ISD::ConstantPool, MVT::i32, Custom);
|
||||
setOperationAction(ISD::GLOBAL_OFFSET_TABLE, MVT::i32, Custom);
|
||||
setOperationAction(ISD::GlobalTLSAddress, MVT::i32, Custom);
|
||||
|
||||
// Expand mem operations genericly.
|
||||
setOperationAction(ISD::MEMSET , MVT::Other, Expand);
|
||||
@ -293,6 +294,8 @@ const char *ARMTargetLowering::getTargetNodeName(unsigned Opcode) const {
|
||||
|
||||
case ARMISD::FMRRD: return "ARMISD::FMRRD";
|
||||
case ARMISD::FMDRR: return "ARMISD::FMDRR";
|
||||
|
||||
case ARMISD::THREAD_POINTER:return "ARMISD::THREAD_POINTER";
|
||||
}
|
||||
}
|
||||
|
||||
@ -701,6 +704,91 @@ static SDOperand LowerConstantPool(SDOperand Op, SelectionDAG &DAG) {
|
||||
return DAG.getNode(ARMISD::Wrapper, MVT::i32, Res);
|
||||
}
|
||||
|
||||
// Lower ISD::GlobalTLSAddress using the "general dynamic" model
|
||||
SDOperand
|
||||
ARMTargetLowering::LowerToTLSGeneralDynamicModel(GlobalAddressSDNode *GA,
|
||||
SelectionDAG &DAG) {
|
||||
MVT::ValueType PtrVT = getPointerTy();
|
||||
unsigned char PCAdj = Subtarget->isThumb() ? 4 : 8;
|
||||
ARMConstantPoolValue *CPV =
|
||||
new ARMConstantPoolValue(GA->getGlobal(), ARMPCLabelIndex, ARMCP::CPValue,
|
||||
PCAdj, "tlsgd", true);
|
||||
SDOperand Argument = DAG.getTargetConstantPool(CPV, PtrVT, 2);
|
||||
Argument = DAG.getNode(ARMISD::Wrapper, MVT::i32, Argument);
|
||||
Argument = DAG.getLoad(PtrVT, DAG.getEntryNode(), Argument, NULL, 0);
|
||||
SDOperand Chain = Argument.getValue(1);
|
||||
|
||||
SDOperand PICLabel = DAG.getConstant(ARMPCLabelIndex++, MVT::i32);
|
||||
Argument = DAG.getNode(ARMISD::PIC_ADD, PtrVT, Argument, PICLabel);
|
||||
|
||||
// call __tls_get_addr.
|
||||
ArgListTy Args;
|
||||
ArgListEntry Entry;
|
||||
Entry.Node = Argument;
|
||||
Entry.Ty = (const Type *) Type::Int32Ty;
|
||||
Args.push_back(Entry);
|
||||
std::pair<SDOperand, SDOperand> CallResult =
|
||||
LowerCallTo(Chain, (const Type *) Type::Int32Ty, false, false,
|
||||
CallingConv::C, false,
|
||||
DAG.getExternalSymbol("__tls_get_addr", PtrVT), Args, DAG);
|
||||
return CallResult.first;
|
||||
}
|
||||
|
||||
// Lower ISD::GlobalTLSAddress using the "initial exec" or
|
||||
// "local exec" model.
|
||||
SDOperand
|
||||
ARMTargetLowering::LowerToTLSExecModels(GlobalAddressSDNode *GA,
|
||||
SelectionDAG &DAG) {
|
||||
GlobalValue *GV = GA->getGlobal();
|
||||
SDOperand Offset;
|
||||
SDOperand Chain = DAG.getEntryNode();
|
||||
MVT::ValueType PtrVT = getPointerTy();
|
||||
// Get the Thread Pointer
|
||||
SDOperand ThreadPointer = DAG.getNode(ARMISD::THREAD_POINTER, PtrVT);
|
||||
|
||||
if (GV->isDeclaration()){
|
||||
// initial exec model
|
||||
unsigned char PCAdj = Subtarget->isThumb() ? 4 : 8;
|
||||
ARMConstantPoolValue *CPV =
|
||||
new ARMConstantPoolValue(GA->getGlobal(), ARMPCLabelIndex, ARMCP::CPValue,
|
||||
PCAdj, "gottpoff", true);
|
||||
Offset = DAG.getTargetConstantPool(CPV, PtrVT, 2);
|
||||
Offset = DAG.getNode(ARMISD::Wrapper, MVT::i32, Offset);
|
||||
Offset = DAG.getLoad(PtrVT, Chain, Offset, NULL, 0);
|
||||
Chain = Offset.getValue(1);
|
||||
|
||||
SDOperand PICLabel = DAG.getConstant(ARMPCLabelIndex++, MVT::i32);
|
||||
Offset = DAG.getNode(ARMISD::PIC_ADD, PtrVT, Offset, PICLabel);
|
||||
|
||||
Offset = DAG.getLoad(PtrVT, Chain, Offset, NULL, 0);
|
||||
} else {
|
||||
// local exec model
|
||||
ARMConstantPoolValue *CPV =
|
||||
new ARMConstantPoolValue(GV, ARMCP::CPValue, "tpoff");
|
||||
Offset = DAG.getTargetConstantPool(CPV, PtrVT, 2);
|
||||
Offset = DAG.getNode(ARMISD::Wrapper, MVT::i32, Offset);
|
||||
Offset = DAG.getLoad(PtrVT, Chain, Offset, NULL, 0);
|
||||
}
|
||||
|
||||
// The address of the thread local variable is the add of the thread
|
||||
// pointer with the offset of the variable.
|
||||
return DAG.getNode(ISD::ADD, PtrVT, ThreadPointer, Offset);
|
||||
}
|
||||
|
||||
SDOperand
|
||||
ARMTargetLowering::LowerGlobalTLSAddress(SDOperand Op, SelectionDAG &DAG) {
|
||||
// TODO: implement the "local dynamic" model
|
||||
assert(Subtarget->isTargetELF() &&
|
||||
"TLS not implemented for non-ELF targets");
|
||||
GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Op);
|
||||
// If the relocation model is PIC, use the "General Dynamic" TLS Model,
|
||||
// otherwise use the "Local Exec" TLS Model
|
||||
if (getTargetMachine().getRelocationModel() == Reloc::PIC_)
|
||||
return LowerToTLSGeneralDynamicModel(GA, DAG);
|
||||
else
|
||||
return LowerToTLSExecModels(GA, DAG);
|
||||
}
|
||||
|
||||
SDOperand ARMTargetLowering::LowerGlobalAddressELF(SDOperand Op,
|
||||
SelectionDAG &DAG) {
|
||||
MVT::ValueType PtrVT = getPointerTy();
|
||||
@ -1249,6 +1337,7 @@ SDOperand ARMTargetLowering::LowerOperation(SDOperand Op, SelectionDAG &DAG) {
|
||||
case ISD::GlobalAddress:
|
||||
return Subtarget->isTargetDarwin() ? LowerGlobalAddressDarwin(Op, DAG) :
|
||||
LowerGlobalAddressELF(Op, DAG);
|
||||
case ISD::GlobalTLSAddress: return LowerGlobalTLSAddress(Op, DAG);
|
||||
case ISD::CALL: return LowerCALL(Op, DAG);
|
||||
case ISD::RET: return LowerRET(Op, DAG);
|
||||
case ISD::SELECT_CC: return LowerSELECT_CC(Op, DAG, Subtarget);
|
||||
|
@ -63,7 +63,9 @@ namespace llvm {
|
||||
RRX, // V = RRX X, Flag -> srl X, 1 + shift in carry flag.
|
||||
|
||||
FMRRD, // double to two gprs.
|
||||
FMDRR // Two gprs to double.
|
||||
FMDRR, // Two gprs to double.
|
||||
|
||||
THREAD_POINTER
|
||||
};
|
||||
}
|
||||
|
||||
@ -125,6 +127,11 @@ namespace llvm {
|
||||
SDOperand LowerCALL(SDOperand Op, SelectionDAG &DAG);
|
||||
SDOperand LowerGlobalAddressDarwin(SDOperand Op, SelectionDAG &DAG);
|
||||
SDOperand LowerGlobalAddressELF(SDOperand Op, SelectionDAG &DAG);
|
||||
SDOperand LowerGlobalTLSAddress(SDOperand Op, SelectionDAG &DAG);
|
||||
SDOperand LowerToTLSGeneralDynamicModel(GlobalAddressSDNode *GA,
|
||||
SelectionDAG &DAG);
|
||||
SDOperand LowerToTLSExecModels(GlobalAddressSDNode *GA,
|
||||
SelectionDAG &DAG);
|
||||
SDOperand LowerGLOBAL_OFFSET_TABLE(SDOperand Op, SelectionDAG &DAG);
|
||||
SDOperand LowerFORMAL_ARGUMENTS(SDOperand Op, SelectionDAG &DAG);
|
||||
SDOperand LowerBR_JT(SDOperand Op, SelectionDAG &DAG);
|
||||
|
@ -39,6 +39,8 @@ def SDT_ARMCmp : SDTypeProfile<0, 2, [SDTCisSameAs<0, 1>]>;
|
||||
def SDT_ARMPICAdd : SDTypeProfile<1, 2, [SDTCisSameAs<0, 1>,
|
||||
SDTCisPtrTy<1>, SDTCisVT<2, i32>]>;
|
||||
|
||||
def SDT_ARMThreadPointer : SDTypeProfile<1, 0, [SDTCisPtrTy<0>]>;
|
||||
|
||||
// Node definitions.
|
||||
def ARMWrapper : SDNode<"ARMISD::Wrapper", SDTIntUnaryOp>;
|
||||
def ARMWrapperJT : SDNode<"ARMISD::WrapperJT", SDTIntBinOp>;
|
||||
@ -79,6 +81,8 @@ def ARMsrl_flag : SDNode<"ARMISD::SRL_FLAG", SDTIntUnaryOp, [SDNPOutFlag]>;
|
||||
def ARMsra_flag : SDNode<"ARMISD::SRA_FLAG", SDTIntUnaryOp, [SDNPOutFlag]>;
|
||||
def ARMrrx : SDNode<"ARMISD::RRX" , SDTIntUnaryOp, [SDNPInFlag ]>;
|
||||
|
||||
def ARMthread_pointer: SDNode<"ARMISD::THREAD_POINTER", SDT_ARMThreadPointer>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ARM Instruction Predicate Definitions.
|
||||
//
|
||||
@ -1068,6 +1072,17 @@ def LEApcrelJT : AI1<(ops GPR:$dst, i32imm:$label, i32imm:$id),
|
||||
!strconcat("${:private}PCRELL${:uid}:\n\t",
|
||||
"add $dst, pc, #PCRELV${:uid}")),
|
||||
[]>;
|
||||
//===----------------------------------------------------------------------===//
|
||||
// TLS Instructions
|
||||
//
|
||||
|
||||
// __aeabi_read_tp preserves the registers r1-r3.
|
||||
let isCall = 1,
|
||||
Defs = [R0, R12, LR] in {
|
||||
def TPsoft : AI<(ops),
|
||||
"bl __aeabi_read_tp",
|
||||
[(set R0, ARMthread_pointer)]>;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Non-Instruction Patterns
|
||||
|
@ -523,6 +523,18 @@ def tLEApcrelJT : TIx2<(ops GPR:$dst, i32imm:$label, i32imm:$id),
|
||||
"${:private}PCRELL${:uid}:\n\tadd $dst, pc")),
|
||||
[]>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// TLS Instructions
|
||||
//
|
||||
|
||||
// __aeabi_read_tp preserves the registers r1-r3.
|
||||
let isCall = 1,
|
||||
Defs = [R0, LR] in {
|
||||
def tTPsoft : TIx2<(ops),
|
||||
"bl __aeabi_read_tp",
|
||||
[(set R0, ARMthread_pointer)]>;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Non-Instruction Patterns
|
||||
//
|
||||
|
@ -70,6 +70,8 @@ ARMTargetAsmInfo::ARMTargetAsmInfo(const ARMTargetMachine &TM) {
|
||||
StaticCtorsSection = "\t.section .ctors,\"aw\",%progbits";
|
||||
StaticDtorsSection = "\t.section .dtors,\"aw\",%progbits";
|
||||
}
|
||||
TLSDataSection = "\t.section .tdata,\"awT\",%progbits";
|
||||
TLSBSSSection = "\t.section .tbss,\"awT\",%nobits";
|
||||
}
|
||||
|
||||
ZeroDirective = "\t.space\t";
|
||||
|
Loading…
Reference in New Issue
Block a user