diff --git a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp --- a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp +++ b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp @@ -1544,24 +1544,58 @@ Operands.push_back(PPCOperand::CreateFromMCExpr(EVal, S, E, isPPC64())); // Check whether this is a TLS call expression - bool TLSCall = false; - if (const MCSymbolRefExpr *Ref = dyn_cast(EVal)) - TLSCall = Ref->getSymbol().getName() == "__tls_get_addr"; + const char TlsGetAddr[] = "__tls_get_addr"; + bool TlsCall = false; + const MCExpr *TlsCallAddend = nullptr; + if (auto *Ref = dyn_cast(EVal)) { + TlsCall = Ref->getSymbol().getName() == TlsGetAddr; + } else if (auto *Bin = dyn_cast(EVal); + Bin && Bin->getOpcode() == MCBinaryExpr::Add) { + if (auto *Ref = dyn_cast(Bin->getLHS())) { + TlsCall = Ref->getSymbol().getName() == TlsGetAddr; + TlsCallAddend = Bin->getRHS(); + } + } - if (TLSCall && parseOptionalToken(AsmToken::LParen)) { + if (TlsCall && parseOptionalToken(AsmToken::LParen)) { const MCExpr *TLSSym; - S = Parser.getTok().getLoc(); + const SMLoc S2 = Parser.getTok().getLoc(); if (ParseExpression(TLSSym)) - return Error(S, "invalid TLS call expression"); + return Error(S2, "invalid TLS call expression"); + E = Parser.getTok().getLoc(); if (parseToken(AsmToken::RParen, "expected ')'")) return true; - E = Parser.getTok().getLoc(); + // PPC32 allows bl __tls_get_addr[+a](x@tlsgd)@plt+b. Parse "@plt[+b]". + if (!isPPC64() && parseOptionalToken(AsmToken::At)) { + AsmToken Tok = getTok(); + if (!(parseOptionalToken(AsmToken::Identifier) && + Tok.getString().compare_insensitive("plt") == 0)) + return Error(Tok.getLoc(), "expected 'plt'"); + EVal = MCSymbolRefExpr::create(TlsGetAddr, MCSymbolRefExpr::VK_PLT, + getContext()); + if (parseOptionalToken(AsmToken::Plus)) { + const MCExpr *Addend = nullptr; + SMLoc EndLoc; + if (parsePrimaryExpr(Addend, EndLoc)) + return true; + if (TlsCallAddend) // __tls_get_addr+a(x@tlsgd)@plt+b + TlsCallAddend = + MCBinaryExpr::createAdd(TlsCallAddend, Addend, getContext()); + else // __tls_get_addr(x@tlsgd)@plt+b + TlsCallAddend = Addend; + } + if (TlsCallAddend) + EVal = MCBinaryExpr::createAdd(EVal, TlsCallAddend, getContext()); + // Add a __tls_get_addr operand with addend a, b, or a+b. + Operands.back() = PPCOperand::CreateFromMCExpr( + EVal, S, Parser.getTok().getLoc(), false); + } Operands.push_back(PPCOperand::CreateFromMCExpr(TLSSym, S, E, isPPC64())); } // Otherwise, check for D-form memory operands - if (!TLSCall && parseOptionalToken(AsmToken::LParen)) { + if (!TlsCall && parseOptionalToken(AsmToken::LParen)) { S = Parser.getTok().getLoc(); int64_t IntVal; diff --git a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp --- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp +++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp @@ -564,10 +564,10 @@ // come at the _end_ of the expression. const MCOperand &Op = MI->getOperand(OpNo); const MCSymbolRefExpr *RefExp = nullptr; - const MCConstantExpr *ConstExp = nullptr; + const MCExpr *Rhs = nullptr; if (const MCBinaryExpr *BinExpr = dyn_cast(Op.getExpr())) { RefExp = cast(BinExpr->getLHS()); - ConstExp = cast(BinExpr->getRHS()); + Rhs = BinExpr->getRHS(); } else RefExp = cast(Op.getExpr()); @@ -584,8 +584,14 @@ if (RefExp->getKind() != MCSymbolRefExpr::VK_None && RefExp->getKind() != MCSymbolRefExpr::VK_PPC_NOTOC) O << '@' << MCSymbolRefExpr::getVariantKindName(RefExp->getKind()); - if (ConstExp != nullptr) - O << '+' << ConstExp->getValue(); + if (Rhs) { + SmallString<0> Buf; + raw_svector_ostream Tmp(Buf); + Rhs->print(Tmp, &MAI); + if (isdigit(Buf[0])) + O << '+'; + O << Buf; + } } /// showRegistersWithPercentPrefix - Check if this register name should be diff --git a/llvm/test/MC/PowerPC/ppc32-tls.s b/llvm/test/MC/PowerPC/ppc32-tls.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/PowerPC/ppc32-tls.s @@ -0,0 +1,53 @@ +# RUN: llvm-mc -triple=powerpc %s | FileCheck %s --check-prefix=ASM +# RUN: llvm-mc -filetype=obj -triple=powerpc %s -o %t +# RUN: llvm-readobj -r %t | FileCheck %s + +# RUN: not llvm-mc -triple=powerpc --defsym ERR=1 %s 2>&1 | FileCheck %s --check-prefix=ERR --implicit-check-not=error: + +# ASM: bl __tls_get_addr(a@tlsgd) +# ASM: bl __tls_get_addr(b@tlsld) +# ASM: bl __tls_get_addr(c@tlsgd)@PLT +# ASM: bl __tls_get_addr(d@tlsld)@PLT+32768 +# ASM: bl __tls_get_addr(e@tlsld)@PLT+32768 +bl __tls_get_addr(a@tlsgd) +bl __tls_get_addr(b@tlsld) +bl __tls_get_addr(c@tlsgd)@plt +bl __tls_get_addr(d@tlsld)@PLT+32768 +bl __tls_get_addr+32768(e@tlsld)@plt # gcc -fPIC + +## These are not present in the wild, but just to test we can parse them. +# ASM: bl __tls_get_addr(f@tlsld)@PLT+1+(-2) +bl __tls_get_addr+1(f@tlsld)@PLT+-2 +# ASM: bl __tls_get_addr(g@tlsld)@PLT+1+(y-x) +x: +bl __tls_get_addr+1(g@tlsld)@PLT+(y-x) +y: + +# CHECK: .rela.text { +# CHECK-NEXT: 0x0 R_PPC_TLSGD a 0x0 +# CHECK-NEXT: 0x0 R_PPC_REL24 __tls_get_addr 0x0 +# CHECK-NEXT: 0x4 R_PPC_TLSLD b 0x0 +# CHECK-NEXT: 0x4 R_PPC_REL24 __tls_get_addr 0x0 +# CHECK-NEXT: 0x8 R_PPC_TLSGD c 0x0 +# CHECK-NEXT: 0x8 R_PPC_PLTREL24 __tls_get_addr 0x0 +# CHECK-NEXT: 0xC R_PPC_TLSLD d 0x0 +# CHECK-NEXT: 0xC R_PPC_PLTREL24 __tls_get_addr 0x8000 +# CHECK-NEXT: 0x10 R_PPC_TLSLD e 0x0 +# CHECK-NEXT: 0x10 R_PPC_PLTREL24 __tls_get_addr 0x8000 +# CHECK-NEXT: 0x14 R_PPC_TLSLD f 0x0 +# CHECK-NEXT: 0x14 R_PPC_PLTREL24 __tls_get_addr 0xFFFFFFFF +# CHECK-NEXT: 0x18 R_PPC_TLSLD g 0x0 +# CHECK-NEXT: 0x18 R_PPC_PLTREL24 __tls_get_addr 0x5 +# CHECK-NEXT: } + +.ifdef ERR +# ERR: :[[#@LINE+1]]:27: error: unexpected token +bl __tls_get_addr(d@tlsld)plt +# ERR: :[[#@LINE+1]]:28: error: expected 'plt' +bl __tls_get_addr(d@tlsld)@invalid +# ERR: :[[#@LINE+1]]:31: error: unexpected token +bl __tls_get_addr(d@tlsld)@plt-32768 + +# ERR: :[[#@LINE+1]]:21: error: invalid memory operand +bl __tls_get_addr-1(f@tlsld)@plt +.endif