khchen created this revision.
khchen added reviewers: jrtc27, MaskRay, kito-cheng.
Herald added subscribers: vkmr, frasercrmck, dexonsmith, evandro, luismarques, 
apazos, sameer.abuasal, s.egerton, Jim, benna, psnobl, jocewei, PkmX, the_o, 
brucehoult, MartinMosbeck, rogfer01, edward-jones, zzheng, shiva0217, niosHD, 
sabuasal, simoncook, johnrusso, rbar, asb, hiraditya.
khchen requested review of this revision.
Herald added projects: clang, LLVM.
Herald added subscribers: llvm-commits, cfe-commits.

1. Support a new link behavoir 'OR' for module flag metadata, use for 
riscv-isa-bits.

(This feature could be in separated patch if PoC patch is workable.)

2. riscv-isa-bits records the march information for a module.

RISCVAsmPrinter reads the riscv-isa-bits to generate corrent arch attribute
if -mattr is missing.

Currently RISC-V encodes arch information per function attribute, 
'target-features'.
so there are two issues we want to fix.

1. In IFUNC case (ex. https://godbolt.org/z/a1oTbacn9), the final arch

attribute information is ambiguous because one compilation unit have
different target-feature value in function attribute.
We could not just union of all target-features, because in IFUNC case,
the base arch string is excepted elf arch attribute.

2. During the LTO, clang driver will not pass -march option to LTO code

generator, because users maybe specify the incorrect -march value if
some linked external libraries have been compiled with different arch
extensions.

The probably way is adding a new module flag metadata, riscv-isa-bits, to
records -march info for one compilation unit, and each riscv-isa-bits
get combined (OR) when linking.

In this PoC patch, I think the potential issue is illegal arch combination
will report an error in code generation stage, not in linking stage.
(For example, zfinx is conflict with f/d/q, and Zceb and Zcec are conflict with 
d)
I'm not sure having a target dependence behaivor in bitcode linking does make
sense or not.

Thanks for @jrtc27, @MaskRay to address this issue in D102926 
<https://reviews.llvm.org/D102926> and D102925 
<https://reviews.llvm.org/D102925>,
and @kito-cheng's reminder of exclusive extensions issue.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D106347

Files:
  clang/lib/CodeGen/CodeGenModule.cpp
  clang/lib/CodeGen/CodeGenTypeCache.h
  clang/test/CodeGen/RISCV/riscv-metadata-isa-bits-empty-target-feature.cpp
  clang/test/CodeGen/RISCV/riscv-metadata-isa-bits-ifunc.c
  clang/test/CodeGen/RISCV/riscv-metadata-isa-bits.c
  llvm/include/llvm/IR/Module.h
  llvm/include/llvm/Support/RISCVISAInfo.h
  llvm/lib/IR/Verifier.cpp
  llvm/lib/Linker/IRMover.cpp
  llvm/lib/Support/RISCVISAInfo.cpp
  llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp
  llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h
  llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
  llvm/test/CodeGen/RISCV/riscv-isa-bits.ll
  llvm/test/Linker/Inputs/module-flags-or-1.ll
  llvm/test/Linker/module-flags-or-1.ll

Index: llvm/test/Linker/module-flags-or-1.ll
===================================================================
--- /dev/null
+++ 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}
Index: llvm/test/Linker/Inputs/module-flags-or-1.ll
===================================================================
--- /dev/null
+++ 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}
Index: llvm/test/CodeGen/RISCV/riscv-isa-bits.ll
===================================================================
--- /dev/null
+++ 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}
Index: llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
===================================================================
--- llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
+++ 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<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
+    const auto *ISABitsVal =
+        dyn_cast_or_null<ValueAsMetadata>(M.getModuleFlag("riscv-isa-bits"));
+    if (ISABitsVal && STI->getFeatureString().empty()) {
+      const ConstantInt *ConstVal = cast<ConstantInt>(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<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
Index: llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h
===================================================================
--- llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h
+++ 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
Index: llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp
===================================================================
--- llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp
+++ llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp
@@ -49,9 +49,15 @@
   unsigned XLen = STI.hasFeature(RISCV::Feature64Bit) ? 64 : 32;
   std::vector<std::string> 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());
 }
 
Index: llvm/lib/Support/RISCVISAInfo.cpp
===================================================================
--- llvm/lib/Support/RISCVISAInfo.cpp
+++ 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.
Index: llvm/lib/Linker/IRMover.cpp
===================================================================
--- llvm/lib/Linker/IRMover.cpp
+++ 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<ConstantInt>(DstOp->getOperand(2));
+      ConstantInt *SrcValue =
+          mdconst::extract<ConstantInt>(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<MDNode>(DstOp->getOperand(2));
       MDNode *SrcValue = cast<MDNode>(SrcOp->getOperand(2));
Index: llvm/lib/IR/Verifier.cpp
===================================================================
--- llvm/lib/IR/Verifier.cpp
+++ 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<ConstantInt>(Op->getOperand(2)),
            "invalid value for 'max' module flag (expected constant integer)",
            Op->getOperand(2));
Index: llvm/include/llvm/Support/RISCVISAInfo.h
===================================================================
--- llvm/include/llvm/Support/RISCVISAInfo.h
+++ 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<std::string> &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<StringRef> &Features) const;
@@ -74,6 +84,7 @@
 
   void addExtension(StringRef ExtName, unsigned MajorVersion = 0,
                     unsigned MinorVersion = 0);
+  void addBaseExtension() { addExtension("i", 2, 0); }
 
   void updateFLen();
 };
Index: llvm/include/llvm/IR/Module.h
===================================================================
--- llvm/include/llvm/IR/Module.h
+++ 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
Index: clang/test/CodeGen/RISCV/riscv-metadata-isa-bits.c
===================================================================
--- /dev/null
+++ 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}
Index: clang/test/CodeGen/RISCV/riscv-metadata-isa-bits-ifunc.c
===================================================================
--- /dev/null
+++ 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);
Index: clang/test/CodeGen/RISCV/riscv-metadata-isa-bits-empty-target-feature.cpp
===================================================================
--- /dev/null
+++ 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;
+}
Index: clang/lib/CodeGen/CodeGenTypeCache.h
===================================================================
--- clang/lib/CodeGen/CodeGenTypeCache.h
+++ 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;
Index: clang/lib/CodeGen/CodeGenModule.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenModule.cpp
+++ 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<std::string> 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) {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to