From 7bdd7c2346ff53c68a8748893170134826f23012 Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Wed, 18 Feb 2015 09:11:36 +0000 Subject: [PATCH] [SystemZ] Support all TLS access models - MC part The current SystemZ back-end only supports the local-exec TLS access model. This patch adds all required MC support for the other TLS models, which means in particular: - Support additional relocation types for Initial-exec model: R_390_TLS_IEENT Local-dynamic-model: R_390_TLS_LDO32, R_390_TLS_LDO64, R_390_TLS_LDM32, R_390_TLS_LDM64, R_390_TLS_LDCALL General-dynamic model: R_390_TLS_GD32, R_390_TLS_GD64, R_390_TLS_GDCALL - Support assembler syntax to generate additional relocations for use with __tls_get_offset calls: :tls_gdcall: :tls_ldcall: The patch also adds a new test to verify fixups and relocations, and removes the (already unused) FK_390_PLT16DBL/FK_390_PLT32DBL fixup kinds. llvm-svn: 229652 --- .../Target/SystemZ/AsmParser/SystemZAsmParser.cpp | 93 ++++++++++++++-- .../SystemZ/InstPrinter/SystemZInstPrinter.cpp | 24 +++++ .../SystemZ/InstPrinter/SystemZInstPrinter.h | 1 + .../SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp | 8 +- .../SystemZ/MCTargetDesc/SystemZMCCodeEmitter.cpp | 34 +++++- .../Target/SystemZ/MCTargetDesc/SystemZMCFixups.h | 3 +- .../SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp | 48 ++++++++- llvm/lib/Target/SystemZ/SystemZInstrInfo.td | 5 +- llvm/lib/Target/SystemZ/SystemZOperands.td | 30 ++++++ llvm/test/MC/SystemZ/fixups.s | 119 +++++++++++++++++++++ 10 files changed, 344 insertions(+), 21 deletions(-) create mode 100644 llvm/test/MC/SystemZ/fixups.s diff --git a/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp b/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp index cb528db..9181ff7 100644 --- a/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp +++ b/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp @@ -57,6 +57,7 @@ private: KindReg, KindAccessReg, KindImm, + KindImmTLS, KindMem }; @@ -96,11 +97,19 @@ private: const MCExpr *Length; }; + // Imm is an immediate operand, and Sym is an optional TLS symbol + // for use with a __tls_get_offset marker relocation. + struct ImmTLSOp { + const MCExpr *Imm; + const MCExpr *Sym; + }; + union { TokenOp Token; RegOp Reg; unsigned AccessReg; const MCExpr *Imm; + ImmTLSOp ImmTLS; MemOp Mem; }; @@ -160,6 +169,14 @@ public: Op->Mem.Length = Length; return Op; } + static std::unique_ptr + createImmTLS(const MCExpr *Imm, const MCExpr *Sym, + SMLoc StartLoc, SMLoc EndLoc) { + auto Op = make_unique(KindImmTLS, StartLoc, EndLoc); + Op->ImmTLS.Imm = Imm; + Op->ImmTLS.Sym = Sym; + return Op; + } // Token operands bool isToken() const override { @@ -200,6 +217,11 @@ public: return Imm; } + // Immediate operands with optional TLS symbol. + bool isImmTLS() const { + return Kind == KindImmTLS; + } + // Memory operands. bool isMem() const override { return Kind == KindMem; @@ -260,6 +282,13 @@ public: addExpr(Inst, Mem.Disp); addExpr(Inst, Mem.Length); } + void addImmTLSOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands"); + assert(Kind == KindImmTLS && "Invalid operand type"); + addExpr(Inst, ImmTLS.Imm); + if (ImmTLS.Sym) + addExpr(Inst, ImmTLS.Sym); + } // Used by the TableGen code to check for particular operand types. bool isGR32() const { return isReg(GR32Reg); } @@ -325,6 +354,9 @@ private: const unsigned *Regs, RegisterKind RegKind, MemoryKind MemKind); + OperandMatchResultTy parsePCRel(OperandVector &Operands, int64_t MinVal, + int64_t MaxVal, bool AllowTLS); + bool parseOperand(OperandVector &Operands, StringRef Mnemonic); public: @@ -395,13 +427,17 @@ public: return parseAddress(Operands, SystemZMC::GR64Regs, ADDR64Reg, BDLMem); } OperandMatchResultTy parseAccessReg(OperandVector &Operands); - OperandMatchResultTy parsePCRel(OperandVector &Operands, int64_t MinVal, - int64_t MaxVal); OperandMatchResultTy parsePCRel16(OperandVector &Operands) { - return parsePCRel(Operands, -(1LL << 16), (1LL << 16) - 1); + return parsePCRel(Operands, -(1LL << 16), (1LL << 16) - 1, false); } OperandMatchResultTy parsePCRel32(OperandVector &Operands) { - return parsePCRel(Operands, -(1LL << 32), (1LL << 32) - 1); + return parsePCRel(Operands, -(1LL << 32), (1LL << 32) - 1, false); + } + OperandMatchResultTy parsePCRelTLS16(OperandVector &Operands) { + return parsePCRel(Operands, -(1LL << 16), (1LL << 16) - 1, true); + } + OperandMatchResultTy parsePCRelTLS32(OperandVector &Operands) { + return parsePCRel(Operands, -(1LL << 32), (1LL << 32) - 1, true); } }; } // end anonymous namespace @@ -743,7 +779,7 @@ SystemZAsmParser::parseAccessReg(OperandVector &Operands) { SystemZAsmParser::OperandMatchResultTy SystemZAsmParser::parsePCRel(OperandVector &Operands, int64_t MinVal, - int64_t MaxVal) { + int64_t MaxVal, bool AllowTLS) { MCContext &Ctx = getContext(); MCStreamer &Out = getStreamer(); const MCExpr *Expr; @@ -766,9 +802,54 @@ SystemZAsmParser::parsePCRel(OperandVector &Operands, int64_t MinVal, Expr = Value == 0 ? Base : MCBinaryExpr::CreateAdd(Base, Expr, Ctx); } + // Optionally match :tls_gdcall: or :tls_ldcall: followed by a TLS symbol. + const MCExpr *Sym = nullptr; + if (AllowTLS && getLexer().is(AsmToken::Colon)) { + Parser.Lex(); + + if (Parser.getTok().isNot(AsmToken::Identifier)) { + Error(Parser.getTok().getLoc(), "unexpected token"); + return MatchOperand_ParseFail; + } + + MCSymbolRefExpr::VariantKind Kind = MCSymbolRefExpr::VK_None; + StringRef Name = Parser.getTok().getString(); + if (Name == "tls_gdcall") + Kind = MCSymbolRefExpr::VK_TLSGD; + else if (Name == "tls_ldcall") + Kind = MCSymbolRefExpr::VK_TLSLDM; + else { + Error(Parser.getTok().getLoc(), "unknown TLS tag"); + return MatchOperand_ParseFail; + } + Parser.Lex(); + + if (Parser.getTok().isNot(AsmToken::Colon)) { + Error(Parser.getTok().getLoc(), "unexpected token"); + return MatchOperand_ParseFail; + } + Parser.Lex(); + + if (Parser.getTok().isNot(AsmToken::Identifier)) { + Error(Parser.getTok().getLoc(), "unexpected token"); + return MatchOperand_ParseFail; + } + + StringRef Identifier = Parser.getTok().getString(); + Sym = MCSymbolRefExpr::Create(Ctx.GetOrCreateSymbol(Identifier), + Kind, Ctx); + Parser.Lex(); + } + SMLoc EndLoc = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); - Operands.push_back(SystemZOperand::createImm(Expr, StartLoc, EndLoc)); + + if (AllowTLS) + Operands.push_back(SystemZOperand::createImmTLS(Expr, Sym, + StartLoc, EndLoc)); + else + Operands.push_back(SystemZOperand::createImm(Expr, StartLoc, EndLoc)); + return MatchOperand_Success; } diff --git a/llvm/lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.cpp b/llvm/lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.cpp index d2ba9b6..996a492 100644 --- a/llvm/lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.cpp +++ b/llvm/lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.cpp @@ -10,6 +10,7 @@ #include "SystemZInstPrinter.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCSymbol.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -124,6 +125,29 @@ void SystemZInstPrinter::printPCRelOperand(const MCInst *MI, int OpNum, O << *MO.getExpr(); } +void SystemZInstPrinter::printPCRelTLSOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + // Output the PC-relative operand. + printPCRelOperand(MI, OpNum, O); + + // Output the TLS marker if present. + if ((unsigned)OpNum + 1 < MI->getNumOperands()) { + const MCOperand &MO = MI->getOperand(OpNum + 1); + const MCSymbolRefExpr &refExp = cast(*MO.getExpr()); + switch (refExp.getKind()) { + case MCSymbolRefExpr::VK_TLSGD: + O << ":tls_gdcall:"; + break; + case MCSymbolRefExpr::VK_TLSLDM: + O << ":tls_ldcall:"; + break; + default: + llvm_unreachable("Unexpected symbol kind"); + } + O << refExp.getSymbol().getName(); + } +} + void SystemZInstPrinter::printOperand(const MCInst *MI, int OpNum, raw_ostream &O) { printOperand(MI->getOperand(OpNum), O); diff --git a/llvm/lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.h b/llvm/lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.h index 753903c..732e5fa 100644 --- a/llvm/lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.h +++ b/llvm/lib/Target/SystemZ/InstPrinter/SystemZInstPrinter.h @@ -56,6 +56,7 @@ private: void printS32ImmOperand(const MCInst *MI, int OpNum, raw_ostream &O); void printU32ImmOperand(const MCInst *MI, int OpNum, raw_ostream &O); void printPCRelOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printPCRelTLSOperand(const MCInst *MI, int OpNum, raw_ostream &O); void printAccessRegOperand(const MCInst *MI, int OpNum, raw_ostream &O); // Print the mnemonic for a condition-code mask ("ne", "lh", etc.) diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp index 6e7268d..b79b1d8 100644 --- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp +++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp @@ -27,9 +27,10 @@ static uint64_t extractBitsForFixup(MCFixupKind Kind, uint64_t Value) { switch (unsigned(Kind)) { case SystemZ::FK_390_PC16DBL: case SystemZ::FK_390_PC32DBL: - case SystemZ::FK_390_PLT16DBL: - case SystemZ::FK_390_PLT32DBL: return (int64_t)Value / 2; + + case SystemZ::FK_390_TLS_CALL: + return 0; } llvm_unreachable("Unknown fixup kind!"); @@ -72,8 +73,7 @@ SystemZMCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { const static MCFixupKindInfo Infos[SystemZ::NumTargetFixupKinds] = { { "FK_390_PC16DBL", 0, 16, MCFixupKindInfo::FKF_IsPCRel }, { "FK_390_PC32DBL", 0, 32, MCFixupKindInfo::FKF_IsPCRel }, - { "FK_390_PLT16DBL", 0, 16, MCFixupKindInfo::FKF_IsPCRel }, - { "FK_390_PLT32DBL", 0, 32, MCFixupKindInfo::FKF_IsPCRel } + { "FK_390_TLS_CALL", 0, 0, 0 } }; if (Kind < FirstTargetFixupKind) diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCCodeEmitter.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCCodeEmitter.cpp index 27b4bd8..d9bb916 100644 --- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCCodeEmitter.cpp +++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCCodeEmitter.cpp @@ -74,20 +74,36 @@ private: // Operand OpNum of MI needs a PC-relative fixup of kind Kind at // Offset bytes from the start of MI. Add the fixup to Fixups // and return the in-place addend, which since we're a RELA target - // is always 0. + // is always 0. If AllowTLS is true and optional operand OpNum + 1 + // is present, also emit a TLS call fixup for it. uint64_t getPCRelEncoding(const MCInst &MI, unsigned OpNum, SmallVectorImpl &Fixups, - unsigned Kind, int64_t Offset) const; + unsigned Kind, int64_t Offset, + bool AllowTLS) const; uint64_t getPC16DBLEncoding(const MCInst &MI, unsigned OpNum, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const { - return getPCRelEncoding(MI, OpNum, Fixups, SystemZ::FK_390_PC16DBL, 2); + return getPCRelEncoding(MI, OpNum, Fixups, + SystemZ::FK_390_PC16DBL, 2, false); } uint64_t getPC32DBLEncoding(const MCInst &MI, unsigned OpNum, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const { - return getPCRelEncoding(MI, OpNum, Fixups, SystemZ::FK_390_PC32DBL, 2); + return getPCRelEncoding(MI, OpNum, Fixups, + SystemZ::FK_390_PC32DBL, 2, false); + } + uint64_t getPC16DBLTLSEncoding(const MCInst &MI, unsigned OpNum, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + return getPCRelEncoding(MI, OpNum, Fixups, + SystemZ::FK_390_PC16DBL, 2, true); + } + uint64_t getPC32DBLTLSEncoding(const MCInst &MI, unsigned OpNum, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + return getPCRelEncoding(MI, OpNum, Fixups, + SystemZ::FK_390_PC32DBL, 2, true); } }; } // end anonymous namespace @@ -181,7 +197,8 @@ getBDLAddr12Len8Encoding(const MCInst &MI, unsigned OpNum, uint64_t SystemZMCCodeEmitter::getPCRelEncoding(const MCInst &MI, unsigned OpNum, SmallVectorImpl &Fixups, - unsigned Kind, int64_t Offset) const { + unsigned Kind, int64_t Offset, + bool AllowTLS) const { const MCOperand &MO = MI.getOperand(OpNum); const MCExpr *Expr; if (MO.isImm()) @@ -198,6 +215,13 @@ SystemZMCCodeEmitter::getPCRelEncoding(const MCInst &MI, unsigned OpNum, } } Fixups.push_back(MCFixup::Create(Offset, Expr, (MCFixupKind)Kind)); + + // Output the fixup for the TLS marker if present. + if (AllowTLS && OpNum + 1 < MI.getNumOperands()) { + const MCOperand &MOTLS = MI.getOperand(OpNum + 1); + Fixups.push_back(MCFixup::Create(0, MOTLS.getExpr(), + (MCFixupKind)SystemZ::FK_390_TLS_CALL)); + } return 0; } diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCFixups.h b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCFixups.h index 52a8d1d..229ab5d 100644 --- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCFixups.h +++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCFixups.h @@ -18,8 +18,7 @@ enum FixupKind { // These correspond directly to R_390_* relocations. FK_390_PC16DBL = FirstTargetFixupKind, FK_390_PC32DBL, - FK_390_PLT16DBL, - FK_390_PLT32DBL, + FK_390_TLS_CALL, // Marker LastTargetFixupKind, diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp index c6a1816..2632518 100644 --- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp +++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCObjectWriter.cpp @@ -55,8 +55,6 @@ static unsigned getPCRelReloc(unsigned Kind) { case FK_Data_8: return ELF::R_390_PC64; case SystemZ::FK_390_PC16DBL: return ELF::R_390_PC16DBL; case SystemZ::FK_390_PC32DBL: return ELF::R_390_PC32DBL; - case SystemZ::FK_390_PLT16DBL: return ELF::R_390_PLT16DBL; - case SystemZ::FK_390_PLT32DBL: return ELF::R_390_PLT32DBL; } llvm_unreachable("Unsupported PC-relative address"); } @@ -70,6 +68,35 @@ static unsigned getTLSLEReloc(unsigned Kind) { llvm_unreachable("Unsupported absolute address"); } +// Return the R_390_TLS_LDO* relocation type for MCFixupKind Kind. +static unsigned getTLSLDOReloc(unsigned Kind) { + switch (Kind) { + case FK_Data_4: return ELF::R_390_TLS_LDO32; + case FK_Data_8: return ELF::R_390_TLS_LDO64; + } + llvm_unreachable("Unsupported absolute address"); +} + +// Return the R_390_TLS_LDM* relocation type for MCFixupKind Kind. +static unsigned getTLSLDMReloc(unsigned Kind) { + switch (Kind) { + case FK_Data_4: return ELF::R_390_TLS_LDM32; + case FK_Data_8: return ELF::R_390_TLS_LDM64; + case SystemZ::FK_390_TLS_CALL: return ELF::R_390_TLS_LDCALL; + } + llvm_unreachable("Unsupported absolute address"); +} + +// Return the R_390_TLS_GD* relocation type for MCFixupKind Kind. +static unsigned getTLSGDReloc(unsigned Kind) { + switch (Kind) { + case FK_Data_4: return ELF::R_390_TLS_GD32; + case FK_Data_8: return ELF::R_390_TLS_GD64; + case SystemZ::FK_390_TLS_CALL: return ELF::R_390_TLS_GDCALL; + } + llvm_unreachable("Unsupported absolute address"); +} + // Return the PLT relocation counterpart of MCFixupKind Kind. static unsigned getPLTReloc(unsigned Kind) { switch (Kind) { @@ -94,6 +121,23 @@ unsigned SystemZObjectWriter::GetRelocType(const MCValue &Target, assert(!IsPCRel && "NTPOFF shouldn't be PC-relative"); return getTLSLEReloc(Kind); + case MCSymbolRefExpr::VK_INDNTPOFF: + if (IsPCRel && Kind == SystemZ::FK_390_PC32DBL) + return ELF::R_390_TLS_IEENT; + llvm_unreachable("Only PC-relative INDNTPOFF accesses are supported for now"); + + case MCSymbolRefExpr::VK_DTPOFF: + assert(!IsPCRel && "DTPOFF shouldn't be PC-relative"); + return getTLSLDOReloc(Kind); + + case MCSymbolRefExpr::VK_TLSLDM: + assert(!IsPCRel && "TLSLDM shouldn't be PC-relative"); + return getTLSLDMReloc(Kind); + + case MCSymbolRefExpr::VK_TLSGD: + assert(!IsPCRel && "TLSGD shouldn't be PC-relative"); + return getTLSGDReloc(Kind); + case MCSymbolRefExpr::VK_GOT: if (IsPCRel && Kind == SystemZ::FK_390_PC32DBL) return ELF::R_390_GOTENT; diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td index 902d74d..0f75264 100644 --- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td +++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td @@ -251,9 +251,10 @@ let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1 in { // Define the general form of the call instructions for the asm parser. // These instructions don't hard-code %r14 as the return address register. -def BRAS : InstRI<0xA75, (outs), (ins GR64:$R1, brtarget16:$I2), +// Allow an optional TLS marker symbol to generate TLS call relocations. +def BRAS : InstRI<0xA75, (outs), (ins GR64:$R1, brtarget16tls:$I2), "bras\t$R1, $I2", []>; -def BRASL : InstRIL<0xC05, (outs), (ins GR64:$R1, brtarget32:$I2), +def BRASL : InstRIL<0xC05, (outs), (ins GR64:$R1, brtarget32tls:$I2), "brasl\t$R1, $I2", []>; def BASR : InstRR<0x0D, (outs), (ins GR64:$R1, ADDR64:$R2), "basr\t$R1, $R2", []>; diff --git a/llvm/lib/Target/SystemZ/SystemZOperands.td b/llvm/lib/Target/SystemZ/SystemZOperands.td index 7be81dc..1b5b7d7 100644 --- a/llvm/lib/Target/SystemZ/SystemZOperands.td +++ b/llvm/lib/Target/SystemZ/SystemZOperands.td @@ -16,6 +16,11 @@ class ImmediateAsmOperand let Name = name; let RenderMethod = "addImmOperands"; } +class ImmediateTLSAsmOperand + : AsmOperandClass { + let Name = name; + let RenderMethod = "addImmTLSOperands"; +} // Constructs both a DAG pattern and instruction operand for an immediate // of type VT. PRED returns true if a node is acceptable and XFORM returns @@ -34,6 +39,11 @@ class PCRelAsmOperand : ImmediateAsmOperand<"PCRel"##size> { let PredicateMethod = "isImm"; let ParserMethod = "parsePCRel"##size; } +class PCRelTLSAsmOperand + : ImmediateTLSAsmOperand<"PCRelTLS"##size> { + let PredicateMethod = "isImmTLS"; + let ParserMethod = "parsePCRelTLS"##size; +} // Constructs an operand for a PC-relative address with address type VT. // ASMOP is the associated asm operand. @@ -41,6 +51,10 @@ class PCRelOperand : Operand { let PrintMethod = "printPCRelOperand"; let ParserMatchClass = asmop; } +class PCRelTLSOperand : Operand { + let PrintMethod = "printPCRelTLSOperand"; + let ParserMatchClass = asmop; +} // Constructs both a DAG pattern and instruction operand for a PC-relative // address with address size VT. SELF is the name of the operand and @@ -370,6 +384,8 @@ def fpimmneg0 : PatLeaf<(fpimm), [{ return N->isExactlyValue(-0.0); }]>; // PC-relative asm operands. def PCRel16 : PCRelAsmOperand<"16">; def PCRel32 : PCRelAsmOperand<"32">; +def PCRelTLS16 : PCRelTLSAsmOperand<"16">; +def PCRelTLS32 : PCRelTLSAsmOperand<"32">; // PC-relative offsets of a basic block. The offset is sign-extended // and multiplied by 2. @@ -382,6 +398,20 @@ def brtarget32 : PCRelOperand { let DecoderMethod = "decodePC32DBLOperand"; } +// Variants of brtarget16/32 with an optional additional TLS symbol. +// These are used to annotate calls to __tls_get_offset. +def tlssym : Operand { } +def brtarget16tls : PCRelTLSOperand { + let MIOperandInfo = (ops brtarget16:$func, tlssym:$sym); + let EncoderMethod = "getPC16DBLTLSEncoding"; + let DecoderMethod = "decodePC16DBLOperand"; +} +def brtarget32tls : PCRelTLSOperand { + let MIOperandInfo = (ops brtarget32:$func, tlssym:$sym); + let EncoderMethod = "getPC32DBLTLSEncoding"; + let DecoderMethod = "decodePC32DBLOperand"; +} + // A PC-relative offset of a global value. The offset is sign-extended // and multiplied by 2. def pcrel32 : PCRelAddress { diff --git a/llvm/test/MC/SystemZ/fixups.s b/llvm/test/MC/SystemZ/fixups.s new file mode 100644 index 0000000..8354121 --- /dev/null +++ b/llvm/test/MC/SystemZ/fixups.s @@ -0,0 +1,119 @@ + +# RUN: llvm-mc -triple s390x-unknown-unknown --show-encoding %s | FileCheck %s + +# RUN: llvm-mc -triple s390x-unknown-unknown -filetype=obj %s | \ +# RUN: llvm-readobj -r | FileCheck %s -check-prefix=CHECK-REL + +# CHECK: larl %r14, target # encoding: [0xc0,0xe0,A,A,A,A] +# CHECK-NEXT: # fixup A - offset: 2, value: target+2, kind: FK_390_PC32DBL +# CHECK-REL: 0x{{[0-9A-F]*2}} R_390_PC32DBL target 0x2 + .align 16 + larl %r14, target + +# CHECK: larl %r14, target@GOT # encoding: [0xc0,0xe0,A,A,A,A] +# CHECK-NEXT: # fixup A - offset: 2, value: target@GOT+2, kind: FK_390_PC32DBL +# CHECK-REL: 0x{{[0-9A-F]*2}} R_390_GOTENT target 0x2 + .align 16 + larl %r14, target@got + +# CHECK: larl %r14, target@INDNTPOFF # encoding: [0xc0,0xe0,A,A,A,A] +# CHECK-NEXT: # fixup A - offset: 2, value: target@INDNTPOFF+2, kind: FK_390_PC32DBL +# CHECK-REL: 0x{{[0-9A-F]*2}} R_390_TLS_IEENT target 0x2 + .align 16 + larl %r14, target@indntpoff + +# CHECK: brasl %r14, target # encoding: [0xc0,0xe5,A,A,A,A] +# CHECK-NEXT: # fixup A - offset: 2, value: target+2, kind: FK_390_PC32DBL +# CHECK-REL: 0x{{[0-9A-F]*2}} R_390_PC32DBL target 0x2 + .align 16 + brasl %r14, target + +# CHECK: brasl %r14, target@PLT # encoding: [0xc0,0xe5,A,A,A,A] +# CHECK-NEXT: # fixup A - offset: 2, value: target@PLT+2, kind: FK_390_PC32DBL +# CHECK-REL: 0x{{[0-9A-F]*2}} R_390_PLT32DBL target 0x2 + .align 16 + brasl %r14, target@plt + +# CHECK: brasl %r14, target@PLT:tls_gdcall:sym # encoding: [0xc0,0xe5,A,A,A,A] +# CHECK-NEXT: # fixup A - offset: 2, value: target@PLT+2, kind: FK_390_PC32DBL +# CHECK-NEXT: # fixup B - offset: 0, value: sym@TLSGD, kind: FK_390_TLS_CALL +# CHECK-REL: 0x{{[0-9A-F]*0}} R_390_TLS_GDCALL sym 0x0 +# CHECK-REL: 0x{{[0-9A-F]*2}} R_390_PLT32DBL target 0x2 + .align 16 + brasl %r14, target@plt:tls_gdcall:sym + +# CHECK: brasl %r14, target@PLT:tls_ldcall:sym # encoding: [0xc0,0xe5,A,A,A,A] +# CHECK-NEXT: # fixup A - offset: 2, value: target@PLT+2, kind: FK_390_PC32DBL +# CHECK-NEXT: # fixup B - offset: 0, value: sym@TLSLDM, kind: FK_390_TLS_CALL +# CHECK-REL: 0x{{[0-9A-F]*0}} R_390_TLS_LDCALL sym 0x0 +# CHECK-REL: 0x{{[0-9A-F]*2}} R_390_PLT32DBL target 0x2 + .align 16 + brasl %r14, target@plt:tls_ldcall:sym + +# CHECK: bras %r14, target # encoding: [0xa7,0xe5,A,A] +# CHECK-NEXT: # fixup A - offset: 2, value: target+2, kind: FK_390_PC16DBL +# CHECK-REL: 0x{{[0-9A-F]*2}} R_390_PC16DBL target 0x2 + .align 16 + bras %r14, target + +# CHECK: bras %r14, target@PLT # encoding: [0xa7,0xe5,A,A] +# CHECK-NEXT: # fixup A - offset: 2, value: target@PLT+2, kind: FK_390_PC16DBL +# CHECK-REL: 0x{{[0-9A-F]*2}} R_390_PLT16DBL target 0x2 + .align 16 + bras %r14, target@plt + +# CHECK: bras %r14, target@PLT:tls_gdcall:sym # encoding: [0xa7,0xe5,A,A] +# CHECK-NEXT: # fixup A - offset: 2, value: target@PLT+2, kind: FK_390_PC16DBL +# CHECK-NEXT: # fixup B - offset: 0, value: sym@TLSGD, kind: FK_390_TLS_CALL +# CHECK-REL: 0x{{[0-9A-F]*0}} R_390_TLS_GDCALL sym 0x0 +# CHECK-REL: 0x{{[0-9A-F]*2}} R_390_PLT16DBL target 0x2 + .align 16 + bras %r14, target@plt:tls_gdcall:sym + +# CHECK: bras %r14, target@PLT:tls_ldcall:sym # encoding: [0xa7,0xe5,A,A] +# CHECK-NEXT: # fixup A - offset: 2, value: target@PLT+2, kind: FK_390_PC16DBL +# CHECK-NEXT: # fixup B - offset: 0, value: sym@TLSLDM, kind: FK_390_TLS_CALL +# CHECK-REL: 0x{{[0-9A-F]*0}} R_390_TLS_LDCALL sym 0x0 +# CHECK-REL: 0x{{[0-9A-F]*2}} R_390_PLT16DBL target 0x2 + .align 16 + bras %r14, target@plt:tls_ldcall:sym + + +# Data relocs +# llvm-mc does not show any "encoding" string for data, so we just check the relocs + +# CHECK-REL: .rela.data + .data + +# CHECK-REL: 0x{{[0-9A-F]*0}} R_390_TLS_LE64 target 0x0 + .align 16 + .quad target@ntpoff + +# CHECK-REL: 0x{{[0-9A-F]*0}} R_390_TLS_LDO64 target 0x0 + .align 16 + .quad target@dtpoff + +# CHECK-REL: 0x{{[0-9A-F]*0}} R_390_TLS_LDM64 target 0x0 + .align 16 + .quad target@tlsldm + +# CHECK-REL: 0x{{[0-9A-F]*0}} R_390_TLS_GD64 target 0x0 + .align 16 + .quad target@tlsgd + +# CHECK-REL: 0x{{[0-9A-F]*0}} R_390_TLS_LE32 target 0x0 + .align 16 + .long target@ntpoff + +# CHECK-REL: 0x{{[0-9A-F]*0}} R_390_TLS_LDO32 target 0x0 + .align 16 + .long target@dtpoff + +# CHECK-REL: 0x{{[0-9A-F]*0}} R_390_TLS_LDM32 target 0x0 + .align 16 + .long target@tlsldm + +# CHECK-REL: 0x{{[0-9A-F]*0}} R_390_TLS_GD32 target 0x0 + .align 16 + .long target@tlsgd + -- 2.7.4