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<std::string> Features(getTarget().getTargetOpts().Features);
+    llvm::RISCVISAInfo::filterISAStrings(Features);
+    std::vector<llvm::Metadata *> 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<std::string> &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<std::string> &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<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());
 }
 
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<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
+    const auto *ISAFeatureNodes =
+        dyn_cast_or_null<MDNode>(M.getModuleFlag("riscv-isa-features"));
+    if (STI->getFeatureString().empty() && ISAFeatureNodes) {
+      std::vector<std::string> Features;
+      for (const MDOperand &Feature : ISAFeatureNodes->operands()) {
+        auto MAttr = cast<MDString>(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<RISCVTargetStreamer &>(*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"}