[llvm-branch-commits] [llvm] 25d8502 - [PPC32] Parse bl __tls_get_addr(x at tlsgd)@plt+32768
Tobias Hieta via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Aug 8 23:59:25 PDT 2023
Author: Fangrui Song
Date: 2023-08-09T08:56:03+02:00
New Revision: 25d8502b7802404c1544a99020def3e29e6cf96e
URL: https://github.com/llvm/llvm-project/commit/25d8502b7802404c1544a99020def3e29e6cf96e
DIFF: https://github.com/llvm/llvm-project/commit/25d8502b7802404c1544a99020def3e29e6cf96e.diff
LOG: [PPC32] Parse bl __tls_get_addr(x at tlsgd)@plt+32768
PPC32 -fpic/-fPIC generates `bl __tls_get_addr(x at tlsgd)@PLT` or
`bl __tls_get_addr(x at tlsgd)@PLT+32768`.
`powerpc-linux-gnu-gcc -fPIC` generates `bl __tls_get_addr+32668(x at tlsgd)@plt`.
These expressions can be parsed by GNU assembler but not by the integrated
assembler. Add the support.
Differential Revision: https://reviews.llvm.org/D153206
(cherry picked from commit 6e07e90890d61b1be19d3f5fbf00ea7430068325)
Added:
llvm/test/MC/PowerPC/ppc32-tls.s
Modified:
llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
index 56fdf19a0720c3..4f93cdaaa13764 100644
--- a/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
+++ b/llvm/lib/Target/PowerPC/AsmParser/PPCAsmParser.cpp
@@ -1544,24 +1544,58 @@ bool PPCAsmParser::ParseOperand(OperandVector &Operands) {
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<MCSymbolRefExpr>(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<MCSymbolRefExpr>(EVal)) {
+ TlsCall = Ref->getSymbol().getName() == TlsGetAddr;
+ } else if (auto *Bin = dyn_cast<MCBinaryExpr>(EVal);
+ Bin && Bin->getOpcode() == MCBinaryExpr::Add) {
+ if (auto *Ref = dyn_cast<MCSymbolRefExpr>(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 at 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 at tlsgd)@plt+b
+ TlsCallAddend =
+ MCBinaryExpr::createAdd(TlsCallAddend, Addend, getContext());
+ else // __tls_get_addr(x at 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
index dbdfb6e906bbee..13480da4e7317e 100644
--- a/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/MCTargetDesc/PPCInstPrinter.cpp
@@ -564,10 +564,10 @@ void PPCInstPrinter::printTLSCall(const MCInst *MI, unsigned OpNo,
// 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<MCBinaryExpr>(Op.getExpr())) {
RefExp = cast<MCSymbolRefExpr>(BinExpr->getLHS());
- ConstExp = cast<MCConstantExpr>(BinExpr->getRHS());
+ Rhs = BinExpr->getRHS();
} else
RefExp = cast<MCSymbolRefExpr>(Op.getExpr());
@@ -584,8 +584,14 @@ void PPCInstPrinter::printTLSCall(const MCInst *MI, unsigned OpNo,
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
index 00000000000000..3acf40e57f7f3d
--- /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 at tlsgd)
+# ASM: bl __tls_get_addr(b at tlsld)
+# ASM: bl __tls_get_addr(c at tlsgd)@PLT
+# ASM: bl __tls_get_addr(d at tlsld)@PLT+32768
+# ASM: bl __tls_get_addr(e at tlsld)@PLT+32768
+bl __tls_get_addr(a at tlsgd)
+bl __tls_get_addr(b at tlsld)
+bl __tls_get_addr(c at tlsgd)@plt
+bl __tls_get_addr(d at tlsld)@PLT+32768
+bl __tls_get_addr+32768(e at 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 at tlsld)@PLT+1+(-2)
+bl __tls_get_addr+1(f at tlsld)@PLT+-2
+# ASM: bl __tls_get_addr(g at tlsld)@PLT+1+(y-x)
+x:
+bl __tls_get_addr+1(g at 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 at tlsld)plt
+# ERR: :[[#@LINE+1]]:28: error: expected 'plt'
+bl __tls_get_addr(d at tlsld)@invalid
+# ERR: :[[#@LINE+1]]:31: error: unexpected token
+bl __tls_get_addr(d at tlsld)@plt-32768
+
+# ERR: :[[#@LINE+1]]:21: error: invalid memory operand
+bl __tls_get_addr-1(f at tlsld)@plt
+.endif
More information about the llvm-branch-commits
mailing list