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 @@ -62,6 +62,7 @@ #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MD5.h" +#include "llvm/Support/RISCVISAInfo.h" #include "llvm/Support/TimeProfiler.h" using namespace clang; @@ -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,24 @@ 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; + unsigned XLEN = getTriple().getArch() == llvm::Triple::riscv32 ? 32 : 64; + llvm::RISCVISAInfo ISAInfo; + ISAInfo.parse(XLEN, Features); + getModule().addModuleFlag( + llvm::Module::OR, "riscv-isa-bits", + llvm::ConstantInt::get(llvm::IntegerType::get(Ctx, 256), + ISAInfo.toAPInt())); break; } + } } void CodeGenModule::UpdateCompletedType(const TagDecl *TD) { diff --git a/clang/lib/CodeGen/CodeGenTypeCache.h b/clang/lib/CodeGen/CodeGenTypeCache.h --- a/clang/lib/CodeGen/CodeGenTypeCache.h +++ b/clang/lib/CodeGen/CodeGenTypeCache.h @@ -33,7 +33,7 @@ /// void llvm::Type *VoidTy; - /// i8, i16, i32, and i64 + /// i8, i16, i32 and i64 llvm::IntegerType *Int8Ty, *Int16Ty, *Int32Ty, *Int64Ty; /// half, bfloat, float, double llvm::Type *HalfTy, *BFloatTy, *FloatTy, *DoubleTy; diff --git a/clang/test/CodeGen/RISCV/riscv-metadata-isa-bits-empty-target-feature.cpp b/clang/test/CodeGen/RISCV/riscv-metadata-isa-bits-empty-target-feature.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/RISCV/riscv-metadata-isa-bits-empty-target-feature.cpp @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -triple riscv64 -target-feature +f -emit-llvm -o - %s | FileCheck %s + +// CHECK: attributes #0 = {{[{].*}} "target-features"="+64bit,+f" {{.*[}]}} +// CHECK: attributes #1 = {{[{].*}} "target-features"="+64bit,+f" {{.*[}]}} +// CHECK: attributes #2 = {{[{].*}} "target-features"="+64bit,+f" {{.*[}]}} +// CHECK: attributes #3 = {{[{].*}} nounwind {{.*[}]}} + +// Encode isa string as riscv-isa-bits due to some empty target-features attribute +// CHECK: !{{[0-9]+}} = !{i32 8, !"riscv-isa-bits", i256 8} + +struct A { + A() {} +}; + +void test() noexcept { + A a; +} + +int main() { + test(); + return 0; +} diff --git a/clang/test/CodeGen/RISCV/riscv-metadata-isa-bits-ifunc.c b/clang/test/CodeGen/RISCV/riscv-metadata-isa-bits-ifunc.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/RISCV/riscv-metadata-isa-bits-ifunc.c @@ -0,0 +1,26 @@ +// 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" {{.*[}]}} + +// Encode isa string as riscv-isa-bits for i function case. +// CHECK: !{{[0-9]+}} = !{i32 8, !"riscv-isa-bits", i256 0} + +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-bits.c b/clang/test/CodeGen/RISCV/riscv-metadata-isa-bits.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/RISCV/riscv-metadata-isa-bits.c @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -triple riscv32 -emit-llvm -o - %s | FileCheck -check-prefix=RV32-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=RV64-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 + +// Test expected ISA result when giving many -target-feautre +// RUN: %clang_cc1 -triple riscv32 -emit-llvm -target-feature +f -target-feature -f -o - %s | FileCheck -check-prefix=RV32-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 + +// RV32-ISA: !{{[0-9]+}} = !{i32 8, !"riscv-isa-bits", i256 0} +// RV32D-ISA: !{{[0-9]+}} = !{i32 8, !"riscv-isa-bits", i256 16} +// RV32FD-ISA: !{{[0-9]+}} = !{i32 8, !"riscv-isa-bits", i256 24} +// RV32FDVZFH-ISA: !{{[0-9]+}} = !{i32 8, !"riscv-isa-bits", i256 2097304} +// RV64-ISA: !{{[0-9]+}} = !{i32 8, !"riscv-isa-bits", i256 0} +// RV64D-ISA: !{{[0-9]+}} = !{i32 8, !"riscv-isa-bits", i256 16} +// RV64FD-ISA: !{{[0-9]+}} = !{i32 8, !"riscv-isa-bits", i256 24} diff --git a/llvm/include/llvm/IR/Module.h b/llvm/include/llvm/IR/Module.h --- a/llvm/include/llvm/IR/Module.h +++ b/llvm/include/llvm/IR/Module.h @@ -148,9 +148,12 @@ /// Takes the max of the two values, which are required to be integers. Max = 7, + /// OR two values, which are required to be integers. + OR = 8, + // Markers: ModFlagBehaviorFirstVal = Error, - ModFlagBehaviorLastVal = Max + ModFlagBehaviorLastVal = OR }; /// Checks if Metadata represents a valid ModFlagBehavior, and stores the 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 @@ -12,6 +12,7 @@ #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" +#include "llvm/IR/Constants.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/Error.h" @@ -27,6 +28,9 @@ }; class RISCVISAInfo { + static constexpr unsigned NUM_ISA_BITS = 256; + static constexpr unsigned NUM_ISA_BYTES = NUM_ISA_BITS / 8; + public: RISCVISAInfo(); @@ -49,6 +53,12 @@ // Parse RISCV ISA info from feature vector. void parse(unsigned XLen, const std::vector &Features); + // Parse RISCV ISA info from ConstantInt. + void parse(unsigned XLen, const ConstantInt &Val); + + // Convert RISCV ISA info to APInt + APInt toAPInt(); + // Convert RISCV ISA info to a feature vector. void toFeatures(const llvm::opt::ArgList &Args, std::vector &Features) const; @@ -74,6 +84,7 @@ void addExtension(StringRef ExtName, unsigned MajorVersion = 0, unsigned MinorVersion = 0); + void addBaseExtension() { addExtension("i", 2, 0); } void updateFLen(); }; diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -1567,7 +1567,8 @@ // These behavior types accept any value. break; - case Module::Max: { + case Module::Max: + case Module::OR: { Assert(mdconst::dyn_extract_or_null(Op->getOperand(2)), "invalid value for 'max' module flag (expected constant integer)", Op->getOperand(2)); diff --git a/llvm/lib/Linker/IRMover.cpp b/llvm/lib/Linker/IRMover.cpp --- a/llvm/lib/Linker/IRMover.cpp +++ b/llvm/lib/Linker/IRMover.cpp @@ -1303,11 +1303,13 @@ // Diagnose inconsistent merge behavior types. if (SrcBehaviorValue != DstBehaviorValue) { - bool MaxAndWarn = (SrcBehaviorValue == Module::Max && - DstBehaviorValue == Module::Warning) || - (DstBehaviorValue == Module::Max && - SrcBehaviorValue == Module::Warning); - if (!MaxAndWarn) + bool IntBehaviorAndWarn = ((SrcBehaviorValue == Module::Max || + SrcBehaviorValue == Module::OR) && + DstBehaviorValue == Module::Warning) || + ((DstBehaviorValue == Module::Max || + DstBehaviorValue == Module::OR) && + SrcBehaviorValue == Module::Warning); + if (!IntBehaviorAndWarn) return stringErr("linking module flags '" + ID->getString() + "': IDs have conflicting behaviors in '" + SrcM->getModuleIdentifier() + "' and '" + @@ -1355,6 +1357,47 @@ continue; } + // OR the two values if either source or destination request OR behavior. + if (DstBehaviorValue == Module::OR || SrcBehaviorValue == Module::OR) { + ConstantInt *DstValue = + mdconst::extract(DstOp->getOperand(2)); + ConstantInt *SrcValue = + mdconst::extract(SrcOp->getOperand(2)); + + auto initBitVector = [](const ConstantInt &Val) { + BitVector BitVec(Val.getBitWidth()); + std::memcpy((void *)BitVec.getData().data(), + Val.getValue().getRawData(), BitVec.getMemorySize()); + return BitVec; + }; + auto orConstantValues = [&](const ConstantInt &SrcValue, + const ConstantInt &DstValue) { + uint64_t DstBit = DstValue.getBitWidth(); + uint64_t SrcBit = SrcValue.getBitWidth(); + auto ResultType = + DstBit < SrcBit ? SrcValue.getType() : DstValue.getType(); + if (DstBit <= 64 && SrcBit <= 64) { + uint64_t Result = SrcValue.getZExtValue() | DstValue.getZExtValue(); + return llvm::ConstantInt::get(ResultType, Result); + } + BitVector SrcBitVector = initBitVector(SrcValue); + BitVector DstBitVector = initBitVector(DstValue); + DstBitVector |= SrcBitVector; + return llvm::ConstantInt::get( + DstM.getContext(), + llvm::APInt(DstBitVector.getBitCapacity(), DstBitVector.getData())); + }; + // The resulting flag should have a OR behavior, and OR two values from + // between the source and destination values. + Metadata *FlagOps[] = { + (DstBehaviorValue != Module::OR ? SrcOp : DstOp)->getOperand(0), ID, + ConstantAsMetadata::get(orConstantValues(*SrcValue, *DstValue))}; + MDNode *Flag = MDNode::get(DstM.getContext(), FlagOps); + DstModFlags->setOperand(DstIndex, Flag); + Flags[ID].first = Flag; + continue; + } + // Perform the merge for standard behavior types. switch (SrcBehaviorValue) { case Module::Require: @@ -1375,6 +1418,9 @@ case Module::Max: { break; } + case Module::OR: { + break; + } case Module::Append: { MDNode *DstValue = cast(DstOp->getOperand(2)); MDNode *SrcValue = cast(SrcOp->getOperand(2)); 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 @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/RISCVISAInfo.h" +#include "llvm/ADT/BitVector.h" #include "llvm/ADT/None.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" @@ -39,7 +40,7 @@ static const StringRef AllStdExts = "mafdqlcbjtpvn"; -static const RISCVSupportedExtensionInfo SupportedExtensionInfos[] = { +static constexpr RISCVSupportedExtensionInfo SupportedExtensionInfos[] = { {"i", RISCVExtensionVersion{2, 0}, /* Experimental */ false}, {"e", RISCVExtensionVersion{1, 9}, /* Experimental */ false}, {"m", RISCVExtensionVersion{2, 0}, /* Experimental */ false}, @@ -68,6 +69,60 @@ {"zfh", RISCVExtensionVersion{0, 1}, /* Experimental */ true}, }; +enum ISAFeautreBit { + RV32E = 0, + StdExtM = 1, + StdExtA = 2, + StdExtF = 3, + StdExtD = 4, + StdExtC = 5, + StdExtB = 6, + StdExtV = 7, + ExtZba = 8, + ExtZbb = 9, + ExtZbc = 10, + ExtZbe = 11, + ExtZbf = 12, + ExtZbm = 13, + ExtZbp = 14, + ExtZbr = 15, + ExtZbs = 16, + ExtZbt = 17, + ExtZbproposedc = 18, + ExtZvamo = 19, + StdExtZvlsseg = 20, + ExtZfh = 21, +}; + +// Bitmap[ISAFeatureBit] store the corresponding default SupportedExtensonInfo +// we need maintain this table due to we want to support different version isa +// in the future. +static const RISCVSupportedExtensionInfo *const Bitmap[] = { + /*Bitmap[RV32E]=*/&SupportedExtensionInfos[1], + /*Bitmap[StdExtM]=*/&SupportedExtensionInfos[2], + /*Bitmap[StdExtA]=*/&SupportedExtensionInfos[3], + /*Bitmap[StdExtF]=*/&SupportedExtensionInfos[4], + /*Bitmap[StdExtD]=*/&SupportedExtensionInfos[5], + /*Bitmap[StdExtC]=*/&SupportedExtensionInfos[6], + /*Bitmap[StdExtB]=*/&SupportedExtensionInfos[7], + /*Bitmap[StdExtV]=*/&SupportedExtensionInfos[8], + /*Bitmap[ExtZba]=*/&SupportedExtensionInfos[9], + /*Bitmap[ExtZbb]=*/&SupportedExtensionInfos[10], + /*Bitmap[ExtZbc]=*/&SupportedExtensionInfos[11], + /*Bitmap[ExtZbe]=*/&SupportedExtensionInfos[12], + /*Bitmap[ExtZbf]=*/&SupportedExtensionInfos[13], + /*Bitmap[ExtZbm]=*/&SupportedExtensionInfos[14], + /*Bitmap[ExtZbp]=*/&SupportedExtensionInfos[15], + /*Bitmap[ExtZbr]=*/&SupportedExtensionInfos[16], + /*Bitmap[ExtZbs]=*/&SupportedExtensionInfos[17], + /*Bitmap[ExtZbt]=*/&SupportedExtensionInfos[18], + /*Bitmap[ExtZbproposedc]=*/&SupportedExtensionInfos[19], + /*Bitmap[ExtZvamo]=*/&SupportedExtensionInfos[20], + /*Bitmap[StdExtZvlsseg]=*/&SupportedExtensionInfos[21], + /*Bitmap[ExtZfh]=*/&SupportedExtensionInfos[22]}; + +static constexpr int BitmapSize = sizeof(Bitmap) / sizeof(Bitmap[0]); + // Remove 'experimental-' if it's prefix of string, // return true if did the strip. static bool stripExperimentalPrefix(StringRef &Ext) { @@ -412,7 +467,7 @@ } } if (!HasE) - addExtension("i", 2, 0); + addBaseExtension(); updateFLen(); } @@ -690,6 +745,42 @@ return Error::success(); } +void RISCVISAInfo::parse(unsigned XLen, const ConstantInt &Val) { + assert(XLen == 32 || XLen == 64); + assert(Val.getBitWidth() == NUM_ISA_BITS); + this->XLen = XLen; + BitVector Bits(NUM_ISA_BITS); + std::memcpy((void *)Bits.getData().data(), Val.getValue().getRawData(), + NUM_ISA_BYTES); + for (int ISAFeatureBit = Bits.find_first(); ISAFeatureBit != -1;) { + auto Ext = *Bitmap[ISAFeatureBit]; + addExtension(Ext.Name, Ext.Version.Major, Ext.Version.Minor); + ISAFeatureBit = Bits.find_first_in(ISAFeatureBit + 1, NUM_ISA_BITS); + } + + if (!hasExtension("e")) + addBaseExtension(); + updateFLen(); +} + +APInt RISCVISAInfo::toAPInt() { + BitVector Bits(NUM_ISA_BITS); + for (auto &Ext : Exts) { + StringRef ExtName = Ext.first; + if (ExtName == "i") + continue; + auto it = + std::find_if(Bitmap, Bitmap + BitmapSize, + [ExtName](const RISCVSupportedExtensionInfo *const v) { + return ExtName == v->Name; + }); + assert(it != std::end(Bitmap)); + unsigned Bit = std::distance(Bitmap, it); + Bits.set(Bit); + } + return llvm::APInt(NUM_ISA_BITS, Bits.getData()); +} + void RISCVISAInfo::updateFLen() { FLen = 0; // TODO: Handle q extension. 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,23 @@ } void RISCVAsmPrinter::emitStartOfAsmFile(Module &M) { - if (TM.getTargetTriple().isOSBinFormatELF()) - emitAttributes(); + if (TM.getTargetTriple().isOSBinFormatELF()) { + RISCVTargetStreamer &RTS = + static_cast(*OutStreamer->getTargetStreamer()); + const auto *ISABitsVal = + dyn_cast_or_null(M.getModuleFlag("riscv-isa-bits")); + if (ISABitsVal && STI->getFeatureString().empty()) { + const ConstantInt *ConstVal = cast(ISABitsVal->getValue()); + unsigned XLEN = + TM.getTargetTriple().getArch() == llvm::Triple::riscv32 ? 32 : 64; + RISCVISAInfo ISAInfo; + ISAInfo.parse(XLEN, *ConstVal); + 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-bits.ll b/llvm/test/CodeGen/RISCV/riscv-isa-bits.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/riscv-isa-bits.ll @@ -0,0 +1,36 @@ +; RUN: llc -o - < %s | FileCheck %s +; -mattr option would overwrite target-feature and module flag riscv-isa-bits +; 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} + +; +a,+c,+m +!0 = !{i32 8, !"riscv-isa-bits", i256 38} diff --git a/llvm/test/Linker/Inputs/module-flags-or-1.ll b/llvm/test/Linker/Inputs/module-flags-or-1.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Linker/Inputs/module-flags-or-1.ll @@ -0,0 +1,6 @@ +!0 = !{i32 8, !"or two small values", i32 16} +!1 = !{i32 8, !"or two big values-1", i256 -9223372036854775808} +!2 = !{i32 8, !"or two big values-2", i256 1157442765409226768} +!3 = !{i32 8, !"or small and big value", i256 16} +!4 = !{i32 8, !"foo", i44 16} +!llvm.module.flags = !{!0, !1, !2, !3, !4} diff --git a/llvm/test/Linker/module-flags-or-1.ll b/llvm/test/Linker/module-flags-or-1.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Linker/module-flags-or-1.ll @@ -0,0 +1,18 @@ +; RUN: llvm-link %s %p/Inputs/module-flags-or-1.ll -S -o - | FileCheck %s + +; Test OR functionality of module flags. + +!0 = !{i32 8, !"or two small values", i32 8} +; or 7FFFFFFFFFFFFFFF and 8000000000000000 +!1 = !{i32 8, !"or two big values-1", i256 9223372036854775807} +; or 1000000110000001 and 1010101010101010 +!2 = !{i32 8, !"or two big values-2", i256 1152921509170249729} +!3 = !{i32 8, !"or small and big value", i32 8} +!4 = !{i32 8, !"foo", i66 8} +!llvm.module.flags = !{!0, !1, !2, !3, !4} + +;CHECK: !0 = !{i32 8, !"or two small values", i32 24} +;CHECK: !1 = !{i32 8, !"or two big values-1", i256 -1} +;CHECK: !2 = !{i32 8, !"or two big values-2", i256 1157442769704194065} +;CHECK: !3 = !{i32 8, !"or small and big value", i256 24} +;CHECK: !4 = !{i32 8, !"foo", i128 24}