diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -63,6 +63,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MD5.h" #include "llvm/Support/TimeProfiler.h" +#include "llvm/Support/RISCVISAInfo.h" using namespace clang; using namespace CodeGen; @@ -625,13 +626,6 @@ getModule().addModuleFlag(llvm::Module::Error, "min_enum_size", EnumWidth); } - if (Arch == llvm::Triple::riscv32 || Arch == llvm::Triple::riscv64) { - StringRef ABIStr = Target.getABI(); - llvm::LLVMContext &Ctx = TheModule.getContext(); - getModule().addModuleFlag(llvm::Module::Error, "target-abi", - llvm::MDString::get(Ctx, ABIStr)); - } - if (CodeGenOpts.SanitizeCfiCrossDso) { // Indicate that we want cross-DSO control flow integrity checks. getModule().addModuleFlag(llvm::Module::Override, "Cross-DSO CFI", 1); @@ -829,11 +823,28 @@ default: break; case llvm::Triple::riscv32: - case llvm::Triple::riscv64: + case llvm::Triple::riscv64: { getModule().addModuleFlag(llvm::Module::Error, "SmallDataLimit", CodeGenOpts.SmallDataLimit); + StringRef ABIStr = Target.getABI(); + llvm::LLVMContext &Ctx = TheModule.getContext(); + getModule().addModuleFlag(llvm::Module::Error, "target-abi", + llvm::MDString::get(Ctx, ABIStr)); + std::vector Features(getTarget().getTargetOpts().Features); + llvm::RISCVISAInfo::filterISAStrings(Features); + std::vector Ops; + if (Features.empty()) { + Ops.push_back(llvm::MDString::get(Ctx, "")); + } else { + for (auto &ISAFeature : Features) { + Ops.push_back(llvm::MDString::get(Ctx, ISAFeature)); + } + } + getModule().addModuleFlag(llvm::Module::AppendUnique, "riscv-isa-features", + llvm::MDNode::get(Ctx, Ops)); break; } + } } void CodeGenModule::UpdateCompletedType(const TagDecl *TD) { diff --git a/clang/test/CodeGen/RISCV/riscv-metadata-isa-features-empty-target-feature.cpp b/clang/test/CodeGen/RISCV/riscv-metadata-isa-features-empty-target-feature.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/RISCV/riscv-metadata-isa-features-empty-target-feature.cpp @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -triple riscv64 -target-feature +f -target-feature +d -emit-llvm -o - %s | FileCheck %s + +// CHECK: attributes #0 = {{[{].*}} "target-features"="+64bit,+d,+f" {{.*[}]}} +// CHECK: attributes #1 = {{[{].*}} "target-features"="+64bit,+d,+f" {{.*[}]}} +// CHECK: attributes #2 = {{[{].*}} "target-features"="+64bit,+d,+f" {{.*[}]}} +// CHECK: attributes #3 = {{[{].*}} nounwind {{.*[}]}} + +// We need to record extension target-feature in riscv-isa-features module flag metadata because there is some empty target-features attribute +// CHECK: !{{[0-9]+}} = !{i32 6, !"riscv-isa-features", !{{[0-9]+}}} +// CHECK: !{{[0-9]+}} = !{!"+d", !"+f"} + +struct A { + A() {} +}; + +void test() noexcept { + A a; +} + +int main() { + test(); + return 0; +} diff --git a/clang/test/CodeGen/RISCV/riscv-metadata-isa-features-ifunc.c b/clang/test/CodeGen/RISCV/riscv-metadata-isa-features-ifunc.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/RISCV/riscv-metadata-isa-features-ifunc.c @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -triple riscv64 -target-abi lp64 -emit-llvm -o - %s | FileCheck %s + +// CHECK: attributes #0 = {{[{].*}} "target-features"="+64bit" {{.*[}]}} +// CHECK: attributes #1 = {{[{].*}} "target-features"="+64bit,+m" {{.*[}]}} + +// Record extension target-feature in riscv-isa-features module flag metadata for IFUNC case. +// CHECK: !{{[0-9]+}} = !{i32 6, !"riscv-isa-features", !{{[0-9]+}}} +// CHECK: !{{[0-9]+}} = !{!""} + +static int __attribute__((target("m"))) +mul_m(int x, int y) { + return x * y; +} + +static int mul_i(int x, int y) { + return x * y; +} + +static int (*foo_resolver(unsigned long hwcap))(int, int) { + if (hwcap & (1 << ('M' - 'A'))) + return mul_m; + else + return mul_i; +} + +int __attribute__((ifunc("foo_resolver"))) +foo(int, int); diff --git a/clang/test/CodeGen/RISCV/riscv-metadata-isa-features.c b/clang/test/CodeGen/RISCV/riscv-metadata-isa-features.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/RISCV/riscv-metadata-isa-features.c @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -triple riscv32 -emit-llvm -o - %s | FileCheck -check-prefix=BASE-ISA %s +// RUN: %clang_cc1 -triple riscv32 -target-feature +d -emit-llvm -o - %s | FileCheck -check-prefix=RV32D-ISA %s +// RUN: %clang_cc1 -triple riscv32 -emit-llvm -target-feature +f -target-feature +d -o - %s | FileCheck -check-prefix=RV32FD-ISA %s +// RUN: %clang_cc1 -triple riscv64 -emit-llvm -o - %s | FileCheck -check-prefix=BASE-ISA %s +// RUN: %clang_cc1 -triple riscv64 -target-feature +d -target-abi lp64d -emit-llvm -o - %s | FileCheck -check-prefix=RV64D-ISA %s +// RUN: %clang_cc1 -triple riscv64 -target-feature +f -target-feature +d -emit-llvm -o - %s | FileCheck -check-prefix=RV64FD-ISA %s +// RUN: %clang_cc1 -triple riscv32 -emit-llvm -target-feature +f -target-feature +d -target-feature +experimental-v -target-feature +experimental-zfh -o - %s | FileCheck -check-prefix=RV32FDVZFH-ISA %s + +// RUN: %clang_cc1 -triple riscv32 -emit-llvm -target-feature +f -target-feature +d -target-feature +relax -target-feature -save-restore -o - %s | FileCheck -check-prefix=RV32FD-ISA %s + +// Test expected ISA result when giving conflicted -target-feautre +// RUN: %clang_cc1 -triple riscv32 -emit-llvm -target-feature +d -target-feature -d -o - %s | FileCheck -check-prefix=RV32-NEG-D %s +// RUN: %clang_cc1 -triple riscv32 -emit-llvm -target-feature -d -target-feature +d -o - %s | FileCheck -check-prefix=RV32D-ISA %s + +// BASE-ISA: !{{[0-9]+}} = !{!""} +// RV32D-ISA: !{{[0-9]+}} = !{!"+d"} +// RV32FD-ISA: !{{[0-9]+}} = !{!"+d", !"+f"} +// RV32FDVZFH-ISA: !{{[0-9]+}} = !{!"+d", !"+experimental-v", !"+experimental-zfh", !"+f"} +// RV64D-ISA: !{{[0-9]+}} = !{!"+d"} +// RV64FD-ISA: !{{[0-9]+}} = !{!"+d", !"+f"} +// RV32-NEG-D: !{{[0-9]+}} = !{!"-d"} diff --git a/llvm/include/llvm/Support/RISCVISAInfo.h b/llvm/include/llvm/Support/RISCVISAInfo.h --- a/llvm/include/llvm/Support/RISCVISAInfo.h +++ b/llvm/include/llvm/Support/RISCVISAInfo.h @@ -61,6 +61,7 @@ bool hasExtension(StringRef Ext) const; std::string toString() const; + static void filterISAStrings(std::vector &Features); static bool isSupportedExtension(StringRef Ext, bool CheckExperimental); static bool isSupportedExtension(StringRef Ext, unsigned MajorVersion, unsigned MinorVersion, diff --git a/llvm/lib/Support/RISCVISAInfo.cpp b/llvm/lib/Support/RISCVISAInfo.cpp --- a/llvm/lib/Support/RISCVISAInfo.cpp +++ b/llvm/lib/Support/RISCVISAInfo.cpp @@ -129,6 +129,18 @@ return None; } +void RISCVISAInfo::filterISAStrings(std::vector &Features) { + erase_if(Features, [](std::string &Feature) { + StringRef ExtName(Feature); + assert(ExtName.size() > 1 && (ExtName[0] == '+' || ExtName[0] == '-')); + ExtName = ExtName.drop_front(1); // Drop '+' + stripExperimentalPrefix(ExtName); + if (filterSupportedExtensionInfosByName(ExtName).empty()) + return true; + return false; + }); +} + bool RISCVISAInfo::isSupportedExtension(StringRef Ext, bool CheckExperimental) { bool IsExperimental = false; if (CheckExperimental) 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 @@ -11,6 +11,7 @@ #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/RISCVISAInfo.h" namespace llvm { @@ -36,6 +37,7 @@ StringRef StringValue); void emitTargetAttributes(const MCSubtargetInfo &STI); + void emitTargetAttributes(const RISCVISAInfo &ISAInfo); }; // This part is for ascii assembly output 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 @@ -49,9 +49,15 @@ unsigned XLen = STI.hasFeature(RISCV::Feature64Bit) ? 64 : 32; std::vector FeatureVector; RISCVFeatures::toFeatureVector(FeatureVector, STI.getFeatureBits()); - ISAInfo.parse(XLen, FeatureVector); + emitTargetAttributes(ISAInfo); +} +void RISCVTargetStreamer::emitTargetAttributes(const RISCVISAInfo &ISAInfo) { + if (ISAInfo.hasExtension("e")) + emitAttribute(RISCVAttrs::STACK_ALIGN, RISCVAttrs::ALIGN_4); + else + emitAttribute(RISCVAttrs::STACK_ALIGN, RISCVAttrs::ALIGN_16); emitTextAttribute(RISCVAttrs::ARCH, ISAInfo.toString()); } 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 @@ -27,6 +27,7 @@ #include "llvm/MC/MCInst.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/Support/RISCVISAInfo.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -178,10 +179,27 @@ } void RISCVAsmPrinter::emitStartOfAsmFile(Module &M) { - if (TM.getTargetTriple().isOSBinFormatELF()) - emitAttributes(); + if (TM.getTargetTriple().isOSBinFormatELF()) { + RISCVTargetStreamer &RTS = + static_cast(*OutStreamer->getTargetStreamer()); + const auto *ISAFeatureNodes = + dyn_cast_or_null(M.getModuleFlag("riscv-isa-features")); + if (STI->getFeatureString().empty() && ISAFeatureNodes) { + std::vector Features; + for (const MDOperand &Feature : ISAFeatureNodes->operands()) { + auto MAttr = cast(Feature.get())->getString(); + Features.push_back(MAttr.str()); + } + unsigned XLEN = + TM.getTargetTriple().getArch() == llvm::Triple::riscv32 ? 32 : 64; + RISCVISAInfo ISAInfo; + ISAInfo.parse(XLEN, Features); + RTS.emitTargetAttributes(ISAInfo); + } else { + RTS.emitTargetAttributes(*STI); + } + } } - void RISCVAsmPrinter::emitEndOfAsmFile(Module &M) { RISCVTargetStreamer &RTS = static_cast(*OutStreamer->getTargetStreamer()); diff --git a/llvm/test/CodeGen/RISCV/riscv-isa-features.ll b/llvm/test/CodeGen/RISCV/riscv-isa-features.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/riscv-isa-features.ll @@ -0,0 +1,35 @@ +; RUN: llc -o - < %s | FileCheck %s +; -mattr option would overwrite target-feature and module flag riscv-isa-features +; RUN: llc -o - -mattr=+f,+d < %s | FileCheck %s -check-prefix=ISA-F-D +; RUN: llc --filetype=obj -o - < %s | llvm-readelf -A - \ +; RUN: | FileCheck %s -check-prefix=OBJFILE + +; CHECK: .attribute 5, "rv64i2p0_m2p0_a2p0_c2p0" +; ISA-F-D: .attribute 5, "rv64i2p0_f2p0_d2p0" + +; OBJFILE: TagName: arch +; OBJFILE: Value: rv64i2p0_m2p0_a2p0_c2p0 + +target triple = "riscv64-unknown-linux-gnu" + +define float @foo0(i32 %a) nounwind #0 { +; CHECK: call __floatsisf@plt +; ISA-F-D: fcvt.s.w ft0, a0 + %conv = sitofp i32 %a to float + ret float %conv +} + +define float @foo1(i32 %a) nounwind #1 { +; CHECK: fcvt.s.w ft0, a0 +; ISA-F-D: fcvt.s.w ft0, a0 + %conv = sitofp i32 %a to float + ret float %conv +} + +attributes #0 = { "target-features"="+64bit,+a,+c,+m"} +attributes #1 = { "target-features"="+64bit,+a,+c,+d,+f,+m"} + +!llvm.module.flags = !{!0} + +!0 = !{i32 6, !"riscv-isa-features", !1} +!1 = !{!"+a", !"+c", !"+m"}