[llvm] c87bd2d - [AArch64] Implement .variant_pcs directive

Cullen Rhodes via llvm-commits llvm-commits at lists.llvm.org
Tue Oct 13 03:06:55 PDT 2020


Author: Cullen Rhodes
Date: 2020-10-13T10:06:27Z
New Revision: c87bd2d8eb378d152f2b6bde4cb088ad390a676c

URL: https://github.com/llvm/llvm-project/commit/c87bd2d8eb378d152f2b6bde4cb088ad390a676c
DIFF: https://github.com/llvm/llvm-project/commit/c87bd2d8eb378d152f2b6bde4cb088ad390a676c.diff

LOG: [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

Added: 
    llvm/test/CodeGen/AArch64/variant-pcs.ll
    llvm/test/MC/AArch64/directive-variant_pcs-err.s
    llvm/test/MC/AArch64/directive-variant_pcs.s

Modified: 
    llvm/include/llvm/BinaryFormat/ELF.h
    llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
    llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
    llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp
    llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h
index d800d16fdd3a..143810fce89a 100644
--- a/llvm/include/llvm/BinaryFormat/ELF.h
+++ b/llvm/include/llvm/BinaryFormat/ELF.h
@@ -406,6 +406,12 @@ enum {
 #include "ELFRelocs/AArch64.def"
 };
 
+// Special values for the st_other field in the symbol table entry for AArch64.
+enum {
+  // Symbol may follow 
diff erent 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 0904e1c40c81..5079494225eb 100644
--- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
+++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
@@ -89,6 +89,8 @@ class AArch64AsmPrinter : public AsmPrinter {
   void emitStartOfAsmFile(Module &M) override;
   void emitJumpTableInfo() override;
 
+  void emitFunctionEntryLabel() override;
+
   void LowerJumpTableDest(MCStreamer &OutStreamer, const MachineInstr &MI);
 
   void LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
@@ -787,6 +789,19 @@ void AArch64AsmPrinter::emitJumpTableInfo() {
   }
 }
 
+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 6cc841d37dba..ae95d54b2d90 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -184,6 +184,8 @@ class AArch64AsmParser : public MCTargetAsmParser {
   bool parseDirectiveCFINegateRAState();
   bool parseDirectiveCFIBKeyFrame();
 
+  bool parseDirectiveVariantPCS(SMLoc L);
+
   bool parseDirectiveSEHAllocStack(SMLoc L);
   bool parseDirectiveSEHPrologEnd(SMLoc L);
   bool parseDirectiveSEHSaveR19R20X(SMLoc L);
@@ -5171,6 +5173,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);
@@ -5650,6 +5654,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;
+}
+
 /// parseDirectiveSEHAllocStack
 /// ::= .seh_stackalloc
 bool AArch64AsmParser::parseDirectiveSEHAllocStack(SMLoc L) {

diff  --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFStreamer.cpp
index 3e0e9ba9f5f7..ec97e1c8b76a 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";
+  }
+
   void EmitARM64WinCFIAllocStack(unsigned Size) override {
     OS << "\t.seh_stackalloc " << Size << "\n";
   }
@@ -249,6 +253,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 09953315bbd0..73dc1e5d4d2a 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.h
@@ -39,6 +39,9 @@ class AArch64TargetStreamer : public MCTargetStreamer {
   /// 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 EmitARM64WinCFISaveR19R20X(int Offset) {}
   virtual void EmitARM64WinCFISaveFPLR(int Offset) {}
@@ -73,6 +76,7 @@ class AArch64TargetELFStreamer : public AArch64TargetStreamer {
   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)


        


More information about the llvm-commits mailing list