diff options
author | 2020-10-08 14:51:10 +0000 | |
---|---|---|
committer | 2020-12-08 16:30:15 -0500 | |
commit | 542174d77deb7f2a59bcd0b8147144d4e123cf7b (patch) | |
tree | f99cc1e84d04fc1f574bf4e4d3afef903b01d3d1 | |
parent | Add fatal error for unnamed SVE variadic arguments (diff) | |
download | llvm-project-542174d77deb7f2a59bcd0b8147144d4e123cf7b.tar.gz llvm-project-542174d77deb7f2a59bcd0b8147144d4e123cf7b.tar.bz2 llvm-project-542174d77deb7f2a59bcd0b8147144d4e123cf7b.zip |
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.h | 6 | ||||
-rw-r--r-- | llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 15 | ||||
-rw-r--r-- | llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp | 30 | ||||
-rw-r--r-- | llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp | 8 | ||||
-rw-r--r-- | llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h | 4 | ||||
-rw-r--r-- | llvm/test/CodeGen/AArch64/variant-pcs.ll | 51 | ||||
-rw-r--r-- | llvm/test/MC/AArch64/directive-variant_pcs-err.s | 17 | ||||
-rw-r--r-- | llvm/test/MC/AArch64/directive-variant_pcs.s | 11 |
8 files changed, 142 insertions, 0 deletions
diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h index bdcf10fd1640..21a5c26883cd 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 3a94820dac8d..7ec7ffe309f7 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 0ac09c4f96f0..e72ae0e62cb7 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 fe4c34be1519..6dfda8217628 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 3a0c5d8318dd..1af978a806d1 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 000000000000..f6e5fd13f1ed --- /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 000000000000..98cf703b564e --- /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 000000000000..f6f9c9c272f7 --- /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) |