aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCullen Rhodes <cullen.rhodes@arm.com>2020-10-08 14:51:10 +0000
committerTom Stellard <tstellar@redhat.com>2020-12-08 16:30:15 -0500
commit542174d77deb7f2a59bcd0b8147144d4e123cf7b (patch)
treef99cc1e84d04fc1f574bf4e4d3afef903b01d3d1
parent724f62a50241d782f9c46d98e4fb796d60953df4 (diff)
downloadllvm-542174d77deb7f2a59bcd0b8147144d4e123cf7b.zip
llvm-542174d77deb7f2a59bcd0b8147144d4e123cf7b.tar.gz
llvm-542174d77deb7f2a59bcd0b8147144d4e123cf7b.tar.bz2
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 (cherry picked from commit c87bd2d8eb378d152f2b6bde4cb088ad390a676c)
-rw-r--r--llvm/include/llvm/BinaryFormat/ELF.h6
-rw-r--r--llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp15
-rw-r--r--llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp30
-rw-r--r--llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp8
-rw-r--r--llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h4
-rw-r--r--llvm/test/CodeGen/AArch64/variant-pcs.ll51
-rw-r--r--llvm/test/MC/AArch64/directive-variant_pcs-err.s17
-rw-r--r--llvm/test/MC/AArch64/directive-variant_pcs.s11
8 files changed, 142 insertions, 0 deletions
diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h
index bdcf10f..21a5c26 100644
--- a/llvm/include/llvm/BinaryFormat/ELF.h
+++ b/llvm/include/llvm/BinaryFormat/ELF.h
@@ -405,6 +405,12 @@ enum {
#include "ELFRelocs/AArch64.def"
};
+// Special values for the st_other field in the symbol table entry for AArch64.
+enum {
+ // Symbol may follow different calling convention than base PCS.
+ STO_AARCH64_VARIANT_PCS = 0x80
+};
+
// ARM Specific e_flags
enum : unsigned {
EF_ARM_SOFT_FLOAT = 0x00000200U, // Legacy pre EABI_VER5
diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
index 3a94820..7ec7ffe 100644
--- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
+++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
@@ -89,6 +89,8 @@ public:
void emitJumpTableEntry(const MachineJumpTableInfo *MJTI,
const MachineBasicBlock *MBB, unsigned JTI);
+ void emitFunctionEntryLabel() override;
+
void LowerJumpTableDestSmall(MCStreamer &OutStreamer, const MachineInstr &MI);
void LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
@@ -822,6 +824,19 @@ void AArch64AsmPrinter::emitJumpTableEntry(const MachineJumpTableInfo *MJTI,
OutStreamer->emitValue(Value, Size);
}
+void AArch64AsmPrinter::emitFunctionEntryLabel() {
+ if (MF->getFunction().getCallingConv() == CallingConv::AArch64_VectorCall ||
+ MF->getFunction().getCallingConv() ==
+ CallingConv::AArch64_SVE_VectorCall ||
+ STI->getRegisterInfo()->hasSVEArgsOrReturn(MF)) {
+ auto *TS =
+ static_cast<AArch64TargetStreamer *>(OutStreamer->getTargetStreamer());
+ TS->emitDirectiveVariantPCS(CurrentFnSym);
+ }
+
+ return AsmPrinter::emitFunctionEntryLabel();
+}
+
/// Small jump tables contain an unsigned byte or half, representing the offset
/// from the lowest-addressed possible destination to the desired basic
/// block. Since all instructions are 4-byte aligned, this is further compressed
diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index 0ac09c4..e72ae0e 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -179,6 +179,8 @@ private:
bool parseDirectiveCFINegateRAState();
bool parseDirectiveCFIBKeyFrame();
+ bool parseDirectiveVariantPCS(SMLoc L);
+
bool validateInstruction(MCInst &Inst, SMLoc &IDLoc,
SmallVectorImpl<SMLoc> &Loc);
bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
@@ -5077,6 +5079,8 @@ bool AArch64AsmParser::ParseDirective(AsmToken DirectiveID) {
parseDirectiveCFIBKeyFrame();
else if (IDVal == ".arch_extension")
parseDirectiveArchExtension(Loc);
+ else if (IDVal == ".variant_pcs")
+ parseDirectiveVariantPCS(Loc);
else if (IsMachO) {
if (IDVal == MCLOHDirectiveName())
parseDirectiveLOH(IDVal, Loc);
@@ -5507,6 +5511,32 @@ bool AArch64AsmParser::parseDirectiveCFIBKeyFrame() {
return false;
}
+/// parseDirectiveVariantPCS
+/// ::= .variant_pcs symbolname
+bool AArch64AsmParser::parseDirectiveVariantPCS(SMLoc L) {
+ MCAsmParser &Parser = getParser();
+
+ const AsmToken &Tok = Parser.getTok();
+ if (Tok.isNot(AsmToken::Identifier))
+ return TokError("expected symbol name");
+
+ StringRef SymbolName = Tok.getIdentifier();
+
+ MCSymbol *Sym = getContext().lookupSymbol(SymbolName);
+ if (!Sym)
+ return TokError("unknown symbol in '.variant_pcs' directive");
+
+ Parser.Lex(); // Eat the symbol
+
+ // Shouldn't be any more tokens
+ if (parseToken(AsmToken::EndOfStatement))
+ return addErrorSuffix(" in '.variant_pcs' directive");
+
+ getTargetStreamer().emitDirectiveVariantPCS(Sym);
+
+ return false;
+}
+
bool
AArch64AsmParser::classifySymbolRef(const MCExpr *Expr,
AArch64MCExpr::VariantKind &ELFRefKind,
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp
index fe4c34b..6dfda82 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp
@@ -47,6 +47,10 @@ class AArch64TargetAsmStreamer : public AArch64TargetStreamer {
void emitInst(uint32_t Inst) override;
+ void emitDirectiveVariantPCS(MCSymbol *Symbol) override {
+ OS << "\t.variant_pcs " << Symbol->getName() << "\n";
+ }
+
public:
AArch64TargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS);
};
@@ -194,6 +198,10 @@ void AArch64TargetELFStreamer::emitInst(uint32_t Inst) {
getStreamer().emitInst(Inst);
}
+void AArch64TargetELFStreamer::emitDirectiveVariantPCS(MCSymbol *Symbol) {
+ cast<MCSymbolELF>(Symbol)->setOther(ELF::STO_AARCH64_VARIANT_PCS);
+}
+
MCTargetStreamer *createAArch64AsmTargetStreamer(MCStreamer &S,
formatted_raw_ostream &OS,
MCInstPrinter *InstPrint,
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h
index 3a0c5d8..1af978a 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h
@@ -36,6 +36,9 @@ public:
/// Callback used to implement the .inst directive.
virtual void emitInst(uint32_t Inst);
+ /// Callback used to implement the .variant_pcs directive.
+ virtual void emitDirectiveVariantPCS(MCSymbol *Symbol) {};
+
virtual void EmitARM64WinCFIAllocStack(unsigned Size) {}
virtual void EmitARM64WinCFISaveFPLR(int Offset) {}
virtual void EmitARM64WinCFISaveFPLRX(int Offset) {}
@@ -63,6 +66,7 @@ private:
AArch64ELFStreamer &getStreamer();
void emitInst(uint32_t Inst) override;
+ void emitDirectiveVariantPCS(MCSymbol *Symbol) override;
public:
AArch64TargetELFStreamer(MCStreamer &S) : AArch64TargetStreamer(S) {}
diff --git a/llvm/test/CodeGen/AArch64/variant-pcs.ll b/llvm/test/CodeGen/AArch64/variant-pcs.ll
new file mode 100644
index 0000000..f6e5fd1
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/variant-pcs.ll
@@ -0,0 +1,51 @@
+; RUN: llc -mtriple=aarch64-linux-gnu -mattr=+sve -o - %s | FileCheck %s --check-prefix=CHECK-ASM
+; RUN: llc -mtriple=aarch64-linux-gnu -mattr=+sve -filetype=obj -o - %s \
+; RUN: | llvm-readobj --symbols - | FileCheck %s --check-prefix=CHECK-OBJ
+
+define i32 @base_pcs() {
+; CHECK-ASM-LABEL: base_pcs:
+; CHECK-ASM-NOT: .variant_pcs
+; CHECK-OBJ-LABEL: Name: base_pcs
+; CHECK-OBJ: Other: 0
+ ret i32 42
+}
+
+define aarch64_vector_pcs <4 x i32> @neon_vector_pcs_1(<4 x i32> %arg) {
+; CHECK-ASM: .variant_pcs neon_vector_pcs_1
+; CHECK-ASM-NEXT: neon_vector_pcs_1:
+; CHECK-OBJ-LABEL: Name: neon_vector_pcs_1
+; CHECK-OBJ: Other [ (0x80)
+ ret <4 x i32> %arg
+}
+
+define <vscale x 4 x i32> @sve_vector_pcs_1() {
+; CHECK-ASM: .variant_pcs sve_vector_pcs_1
+; CHECK-ASM-NEXT: sve_vector_pcs_1:
+; CHECK-OBJ-LABEL: Name: sve_vector_pcs_1
+; CHECK-OBJ: Other [ (0x80)
+ ret <vscale x 4 x i32> undef
+}
+
+define <vscale x 4 x i1> @sve_vector_pcs_2() {
+; CHECK-ASM: .variant_pcs sve_vector_pcs_2
+; CHECK-ASM-NEXT: sve_vector_pcs_2:
+; CHECK-OBJ-LABEL: Name: sve_vector_pcs_2
+; CHECK-OBJ: Other [ (0x80)
+ ret <vscale x 4 x i1> undef
+}
+
+define void @sve_vector_pcs_3(<vscale x 4 x i32> %arg) {
+; CHECK-ASM: .variant_pcs sve_vector_pcs_3
+; CHECK-ASM-NEXT: sve_vector_pcs_3:
+; CHECK-OBJ-LABEL: Name: sve_vector_pcs_3
+; CHECK-OBJ: Other [ (0x80)
+ ret void
+}
+
+define void @sve_vector_pcs_4(<vscale x 4 x i1> %arg) {
+; CHECK-ASM: .variant_pcs sve_vector_pcs_4
+; CHECK-ASM-NEXT: sve_vector_pcs_4:
+; CHECK-OBJ-LABEL: Name: sve_vector_pcs_4
+; CHECK-OBJ: Other [ (0x80)
+ ret void
+}
diff --git a/llvm/test/MC/AArch64/directive-variant_pcs-err.s b/llvm/test/MC/AArch64/directive-variant_pcs-err.s
new file mode 100644
index 0000000..98cf703
--- /dev/null
+++ b/llvm/test/MC/AArch64/directive-variant_pcs-err.s
@@ -0,0 +1,17 @@
+// RUN: not llvm-mc -triple aarch64-unknown-none-eabi -filetype asm -o - %s 2>&1 | FileCheck %s
+
+.variant_pcs
+// CHECK: error: expected symbol name
+// CHECK-NEXT: .variant_pcs
+// CHECK-NEXT: ^
+
+.variant_pcs foo
+// CHECK: error: unknown symbol in '.variant_pcs' directive
+// CHECK-NEXT: .variant_pcs foo
+// CHECK-NEXT: ^
+
+.global foo
+.variant_pcs foo bar
+// CHECK: error: unexpected token in '.variant_pcs' directive
+// CHECK-NEXT: .variant_pcs foo bar
+// CHECK-NEXT: ^
diff --git a/llvm/test/MC/AArch64/directive-variant_pcs.s b/llvm/test/MC/AArch64/directive-variant_pcs.s
new file mode 100644
index 0000000..f6f9c9c
--- /dev/null
+++ b/llvm/test/MC/AArch64/directive-variant_pcs.s
@@ -0,0 +1,11 @@
+// RUN: llvm-mc -triple aarch64-elf -filetype asm -o - %s | FileCheck %s
+// RUN: llvm-mc -triple aarch64-elf -filetype obj -o - %s \
+// RUN: | llvm-readobj --symbols - | FileCheck %s --check-prefix=CHECK-ST_OTHER
+
+.text
+.global foo
+.variant_pcs foo
+// CHECK: .variant_pcs foo
+
+// CHECK-ST_OTHER: Name: foo
+// CHECK-ST_OTHER: Other [ (0x80)