diff --git a/llvm/include/llvm/BinaryFormat/DynamicTags.def b/llvm/include/llvm/BinaryFormat/DynamicTags.def --- a/llvm/include/llvm/BinaryFormat/DynamicTags.def +++ b/llvm/include/llvm/BinaryFormat/DynamicTags.def @@ -31,6 +31,11 @@ #define PPC64_DYNAMIC_TAG_DEFINED #endif +#ifndef RISCV_DYNAMIC_TAG +#define RISCV_DYNAMIC_TAG(name, value) DYNAMIC_TAG(name, value) +#define RISCV_DYNAMIC_TAG_DEFINED +#endif + #ifndef DYNAMIC_TAG_MARKER #define DYNAMIC_TAG_MARKER(name, value) DYNAMIC_TAG(name, value) #define DYNAMIC_TAG_MARKER_DEFINED @@ -213,6 +218,9 @@ PPC64_DYNAMIC_TAG(PPC64_GLINK, 0x70000000) // Address of 32 bytes before the // first glink lazy resolver stub. +// RISC-V specific dynamic table entries. +RISCV_DYNAMIC_TAG(RISCV_VARIANT_CC, 0x70000001) + // Sun machine-independent extensions. DYNAMIC_TAG(AUXILIARY, 0x7FFFFFFD) // Shared object to load before self DYNAMIC_TAG(USED, 0x7FFFFFFE) // Same as DT_NEEDED @@ -243,3 +251,7 @@ #undef PPC64_DYNAMIC_TAG #undef PPC64_DYNAMIC_TAG_DEFINED #endif +#ifdef RISCV_DYNAMIC_TAG_DEFINED +#undef RISCV_DYNAMIC_TAG +#undef RISCV_DYNAMIC_TAG_DEFINED +#endif diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h --- a/llvm/include/llvm/BinaryFormat/ELF.h +++ b/llvm/include/llvm/BinaryFormat/ELF.h @@ -642,6 +642,13 @@ #include "ELFRelocs/Lanai.def" }; +// Special values for the st_other field in the symbol table entry for RISC-V. +enum { + // Symbol may follow different calling convention than standard calling + // conventions. + STO_RISCV_VARIANT_CC = 0x80 +}; + // RISCV Specific e_flags enum : unsigned { EF_RISCV_RVC = 0x0001, diff --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp --- a/llvm/lib/Object/ELF.cpp +++ b/llvm/lib/Object/ELF.cpp @@ -481,6 +481,14 @@ #undef PPC64_DYNAMIC_TAG } break; + + case ELF::EM_RISCV: + switch (Type) { +#define RISCV_DYNAMIC_TAG(name, value) DYNAMIC_STRINGIFY_ENUM(name, value) +#include "llvm/BinaryFormat/DynamicTags.def" +#undef RISCV_DYNAMIC_TAG + } + break; } #undef DYNAMIC_TAG switch (Type) { @@ -489,6 +497,7 @@ #define MIPS_DYNAMIC_TAG(name, value) #define HEXAGON_DYNAMIC_TAG(name, value) #define PPC64_DYNAMIC_TAG(name, value) +#define RISCV_DYNAMIC_TAG(name, value) // Also ignore marker tags such as DT_HIOS (maps to DT_VERNEEDNUM), etc. #define DYNAMIC_TAG_MARKER(name, value) #define DYNAMIC_TAG(name, value) case value: return #name; @@ -498,6 +507,7 @@ #undef MIPS_DYNAMIC_TAG #undef HEXAGON_DYNAMIC_TAG #undef PPC64_DYNAMIC_TAG +#undef RISCV_DYNAMIC_TAG #undef DYNAMIC_TAG_MARKER #undef DYNAMIC_STRINGIFY_ENUM default: diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp --- a/llvm/lib/ObjectYAML/ELFYAML.cpp +++ b/llvm/lib/ObjectYAML/ELFYAML.cpp @@ -843,6 +843,7 @@ #define HEXAGON_DYNAMIC_TAG(name, value) #define PPC_DYNAMIC_TAG(name, value) #define PPC64_DYNAMIC_TAG(name, value) +#define RISCV_DYNAMIC_TAG(name, value) // Ignore marker tags such as DT_HIOS (maps to DT_VERNEEDNUM), etc. #define DYNAMIC_TAG_MARKER(name, value) @@ -884,6 +885,13 @@ #undef PPC64_DYNAMIC_TAG #define PPC64_DYNAMIC_TAG(name, value) break; + case ELF::EM_RISCV: +#undef RISCV_DYNAMIC_TAG +#define RISCV_DYNAMIC_TAG(name, value) DYNAMIC_TAG(name, value) +#include "llvm/BinaryFormat/DynamicTags.def" +#undef RISCV_DYNAMIC_TAG +#define RISCV_DYNAMIC_TAG(name, value) + break; default: #include "llvm/BinaryFormat/DynamicTags.def" break; @@ -893,6 +901,7 @@ #undef HEXAGON_DYNAMIC_TAG #undef PPC_DYNAMIC_TAG #undef PPC64_DYNAMIC_TAG +#undef RISCV_DYNAMIC_TAG #undef DYNAMIC_TAG_MARKER #undef STRINGIFY #undef DYNAMIC_TAG @@ -1161,6 +1170,10 @@ if (EMachine == ELF::EM_AARCH64) Map["STO_AARCH64_VARIANT_PCS"] = ELF::STO_AARCH64_VARIANT_PCS; + + if (EMachine == ELF::EM_RISCV) + Map["STO_RISCV_VARIANT_CC"] = ELF::STO_RISCV_VARIANT_CC; + return Map; } diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp --- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -169,6 +169,7 @@ bool parseDirectiveOption(); bool parseDirectiveAttribute(); + bool parseDirectiveVariantCC(); void setFeatureBits(uint64_t Feature, StringRef FeatureString) { if (!(getSTI().getFeatureBits()[Feature])) { @@ -1837,6 +1838,8 @@ return parseDirectiveOption(); else if (IDVal == ".attribute") return parseDirectiveAttribute(); + else if (IDVal == ".variant_cc") + return parseDirectiveVariantCC(); return true; } @@ -2200,6 +2203,32 @@ return false; } +/// parseDirectiveVariantCC +/// ::= .variant_cc symbol +bool RISCVAsmParser::parseDirectiveVariantCC() { + 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_cc' directive"); + + Parser.Lex(); // Eat the symbol + + // Shouldn't be any more tokens + if (parseToken(AsmToken::EndOfStatement)) + return addErrorSuffix(" in '.variant_cc' directive"); + + getTargetStreamer().emitDirectiveVariantCC(Sym); + + return false; +} + void RISCVAsmParser::emitToStreamer(MCStreamer &S, const MCInst &Inst) { MCInst CInst; bool Res = compressInst(CInst, Inst, getSTI(), S.getContext()); diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h @@ -103,6 +103,7 @@ void emitDirectiveOptionNoRVC() override; void emitDirectiveOptionRelax() override; void emitDirectiveOptionNoRelax() override; + void emitDirectiveVariantCC(MCSymbol *Symbol) override; }; } #endif diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp @@ -167,3 +167,7 @@ } return Result; } + +void RISCVTargetELFStreamer::emitDirectiveVariantCC(MCSymbol *Symbol) { + cast(Symbol)->setOther(ELF::STO_RISCV_VARIANT_CC); +} diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h @@ -29,6 +29,8 @@ virtual void emitDirectiveOptionNoRVC(); virtual void emitDirectiveOptionRelax(); virtual void emitDirectiveOptionNoRelax(); + /// Callback used to implement the .variant_cc directive. + virtual void emitDirectiveVariantCC(MCSymbol *Symbol); virtual void emitAttribute(unsigned Attribute, unsigned Value); virtual void finishAttributeSection(); virtual void emitTextAttribute(unsigned Attribute, StringRef String); @@ -59,6 +61,7 @@ void emitDirectiveOptionNoRVC() override; void emitDirectiveOptionRelax() override; void emitDirectiveOptionNoRelax() override; + void emitDirectiveVariantCC(MCSymbol *Symbol) override; }; } diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp @@ -29,6 +29,7 @@ void RISCVTargetStreamer::emitDirectiveOptionNoRVC() {} void RISCVTargetStreamer::emitDirectiveOptionRelax() {} void RISCVTargetStreamer::emitDirectiveOptionNoRelax() {} +void RISCVTargetStreamer::emitDirectiveVariantCC(MCSymbol *Symbol) {} void RISCVTargetStreamer::emitAttribute(unsigned Attribute, unsigned Value) {} void RISCVTargetStreamer::finishAttributeSection() {} void RISCVTargetStreamer::emitTextAttribute(unsigned Attribute, @@ -133,6 +134,10 @@ OS << "\t.option\tnorelax\n"; } +void RISCVTargetAsmStreamer::emitDirectiveVariantCC(MCSymbol *Symbol) { + OS << "\t.variant_cc\t" << Symbol->getName() << "\n"; +} + void RISCVTargetAsmStreamer::emitAttribute(unsigned Attribute, unsigned Value) { OS << "\t.attribute\t" << Attribute << ", " << Twine(Value) << "\n"; } diff --git a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp --- a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp +++ b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp @@ -15,6 +15,7 @@ #include "MCTargetDesc/RISCVMCExpr.h" #include "MCTargetDesc/RISCVTargetStreamer.h" #include "RISCV.h" +#include "RISCVMachineFunctionInfo.h" #include "RISCVTargetMachine.h" #include "TargetInfo/RISCVTargetInfo.h" #include "llvm/ADT/Statistic.h" @@ -68,6 +69,8 @@ void emitStartOfAsmFile(Module &M) override; void emitEndOfAsmFile(Module &M) override; + void emitFunctionEntryLabel() override; + private: void emitAttributes(); }; @@ -196,6 +199,18 @@ RTS.emitTargetAttributes(*STI); } +void RISCVAsmPrinter::emitFunctionEntryLabel() { + const RISCVMachineFunctionInfo *RVFI = + MF->getInfo(); + if (RVFI->isVectorCall()) { + RISCVTargetStreamer &RTS = + static_cast(*OutStreamer->getTargetStreamer()); + RTS.emitDirectiveVariantCC(CurrentFnSym); + } + + return AsmPrinter::emitFunctionEntryLabel(); +} + // Force static initialization. extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVAsmPrinter() { RegisterAsmPrinter X(getTheRISCV32Target()); diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -7173,6 +7173,7 @@ else analyzeInputArgs(MF, CCInfo, Ins, /*IsRet=*/false); + bool IsVectorCall = false; for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { CCValAssign &VA = ArgLocs[i]; SDValue ArgValue; @@ -7185,6 +7186,10 @@ else ArgValue = unpackFromMemLoc(DAG, Chain, VA, DL); + // Check the argument is using vector registers or not. + if (!IsVectorCall && VA.getLocVT().isScalableVector()) + IsVectorCall = true; + if (VA.getLocInfo() == CCValAssign::Indirect) { // If the original argument was split and passed by reference (e.g. i128 // on RV32), we need to load all parts of it here (using the same @@ -7212,6 +7217,11 @@ InVals.push_back(ArgValue); } + if (IsVectorCall) { + RISCVMachineFunctionInfo *RVFI = MF.getInfo(); + RVFI->setIsVectorCall(); + } + if (IsVarArg) { ArrayRef ArgRegs = makeArrayRef(ArgGPRs); unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs); @@ -7685,7 +7695,7 @@ const SmallVectorImpl &Outs, const SmallVectorImpl &OutVals, const SDLoc &DL, SelectionDAG &DAG) const { - const MachineFunction &MF = DAG.getMachineFunction(); + MachineFunction &MF = DAG.getMachineFunction(); const RISCVSubtarget &STI = MF.getSubtarget(); // Stores the assignment of the return value to a location. @@ -7703,6 +7713,7 @@ SDValue Glue; SmallVector RetOps(1, Chain); + bool IsVectorCall = false; // Copy the result values into the output registers. for (unsigned i = 0, e = RVLocs.size(); i < e; ++i) { @@ -7734,6 +7745,10 @@ Glue = Chain.getValue(1); RetOps.push_back(DAG.getRegister(RegHi, MVT::i32)); } else { + // Check the return value is using vector registers or not. + if (!IsVectorCall && VA.getLocVT().isScalableVector()) + IsVectorCall = true; + // Handle a 'normal' return. Val = convertValVTToLocVT(DAG, Val, VA, DL, Subtarget); Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), Val, Glue); @@ -7749,6 +7764,11 @@ } } + if (IsVectorCall) { + RISCVMachineFunctionInfo *RVFI = MF.getInfo(); + RVFI->setIsVectorCall(); + } + RetOps[0] = Chain; // Update chain. // Add the glue node if we have it. diff --git a/llvm/lib/Target/RISCV/RISCVMachineFunctionInfo.h b/llvm/lib/Target/RISCV/RISCVMachineFunctionInfo.h --- a/llvm/lib/Target/RISCV/RISCVMachineFunctionInfo.h +++ b/llvm/lib/Target/RISCV/RISCVMachineFunctionInfo.h @@ -38,6 +38,8 @@ uint64_t RVVPadding = 0; /// Size of stack frame to save callee saved registers unsigned CalleeSavedStackSize = 0; + /// Is there any vector argument or return? + bool IsVectorCall = false; public: RISCVMachineFunctionInfo(const MachineFunction &MF) {} @@ -74,6 +76,9 @@ unsigned getCalleeSavedStackSize() const { return CalleeSavedStackSize; } void setCalleeSavedStackSize(unsigned Size) { CalleeSavedStackSize = Size; } + + bool isVectorCall() const { return IsVectorCall; } + void setIsVectorCall() { IsVectorCall = true; } }; } // end namespace llvm diff --git a/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-variant-cc.ll b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-variant-cc.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-variant-cc.ll @@ -0,0 +1,44 @@ +; RUN: llc -mtriple=riscv64 -mattr=+experimental-v -riscv-v-vector-bits-min=128 -o - %s \ +; RUN: | FileCheck %s --check-prefix=CHECK-ASM +; RUN: llc -mtriple=riscv64 -mattr=+experimental-v -riscv-v-vector-bits-min=128 -filetype=obj -o - %s \ +; RUN: | llvm-readobj --symbols - | FileCheck %s --check-prefix=CHECK-OBJ + +define i32 @base_cc() { +; CHECK-ASM-LABEL: base_cc: +; CHECK-ASM-NOT: .variant_cc +; CHECK-OBJ-LABEL: Name: base_cc +; CHECK-OBJ: Other: 0 + ret i32 42 +} + +define <4 x i32> @fixed_vector_vector_cc_1() { +; CHECK-ASM: .variant_cc fixed_vector_vector_cc_1 +; CHECK-ASM-NEXT: fixed_vector_vector_cc_1: +; CHECK-OBJ-LABEL: Name: fixed_vector_vector_cc_1 +; CHECK-OBJ: Other [ (0x80) + ret <4 x i32> undef +} + +define <4 x i1> @fixed_vector_vector_cc_2() { +; CHECK-ASM: .variant_cc fixed_vector_vector_cc_2 +; CHECK-ASM-NEXT: fixed_vector_vector_cc_2: +; CHECK-OBJ-LABEL: Name: fixed_vector_vector_cc_2 +; CHECK-OBJ: Other [ (0x80) + ret <4 x i1> undef +} + +define void @fixed_vector_vector_cc_3(<4 x i32> %arg) { +; CHECK-ASM: .variant_cc fixed_vector_vector_cc_3 +; CHECK-ASM-NEXT: fixed_vector_vector_cc_3: +; CHECK-OBJ-LABEL: Name: fixed_vector_vector_cc_3 +; CHECK-OBJ: Other [ (0x80) + ret void +} + +define void @fixed_vector_vector_cc_4(<4 x i1> %arg) { +; CHECK-ASM: .variant_cc fixed_vector_vector_cc_4 +; CHECK-ASM-NEXT: fixed_vector_vector_cc_4: +; CHECK-OBJ-LABEL: Name: fixed_vector_vector_cc_4 +; CHECK-OBJ: Other [ (0x80) + ret void +} diff --git a/llvm/test/CodeGen/RISCV/rvv/variant-cc.ll b/llvm/test/CodeGen/RISCV/rvv/variant-cc.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/rvv/variant-cc.ll @@ -0,0 +1,51 @@ +; RUN: llc -mtriple=riscv64 -mattr=+experimental-v -o - %s | FileCheck %s --check-prefix=CHECK-ASM +; RUN: llc -mtriple=riscv64 -mattr=+experimental-v -filetype=obj -o - %s \ +; RUN: | llvm-readobj --symbols - | FileCheck %s --check-prefix=CHECK-OBJ + +define i32 @base_cc() { +; CHECK-ASM-LABEL: base_cc: +; CHECK-ASM-NOT: .variant_cc +; CHECK-OBJ-LABEL: Name: base_cc +; CHECK-OBJ: Other: 0 + ret i32 42 +} + +define <4 x i32> @fixed_vector_cc_1(<4 x i32> %arg) { +; CHECK-ASM-LABEL: fixed_vector_cc_1: +; CHECK-ASM-NOT: .variant_cc +; CHECK-OBJ-LABEL: Name: fixed_vector_cc_1 +; CHECK-OBJ: Other: 0 + ret <4 x i32> %arg +} + +define @rvv_vector_cc_1() { +; CHECK-ASM: .variant_cc rvv_vector_cc_1 +; CHECK-ASM-NEXT: rvv_vector_cc_1: +; CHECK-OBJ-LABEL: Name: rvv_vector_cc_1 +; CHECK-OBJ: Other [ (0x80) + ret undef +} + +define @rvv_vector_cc_2() { +; CHECK-ASM: .variant_cc rvv_vector_cc_2 +; CHECK-ASM-NEXT: rvv_vector_cc_2: +; CHECK-OBJ-LABEL: Name: rvv_vector_cc_2 +; CHECK-OBJ: Other [ (0x80) + ret undef +} + +define void @rvv_vector_cc_3( %arg) { +; CHECK-ASM: .variant_cc rvv_vector_cc_3 +; CHECK-ASM-NEXT: rvv_vector_cc_3: +; CHECK-OBJ-LABEL: Name: rvv_vector_cc_3 +; CHECK-OBJ: Other [ (0x80) + ret void +} + +define void @rvv_vector_cc_4( %arg) { +; CHECK-ASM: .variant_cc rvv_vector_cc_4 +; CHECK-ASM-NEXT: rvv_vector_cc_4: +; CHECK-OBJ-LABEL: Name: rvv_vector_cc_4 +; CHECK-OBJ: Other [ (0x80) + ret void +} diff --git a/llvm/test/MC/RISCV/directive-variant_cc-err.s b/llvm/test/MC/RISCV/directive-variant_cc-err.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/directive-variant_cc-err.s @@ -0,0 +1,17 @@ +// RUN: not llvm-mc -triple riscv64 -filetype asm -o - %s 2>&1 | FileCheck %s + +.variant_cc +// CHECK: error: expected symbol name +// CHECK-NEXT: .variant_cc +// CHECK-NEXT: ^ + +.variant_cc foo +// CHECK: error: unknown symbol in '.variant_cc' directive +// CHECK-NEXT: .variant_cc foo +// CHECK-NEXT: ^ + +.global foo +.variant_cc foo bar +// CHECK: error: unexpected token in '.variant_cc' directive +// CHECK-NEXT: .variant_cc foo bar +// CHECK-NEXT: ^ diff --git a/llvm/test/MC/RISCV/directive-variant_cc.s b/llvm/test/MC/RISCV/directive-variant_cc.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/directive-variant_cc.s @@ -0,0 +1,11 @@ +// RUN: llvm-mc -triple riscv64 -filetype asm -o - %s | FileCheck %s +// RUN: llvm-mc -triple riscv64 -filetype obj -o - %s \ +// RUN: | llvm-readobj --symbols - | FileCheck %s --check-prefix=CHECK-ST_OTHER + +.text +.global foo +.variant_cc foo +// CHECK: .variant_cc foo + +// CHECK-ST_OTHER: Name: foo +// CHECK-ST_OTHER: Other [ (0x80) diff --git a/llvm/test/tools/llvm-readobj/ELF/dynamic-tags-machine-specific.test b/llvm/test/tools/llvm-readobj/ELF/dynamic-tags-machine-specific.test --- a/llvm/test/tools/llvm-readobj/ELF/dynamic-tags-machine-specific.test +++ b/llvm/test/tools/llvm-readobj/ELF/dynamic-tags-machine-specific.test @@ -391,3 +391,41 @@ - Type: PT_DYNAMIC FirstSec: .dynamic LastSec: .dynamic + +## Case 6: Test that RISC-V machine-specific tags can be dumped. +# RUN: yaml2obj --docnum=6 %s -o %t.riscv +# RUN: llvm-readobj --dynamic-table %t.riscv | FileCheck %s --check-prefix=LLVM-RISCV +# RUN: llvm-readelf --dynamic-table %t.riscv | FileCheck %s --check-prefix=GNU-RISCV + +# LLVM-RISCV: DynamicSection [ (2 entries) +# LLVM-RISCV-NEXT: Tag Type Name/Value +# LLVM-RISCV-NEXT: 0x0000000070000001 RISCV_VARIANT_CC 1 +# LLVM-RISCV-NEXT: 0x0000000000000000 NULL 0x0 +# LLVM-RISCV-NEXT:] + +# GNU-RISCV: Dynamic section at offset {{.*}} contains 2 entries: +# GNU-RISCV-NEXT: Tag Type Name/Value +# GNU-RISCV-NEXT: 0x0000000070000001 (RISCV_VARIANT_CC) 1 +# GNU-RISCV-NEXT: 0x0000000000000000 (NULL) 0x0 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_RISCV +Sections: + - Name: .dynamic + Type: SHT_DYNAMIC + Entries: + - Tag: DT_RISCV_VARIANT_CC + Value: 1 + - Tag: DT_NULL + Value: 0 +ProgramHeaders: + - Type: PT_LOAD + FirstSec: .dynamic + LastSec: .dynamic + - Type: PT_DYNAMIC + FirstSec: .dynamic + LastSec: .dynamic diff --git a/llvm/test/tools/llvm-readobj/ELF/riscv-symbols-stother.test b/llvm/test/tools/llvm-readobj/ELF/riscv-symbols-stother.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/ELF/riscv-symbols-stother.test @@ -0,0 +1,23 @@ +## Check that we are able to dump RISC-V STO_* flags correctly when dumping symbols. + +# RUN: yaml2obj %s -o %t.o +# RUN: llvm-readobj --symbols %t.o | FileCheck %s --check-prefix=LLVM +# RUN: llvm-readelf --symbols %t.o | FileCheck %s --check-prefix=GNU + +# LLVM: Name: foo1 +# LLVM: Other [ (0x80) +# LLVM-NEXT: STO_RISCV_VARIANT_CC (0x80) +# LLVM-NEXT: ] + +# GNU: Symbol table '.symtab' contains 2 entries: +# GNU: 1: 0000000000000000 0 NOTYPE LOCAL DEFAULT [VARIANT_CC] UND foo1 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_RISCV +Symbols: + - Name: foo1 + Other: [ STO_RISCV_VARIANT_CC ] diff --git a/llvm/test/tools/obj2yaml/ELF/riscv-sym-other.yaml b/llvm/test/tools/obj2yaml/ELF/riscv-sym-other.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/tools/obj2yaml/ELF/riscv-sym-other.yaml @@ -0,0 +1,18 @@ +## Check RISC-V st_other extension support. + +# RUN: yaml2obj %s -o %t +# RUN: obj2yaml %t | FileCheck %s + +# CHECK: Symbols: +# CHECK: - Name: foo1 +# CHECK: Other: [ STO_RISCV_VARIANT_CC ] + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_RISCV +Symbols: + - Name: foo1 + Other: [ STO_RISCV_VARIANT_CC ] diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -1601,6 +1601,9 @@ LLVM_READOBJ_ENUM_ENT(ELF, STO_MIPS_MIPS16) }; +static const EnumEntry ElfRISCVSymOtherFlags[] = { + LLVM_READOBJ_ENUM_ENT(ELF, STO_RISCV_VARIANT_CC)}; + static const char *getElfMipsOptionsOdkType(unsigned Odk) { switch (Odk) { LLVM_READOBJ_ENUM_CASE(ELF, ODK_NULL); @@ -2239,6 +2242,14 @@ break; } break; + case EM_RISCV: + switch (Type) { + case DT_RISCV_VARIANT_CC: + return std::to_string(Value); + default: + break; + } + break; default: break; } @@ -3754,6 +3765,19 @@ Fields[5].Str.append(" | " + to_hexString(Other, false)); Fields[5].Str.append("]"); } + } else if (this->Obj.getHeader().e_machine == ELF::EM_RISCV) { + uint8_t Other = Symbol.st_other & ~0x3; + Fields[5].Str += " ["; + if (Other & STO_RISCV_VARIANT_CC) { + Other &= ~STO_RISCV_VARIANT_CC; + Fields[5].Str += "VARIANT_CC"; + if (Other != 0) + Fields[5].Str += " | "; + } + // If there is any unrecognized bit, print the value directly. + if (Other) + Fields[5].Str += to_hexString(Other, false); + Fields[5].Str += "]"; } else { Fields[5].Str += " []"; @@ -6514,6 +6538,10 @@ SymOtherFlags.insert(SymOtherFlags.end(), std::begin(ElfAArch64SymOtherFlags), std::end(ElfAArch64SymOtherFlags)); + } else if (this->Obj.getHeader().e_machine == EM_RISCV) { + SymOtherFlags.insert(SymOtherFlags.end(), + std::begin(ElfRISCVSymOtherFlags), + std::end(ElfRISCVSymOtherFlags)); } W.printFlags("Other", Symbol.st_other, makeArrayRef(SymOtherFlags), 0x3u); }