Skip to content

Commit c87bd2d

Browse files
committed
[AArch64] Implement .variant_pcs directive
A dynamic linker with lazy binding support may need to handle variant PCS function symbols specially, so an ELF symbol table marking STO_AARCH64_VARIANT_PCS [1] was added to address this. Function symbols that follow the vector PCS are marked via the .variant_pcs assembler directive, which takes a single parameter specifying the symbol name and sets the STO_AARCH64_VARIANT_PCS st_other flag in the object file. [1] https://github.com/ARM-software/abi-aa/blob/master/aaelf64/aaelf64.rst#st-other-values Reviewed By: sdesmalen Differential Revision: https://reviews.llvm.org/D89138
1 parent 6e56046 commit c87bd2d

File tree

8 files changed

+142
-0
lines changed

8 files changed

+142
-0
lines changed

llvm/include/llvm/BinaryFormat/ELF.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,12 @@ enum {
406406
#include "ELFRelocs/AArch64.def"
407407
};
408408

409+
// Special values for the st_other field in the symbol table entry for AArch64.
410+
enum {
411+
// Symbol may follow different calling convention than base PCS.
412+
STO_AARCH64_VARIANT_PCS = 0x80
413+
};
414+
409415
// ARM Specific e_flags
410416
enum : unsigned {
411417
EF_ARM_SOFT_FLOAT = 0x00000200U, // Legacy pre EABI_VER5

llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ class AArch64AsmPrinter : public AsmPrinter {
8989
void emitStartOfAsmFile(Module &M) override;
9090
void emitJumpTableInfo() override;
9191

92+
void emitFunctionEntryLabel() override;
93+
9294
void LowerJumpTableDest(MCStreamer &OutStreamer, const MachineInstr &MI);
9395

9496
void LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
@@ -787,6 +789,19 @@ void AArch64AsmPrinter::emitJumpTableInfo() {
787789
}
788790
}
789791

792+
void AArch64AsmPrinter::emitFunctionEntryLabel() {
793+
if (MF->getFunction().getCallingConv() == CallingConv::AArch64_VectorCall ||
794+
MF->getFunction().getCallingConv() ==
795+
CallingConv::AArch64_SVE_VectorCall ||
796+
STI->getRegisterInfo()->hasSVEArgsOrReturn(MF)) {
797+
auto *TS =
798+
static_cast<AArch64TargetStreamer *>(OutStreamer->getTargetStreamer());
799+
TS->emitDirectiveVariantPCS(CurrentFnSym);
800+
}
801+
802+
return AsmPrinter::emitFunctionEntryLabel();
803+
}
804+
790805
/// Small jump tables contain an unsigned byte or half, representing the offset
791806
/// from the lowest-addressed possible destination to the desired basic
792807
/// block. Since all instructions are 4-byte aligned, this is further compressed

llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,8 @@ class AArch64AsmParser : public MCTargetAsmParser {
184184
bool parseDirectiveCFINegateRAState();
185185
bool parseDirectiveCFIBKeyFrame();
186186

187+
bool parseDirectiveVariantPCS(SMLoc L);
188+
187189
bool parseDirectiveSEHAllocStack(SMLoc L);
188190
bool parseDirectiveSEHPrologEnd(SMLoc L);
189191
bool parseDirectiveSEHSaveR19R20X(SMLoc L);
@@ -5171,6 +5173,8 @@ bool AArch64AsmParser::ParseDirective(AsmToken DirectiveID) {
51715173
parseDirectiveCFIBKeyFrame();
51725174
else if (IDVal == ".arch_extension")
51735175
parseDirectiveArchExtension(Loc);
5176+
else if (IDVal == ".variant_pcs")
5177+
parseDirectiveVariantPCS(Loc);
51745178
else if (IsMachO) {
51755179
if (IDVal == MCLOHDirectiveName())
51765180
parseDirectiveLOH(IDVal, Loc);
@@ -5650,6 +5654,32 @@ bool AArch64AsmParser::parseDirectiveCFIBKeyFrame() {
56505654
return false;
56515655
}
56525656

5657+
/// parseDirectiveVariantPCS
5658+
/// ::= .variant_pcs symbolname
5659+
bool AArch64AsmParser::parseDirectiveVariantPCS(SMLoc L) {
5660+
MCAsmParser &Parser = getParser();
5661+
5662+
const AsmToken &Tok = Parser.getTok();
5663+
if (Tok.isNot(AsmToken::Identifier))
5664+
return TokError("expected symbol name");
5665+
5666+
StringRef SymbolName = Tok.getIdentifier();
5667+
5668+
MCSymbol *Sym = getContext().lookupSymbol(SymbolName);
5669+
if (!Sym)
5670+
return TokError("unknown symbol in '.variant_pcs' directive");
5671+
5672+
Parser.Lex(); // Eat the symbol
5673+
5674+
// Shouldn't be any more tokens
5675+
if (parseToken(AsmToken::EndOfStatement))
5676+
return addErrorSuffix(" in '.variant_pcs' directive");
5677+
5678+
getTargetStreamer().emitDirectiveVariantPCS(Sym);
5679+
5680+
return false;
5681+
}
5682+
56535683
/// parseDirectiveSEHAllocStack
56545684
/// ::= .seh_stackalloc
56555685
bool AArch64AsmParser::parseDirectiveSEHAllocStack(SMLoc L) {

llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ class AArch64TargetAsmStreamer : public AArch64TargetStreamer {
4747

4848
void emitInst(uint32_t Inst) override;
4949

50+
void emitDirectiveVariantPCS(MCSymbol *Symbol) override {
51+
OS << "\t.variant_pcs " << Symbol->getName() << "\n";
52+
}
53+
5054
void EmitARM64WinCFIAllocStack(unsigned Size) override {
5155
OS << "\t.seh_stackalloc " << Size << "\n";
5256
}
@@ -249,6 +253,10 @@ void AArch64TargetELFStreamer::emitInst(uint32_t Inst) {
249253
getStreamer().emitInst(Inst);
250254
}
251255

256+
void AArch64TargetELFStreamer::emitDirectiveVariantPCS(MCSymbol *Symbol) {
257+
cast<MCSymbolELF>(Symbol)->setOther(ELF::STO_AARCH64_VARIANT_PCS);
258+
}
259+
252260
MCTargetStreamer *createAArch64AsmTargetStreamer(MCStreamer &S,
253261
formatted_raw_ostream &OS,
254262
MCInstPrinter *InstPrint,

llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ class AArch64TargetStreamer : public MCTargetStreamer {
3939
/// Callback used to implement the .inst directive.
4040
virtual void emitInst(uint32_t Inst);
4141

42+
/// Callback used to implement the .variant_pcs directive.
43+
virtual void emitDirectiveVariantPCS(MCSymbol *Symbol) {};
44+
4245
virtual void EmitARM64WinCFIAllocStack(unsigned Size) {}
4346
virtual void EmitARM64WinCFISaveR19R20X(int Offset) {}
4447
virtual void EmitARM64WinCFISaveFPLR(int Offset) {}
@@ -73,6 +76,7 @@ class AArch64TargetELFStreamer : public AArch64TargetStreamer {
7376
AArch64ELFStreamer &getStreamer();
7477

7578
void emitInst(uint32_t Inst) override;
79+
void emitDirectiveVariantPCS(MCSymbol *Symbol) override;
7680

7781
public:
7882
AArch64TargetELFStreamer(MCStreamer &S) : AArch64TargetStreamer(S) {}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
; RUN: llc -mtriple=aarch64-linux-gnu -mattr=+sve -o - %s | FileCheck %s --check-prefix=CHECK-ASM
2+
; RUN: llc -mtriple=aarch64-linux-gnu -mattr=+sve -filetype=obj -o - %s \
3+
; RUN: | llvm-readobj --symbols - | FileCheck %s --check-prefix=CHECK-OBJ
4+
5+
define i32 @base_pcs() {
6+
; CHECK-ASM-LABEL: base_pcs:
7+
; CHECK-ASM-NOT: .variant_pcs
8+
; CHECK-OBJ-LABEL: Name: base_pcs
9+
; CHECK-OBJ: Other: 0
10+
ret i32 42
11+
}
12+
13+
define aarch64_vector_pcs <4 x i32> @neon_vector_pcs_1(<4 x i32> %arg) {
14+
; CHECK-ASM: .variant_pcs neon_vector_pcs_1
15+
; CHECK-ASM-NEXT: neon_vector_pcs_1:
16+
; CHECK-OBJ-LABEL: Name: neon_vector_pcs_1
17+
; CHECK-OBJ: Other [ (0x80)
18+
ret <4 x i32> %arg
19+
}
20+
21+
define <vscale x 4 x i32> @sve_vector_pcs_1() {
22+
; CHECK-ASM: .variant_pcs sve_vector_pcs_1
23+
; CHECK-ASM-NEXT: sve_vector_pcs_1:
24+
; CHECK-OBJ-LABEL: Name: sve_vector_pcs_1
25+
; CHECK-OBJ: Other [ (0x80)
26+
ret <vscale x 4 x i32> undef
27+
}
28+
29+
define <vscale x 4 x i1> @sve_vector_pcs_2() {
30+
; CHECK-ASM: .variant_pcs sve_vector_pcs_2
31+
; CHECK-ASM-NEXT: sve_vector_pcs_2:
32+
; CHECK-OBJ-LABEL: Name: sve_vector_pcs_2
33+
; CHECK-OBJ: Other [ (0x80)
34+
ret <vscale x 4 x i1> undef
35+
}
36+
37+
define void @sve_vector_pcs_3(<vscale x 4 x i32> %arg) {
38+
; CHECK-ASM: .variant_pcs sve_vector_pcs_3
39+
; CHECK-ASM-NEXT: sve_vector_pcs_3:
40+
; CHECK-OBJ-LABEL: Name: sve_vector_pcs_3
41+
; CHECK-OBJ: Other [ (0x80)
42+
ret void
43+
}
44+
45+
define void @sve_vector_pcs_4(<vscale x 4 x i1> %arg) {
46+
; CHECK-ASM: .variant_pcs sve_vector_pcs_4
47+
; CHECK-ASM-NEXT: sve_vector_pcs_4:
48+
; CHECK-OBJ-LABEL: Name: sve_vector_pcs_4
49+
; CHECK-OBJ: Other [ (0x80)
50+
ret void
51+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: not llvm-mc -triple aarch64-unknown-none-eabi -filetype asm -o - %s 2>&1 | FileCheck %s
2+
3+
.variant_pcs
4+
// CHECK: error: expected symbol name
5+
// CHECK-NEXT: .variant_pcs
6+
// CHECK-NEXT: ^
7+
8+
.variant_pcs foo
9+
// CHECK: error: unknown symbol in '.variant_pcs' directive
10+
// CHECK-NEXT: .variant_pcs foo
11+
// CHECK-NEXT: ^
12+
13+
.global foo
14+
.variant_pcs foo bar
15+
// CHECK: error: unexpected token in '.variant_pcs' directive
16+
// CHECK-NEXT: .variant_pcs foo bar
17+
// CHECK-NEXT: ^
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: llvm-mc -triple aarch64-elf -filetype asm -o - %s | FileCheck %s
2+
// RUN: llvm-mc -triple aarch64-elf -filetype obj -o - %s \
3+
// RUN: | llvm-readobj --symbols - | FileCheck %s --check-prefix=CHECK-ST_OTHER
4+
5+
.text
6+
.global foo
7+
.variant_pcs foo
8+
// CHECK: .variant_pcs foo
9+
10+
// CHECK-ST_OTHER: Name: foo
11+
// CHECK-ST_OTHER: Other [ (0x80)

0 commit comments

Comments
 (0)