[llvm] 3297758 - [CSKY] Enable TargetAsmStreamer/ELFStreamer and support asm directive of csky_attribute

Zi Xuan Wu via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 7 23:02:42 PST 2022


Author: Zi Xuan Wu
Date: 2022-03-08T14:00:38+08:00
New Revision: 32977589019d8339b37ee2abcc015d194fd1fa37

URL: https://github.com/llvm/llvm-project/commit/32977589019d8339b37ee2abcc015d194fd1fa37
DIFF: https://github.com/llvm/llvm-project/commit/32977589019d8339b37ee2abcc015d194fd1fa37.diff

LOG: [CSKY] Enable TargetAsmStreamer/ELFStreamer and support asm directive of csky_attribute

Add support of parsing .csky_attribute directive and emit related target attributes in .csky.attribute section.
It does not emit attribute directive in assembly code, so only emit target attributes in ELF streamer.
In ELF streamer, it handles the header EFlag and the csky_attribute section which contains some attribute items.
The EFlag and attribute items are calculated from feature bits based on Subtarget.

Added: 
    llvm/lib/Target/CSKY/MCTargetDesc/CSKYELFStreamer.cpp
    llvm/lib/Target/CSKY/MCTargetDesc/CSKYELFStreamer.h
    llvm/lib/Target/CSKY/MCTargetDesc/CSKYTargetStreamer.cpp
    llvm/lib/Target/CSKY/MCTargetDesc/CSKYTargetStreamer.h
    llvm/test/MC/CSKY/attribute.s
    llvm/test/MC/CSKY/invalid-attribute.s

Modified: 
    llvm/lib/Target/CSKY/AsmParser/CSKYAsmParser.cpp
    llvm/lib/Target/CSKY/CSKYAsmPrinter.cpp
    llvm/lib/Target/CSKY/CSKYAsmPrinter.h
    llvm/lib/Target/CSKY/MCTargetDesc/CMakeLists.txt
    llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCTargetDesc.cpp
    llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCTargetDesc.h

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/CSKY/AsmParser/CSKYAsmParser.cpp b/llvm/lib/Target/CSKY/AsmParser/CSKYAsmParser.cpp
index 2e54d8240c81c..aca05ee8fcfa5 100644
--- a/llvm/lib/Target/CSKY/AsmParser/CSKYAsmParser.cpp
+++ b/llvm/lib/Target/CSKY/AsmParser/CSKYAsmParser.cpp
@@ -9,6 +9,7 @@
 #include "MCTargetDesc/CSKYInstPrinter.h"
 #include "MCTargetDesc/CSKYMCExpr.h"
 #include "MCTargetDesc/CSKYMCTargetDesc.h"
+#include "MCTargetDesc/CSKYTargetStreamer.h"
 #include "TargetInfo/CSKYTargetInfo.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/Statistic.h"
@@ -27,6 +28,8 @@
 #include "llvm/MC/MCStreamer.h"
 #include "llvm/MC/MCSubtargetInfo.h"
 #include "llvm/MC/TargetRegistry.h"
+#include "llvm/Support/CSKYAttributes.h"
+#include "llvm/Support/CSKYTargetParser.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Debug.h"
@@ -84,6 +87,13 @@ class CSKYAsmParser : public MCTargetAsmParser {
   bool processInstruction(MCInst &Inst, SMLoc IDLoc, OperandVector &Operands,
                           MCStreamer &Out);
 
+  CSKYTargetStreamer &getTargetStreamer() {
+    assert(getParser().getStreamer().getTargetStreamer() &&
+           "do not have a target streamer");
+    MCTargetStreamer &TS = *getParser().getStreamer().getTargetStreamer();
+    return static_cast<CSKYTargetStreamer &>(TS);
+  }
+
 // Auto-generated instruction matching functions
 #define GET_ASSEMBLER_HEADER
 #include "CSKYGenAsmMatcher.inc"
@@ -100,6 +110,8 @@ class CSKYAsmParser : public MCTargetAsmParser {
 
   bool parseOperand(OperandVector &Operands, StringRef Mnemonic);
 
+  bool parseDirectiveAttribute();
+
 public:
   enum CSKYMatchResultTy {
     Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY,
@@ -113,6 +125,9 @@ class CSKYAsmParser : public MCTargetAsmParser {
   CSKYAsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
                 const MCInstrInfo &MII, const MCTargetOptions &Options)
       : MCTargetAsmParser(Options, STI, MII) {
+
+    MCAsmParserExtension::Initialize(Parser);
+
     setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
   }
 };
@@ -1481,7 +1496,99 @@ OperandMatchResultTy CSKYAsmParser::tryParseRegister(unsigned &RegNo,
   return MatchOperand_Success;
 }
 
-bool CSKYAsmParser::ParseDirective(AsmToken DirectiveID) { return true; }
+bool CSKYAsmParser::ParseDirective(AsmToken DirectiveID) {
+  // This returns false if this function recognizes the directive
+  // regardless of whether it is successfully handles or reports an
+  // error. Otherwise it returns true to give the generic parser a
+  // chance at recognizing it.
+  StringRef IDVal = DirectiveID.getString();
+
+  if (IDVal == ".csky_attribute")
+    return parseDirectiveAttribute();
+
+  return true;
+}
+
+/// parseDirectiveAttribute
+///  ::= .attribute expression ',' ( expression | "string" )
+bool CSKYAsmParser::parseDirectiveAttribute() {
+  MCAsmParser &Parser = getParser();
+  int64_t Tag;
+  SMLoc TagLoc;
+  TagLoc = Parser.getTok().getLoc();
+  if (Parser.getTok().is(AsmToken::Identifier)) {
+    StringRef Name = Parser.getTok().getIdentifier();
+    Optional<unsigned> Ret =
+        ELFAttrs::attrTypeFromString(Name, CSKYAttrs::getCSKYAttributeTags());
+    if (!Ret.hasValue()) {
+      Error(TagLoc, "attribute name not recognised: " + Name);
+      return false;
+    }
+    Tag = Ret.getValue();
+    Parser.Lex();
+  } else {
+    const MCExpr *AttrExpr;
+
+    TagLoc = Parser.getTok().getLoc();
+    if (Parser.parseExpression(AttrExpr))
+      return true;
+
+    const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(AttrExpr);
+    if (check(!CE, TagLoc, "expected numeric constant"))
+      return true;
+
+    Tag = CE->getValue();
+  }
+
+  if (Parser.parseToken(AsmToken::Comma, "comma expected"))
+    return true;
+
+  StringRef StringValue;
+  int64_t IntegerValue = 0;
+  bool IsIntegerValue = ((Tag != CSKYAttrs::CSKY_ARCH_NAME) &&
+                         (Tag != CSKYAttrs::CSKY_CPU_NAME) &&
+                         (Tag != CSKYAttrs::CSKY_FPU_NUMBER_MODULE));
+
+  SMLoc ValueExprLoc = Parser.getTok().getLoc();
+  if (IsIntegerValue) {
+    const MCExpr *ValueExpr;
+    if (Parser.parseExpression(ValueExpr))
+      return true;
+
+    const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(ValueExpr);
+    if (!CE)
+      return Error(ValueExprLoc, "expected numeric constant");
+    IntegerValue = CE->getValue();
+  } else {
+    if (Parser.getTok().isNot(AsmToken::String))
+      return Error(Parser.getTok().getLoc(), "expected string constant");
+
+    StringValue = Parser.getTok().getStringContents();
+    Parser.Lex();
+  }
+
+  if (Parser.parseToken(AsmToken::EndOfStatement,
+                        "unexpected token in '.csky_attribute' directive"))
+    return true;
+
+  if (IsIntegerValue)
+    getTargetStreamer().emitAttribute(Tag, IntegerValue);
+  else if (Tag != CSKYAttrs::CSKY_ARCH_NAME && Tag != CSKYAttrs::CSKY_CPU_NAME)
+    getTargetStreamer().emitTextAttribute(Tag, StringValue);
+  else {
+    CSKY::ArchKind ID = (Tag == CSKYAttrs::CSKY_ARCH_NAME)
+                            ? CSKY::parseArch(StringValue)
+                            : CSKY::parseCPUArch(StringValue);
+    if (ID == CSKY::ArchKind::INVALID)
+      return Error(ValueExprLoc, (Tag == CSKYAttrs::CSKY_ARCH_NAME)
+                                     ? "unknown arch name"
+                                     : "unknown cpu name");
+
+    getTargetStreamer().emitTextAttribute(Tag, StringValue);
+  }
+
+  return false;
+}
 
 unsigned CSKYAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
                                                    unsigned Kind) {

diff  --git a/llvm/lib/Target/CSKY/CSKYAsmPrinter.cpp b/llvm/lib/Target/CSKY/CSKYAsmPrinter.cpp
index 0c317c9f56288..e14302a5f61ea 100644
--- a/llvm/lib/Target/CSKY/CSKYAsmPrinter.cpp
+++ b/llvm/lib/Target/CSKY/CSKYAsmPrinter.cpp
@@ -16,6 +16,7 @@
 #include "CSKYTargetMachine.h"
 #include "MCTargetDesc/CSKYInstPrinter.h"
 #include "MCTargetDesc/CSKYMCExpr.h"
+#include "MCTargetDesc/CSKYTargetStreamer.h"
 #include "TargetInfo/CSKYTargetInfo.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/CodeGen/AsmPrinter.h"
@@ -40,7 +41,15 @@ CSKYAsmPrinter::CSKYAsmPrinter(llvm::TargetMachine &TM,
 
 bool CSKYAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
   MCP = MF.getConstantPool();
-  Subtarget = &MF.getSubtarget<CSKYSubtarget>();
+  TII = MF.getSubtarget().getInstrInfo();
+
+  // Set the current MCSubtargetInfo to a copy which has the correct
+  // feature bits for the current MachineFunction
+  MCSubtargetInfo &NewSTI =
+      OutStreamer->getContext().getSubtargetCopy(*TM.getMCSubtargetInfo());
+  NewSTI.setFeatureBits(MF.getSubtarget().getFeatureBits());
+  Subtarget = &NewSTI;
+
   return AsmPrinter::runOnMachineFunction(MF);
 }
 
@@ -59,8 +68,6 @@ void CSKYAsmPrinter::EmitToStreamer(MCStreamer &S, const MCInst &Inst) {
 #include "CSKYGenMCPseudoLowering.inc"
 
 void CSKYAsmPrinter::expandTLSLA(const MachineInstr *MI) {
-  const CSKYInstrInfo *TII = Subtarget->getInstrInfo();
-
   DebugLoc DL = MI->getDebugLoc();
 
   MCSymbol *PCLabel = OutContext.getOrCreateSymbol(
@@ -119,6 +126,19 @@ void CSKYAsmPrinter::emitFunctionBodyEnd() {
   InConstantPool = false;
 }
 
+void CSKYAsmPrinter::emitStartOfAsmFile(Module &M) {
+  if (TM.getTargetTriple().isOSBinFormatELF())
+    emitAttributes();
+}
+
+void CSKYAsmPrinter::emitEndOfAsmFile(Module &M) {
+  CSKYTargetStreamer &CTS =
+      static_cast<CSKYTargetStreamer &>(*OutStreamer->getTargetStreamer());
+
+  if (TM.getTargetTriple().isOSBinFormatELF())
+    CTS.finishAttributeSection();
+}
+
 void CSKYAsmPrinter::emitInstruction(const MachineInstr *MI) {
   // Do any auto-generated pseudo lowerings.
   if (emitPseudoExpansionLowering(*OutStreamer, MI))
@@ -218,6 +238,21 @@ void CSKYAsmPrinter::emitMachineConstantPoolValue(
   OutStreamer->emitValue(Expr, Size);
 }
 
+void CSKYAsmPrinter::emitAttributes() {
+  CSKYTargetStreamer &CTS =
+      static_cast<CSKYTargetStreamer &>(*OutStreamer->getTargetStreamer());
+
+  const Triple &TT = TM.getTargetTriple();
+  StringRef CPU = TM.getTargetCPU();
+  StringRef FS = TM.getTargetFeatureString();
+  const CSKYTargetMachine &CTM = static_cast<const CSKYTargetMachine &>(TM);
+  /* TuneCPU doesn't impact emission of ELF attributes, ELF attributes only
+     care about arch related features, so we can set TuneCPU as CPU.  */
+  const CSKYSubtarget STI(TT, CPU, /*TuneCPU=*/CPU, FS, CTM);
+
+  CTS.emitTargetAttributes(STI);
+}
+
 bool CSKYAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
                                      const char *ExtraCode, raw_ostream &OS) {
   // First try the generic code, which knows about modifiers like 'c' and 'n'.

diff  --git a/llvm/lib/Target/CSKY/CSKYAsmPrinter.h b/llvm/lib/Target/CSKY/CSKYAsmPrinter.h
index c626fea15262a..5e87594e4fdf1 100644
--- a/llvm/lib/Target/CSKY/CSKYAsmPrinter.h
+++ b/llvm/lib/Target/CSKY/CSKYAsmPrinter.h
@@ -18,7 +18,8 @@ namespace llvm {
 class LLVM_LIBRARY_VISIBILITY CSKYAsmPrinter : public AsmPrinter {
   CSKYMCInstLower MCInstLowering;
 
-  const CSKYSubtarget *Subtarget;
+  const MCSubtargetInfo *Subtarget;
+  const TargetInstrInfo *TII;
 
   bool InConstantPool = false;
 
@@ -28,6 +29,7 @@ class LLVM_LIBRARY_VISIBILITY CSKYAsmPrinter : public AsmPrinter {
 
   void expandTLSLA(const MachineInstr *MI);
   void emitCustomConstantPool(const MachineInstr *MI);
+  void emitAttributes();
 
 public:
   explicit CSKYAsmPrinter(TargetMachine &TM,
@@ -46,6 +48,10 @@ class LLVM_LIBRARY_VISIBILITY CSKYAsmPrinter : public AsmPrinter {
 
   void emitFunctionBodyEnd() override;
 
+  void emitStartOfAsmFile(Module &M) override;
+
+  void emitEndOfAsmFile(Module &M) override;
+
   void emitInstruction(const MachineInstr *MI) override;
 
   bool runOnMachineFunction(MachineFunction &MF) override;

diff  --git a/llvm/lib/Target/CSKY/MCTargetDesc/CMakeLists.txt b/llvm/lib/Target/CSKY/MCTargetDesc/CMakeLists.txt
index df59a9955a712..0018ea5ef5da0 100644
--- a/llvm/lib/Target/CSKY/MCTargetDesc/CMakeLists.txt
+++ b/llvm/lib/Target/CSKY/MCTargetDesc/CMakeLists.txt
@@ -1,11 +1,13 @@
 add_llvm_component_library(LLVMCSKYDesc
   CSKYAsmBackend.cpp
   CSKYELFObjectWriter.cpp
+  CSKYELFStreamer.cpp
   CSKYInstPrinter.cpp
   CSKYMCAsmInfo.cpp
   CSKYMCExpr.cpp
   CSKYMCTargetDesc.cpp
   CSKYMCCodeEmitter.cpp
+  CSKYTargetStreamer.cpp
 
   LINK_COMPONENTS
   CSKYInfo

diff  --git a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYELFStreamer.cpp b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYELFStreamer.cpp
new file mode 100644
index 0000000000000..6d291b39093c2
--- /dev/null
+++ b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYELFStreamer.cpp
@@ -0,0 +1,335 @@
+//===-- CSKYELFStreamer.cpp - CSKY ELF Target Streamer Methods ------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides CSKY specific target streamer methods.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CSKYELFStreamer.h"
+#include "CSKYMCTargetDesc.h"
+#include "MCTargetDesc/CSKYAsmBackend.h"
+#include "MCTargetDesc/CSKYBaseInfo.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCSectionELF.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCSymbolELF.h"
+#include "llvm/Support/CSKYAttributes.h"
+#include "llvm/Support/CSKYTargetParser.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/LEB128.h"
+
+using namespace llvm;
+
+// This part is for ELF object output.
+CSKYTargetELFStreamer::CSKYTargetELFStreamer(MCStreamer &S,
+                                             const MCSubtargetInfo &STI)
+    : CSKYTargetStreamer(S), CurrentVendor("csky") {
+  MCAssembler &MCA = getStreamer().getAssembler();
+  const FeatureBitset &Features = STI.getFeatureBits();
+
+  unsigned EFlags = MCA.getELFHeaderEFlags();
+
+  EFlags |= ELF::EF_CSKY_ABIV2;
+
+  if (Features[CSKY::ProcCK801])
+    EFlags |= ELF::EF_CSKY_801;
+  else if (Features[CSKY::ProcCK802])
+    EFlags |= ELF::EF_CSKY_802;
+  else if (Features[CSKY::ProcCK803])
+    EFlags |= ELF::EF_CSKY_803;
+  else if (Features[CSKY::ProcCK804])
+    EFlags |= ELF::EF_CSKY_803;
+  else if (Features[CSKY::ProcCK805])
+    EFlags |= ELF::EF_CSKY_805;
+  else if (Features[CSKY::ProcCK807])
+    EFlags |= ELF::EF_CSKY_807;
+  else if (Features[CSKY::ProcCK810])
+    EFlags |= ELF::EF_CSKY_810;
+  else if (Features[CSKY::ProcCK860])
+    EFlags |= ELF::EF_CSKY_860;
+  else
+    EFlags |= ELF::EF_CSKY_810;
+
+  if (Features[CSKY::FeatureFPUV2_SF] || Features[CSKY::FeatureFPUV3_SF])
+    EFlags |= ELF::EF_CSKY_FLOAT;
+
+  EFlags |= ELF::EF_CSKY_EFV1;
+
+  MCA.setELFHeaderEFlags(EFlags);
+}
+
+MCELFStreamer &CSKYTargetELFStreamer::getStreamer() {
+  return static_cast<MCELFStreamer &>(Streamer);
+}
+
+void CSKYTargetELFStreamer::emitAttribute(unsigned Attribute, unsigned Value) {
+  setAttributeItem(Attribute, Value, /*OverwriteExisting=*/true);
+}
+
+void CSKYTargetELFStreamer::emitTextAttribute(unsigned Attribute,
+                                              StringRef String) {
+  setAttributeItem(Attribute, String, /*OverwriteExisting=*/true);
+}
+
+void CSKYTargetELFStreamer::finishAttributeSection() {
+  if (Contents.empty())
+    return;
+
+  if (AttributeSection) {
+    Streamer.SwitchSection(AttributeSection);
+  } else {
+    MCAssembler &MCA = getStreamer().getAssembler();
+    AttributeSection = MCA.getContext().getELFSection(
+        ".csky.attributes", ELF::SHT_CSKY_ATTRIBUTES, 0);
+    Streamer.SwitchSection(AttributeSection);
+    Streamer.emitInt8(ELFAttrs::Format_Version);
+  }
+
+  // Vendor size + Vendor name + '\0'
+  const size_t VendorHeaderSize = 4 + CurrentVendor.size() + 1;
+
+  // Tag + Tag Size
+  const size_t TagHeaderSize = 1 + 4;
+
+  const size_t ContentsSize = calculateContentSize();
+
+  Streamer.emitInt32(VendorHeaderSize + TagHeaderSize + ContentsSize);
+  Streamer.emitBytes(CurrentVendor);
+  Streamer.emitInt8(0); // '\0'
+
+  Streamer.emitInt8(ELFAttrs::File);
+  Streamer.emitInt32(TagHeaderSize + ContentsSize);
+
+  // Size should have been accounted for already, now
+  // emit each field as its type (ULEB or String).
+  for (AttributeItem item : Contents) {
+    Streamer.emitULEB128IntValue(item.Tag);
+    switch (item.Type) {
+    default:
+      llvm_unreachable("Invalid attribute type");
+    case AttributeType::Numeric:
+      Streamer.emitULEB128IntValue(item.IntValue);
+      break;
+    case AttributeType::Text:
+      Streamer.emitBytes(item.StringValue);
+      Streamer.emitInt8(0); // '\0'
+      break;
+    case AttributeType::NumericAndText:
+      Streamer.emitULEB128IntValue(item.IntValue);
+      Streamer.emitBytes(item.StringValue);
+      Streamer.emitInt8(0); // '\0'
+      break;
+    }
+  }
+
+  Contents.clear();
+}
+
+size_t CSKYTargetELFStreamer::calculateContentSize() const {
+  size_t Result = 0;
+  for (AttributeItem item : Contents) {
+    switch (item.Type) {
+    case AttributeType::Hidden:
+      break;
+    case AttributeType::Numeric:
+      Result += getULEB128Size(item.Tag);
+      Result += getULEB128Size(item.IntValue);
+      break;
+    case AttributeType::Text:
+      Result += getULEB128Size(item.Tag);
+      Result += item.StringValue.size() + 1; // string + '\0'
+      break;
+    case AttributeType::NumericAndText:
+      Result += getULEB128Size(item.Tag);
+      Result += getULEB128Size(item.IntValue);
+      Result += item.StringValue.size() + 1; // string + '\0';
+      break;
+    }
+  }
+  return Result;
+}
+
+void CSKYELFStreamer::EmitMappingSymbol(StringRef Name) {
+  if (Name == "$d" && State == EMS_Data)
+    return;
+  if (Name == "$t" && State == EMS_Text)
+    return;
+  if (Name == "$t" && State == EMS_None) {
+    State = EMS_Text;
+    return;
+  }
+
+  State = (Name == "$t" ? EMS_Text : EMS_Data);
+
+  auto *Symbol = cast<MCSymbolELF>(getContext().getOrCreateSymbol(
+      Name + "." + Twine(MappingSymbolCounter++)));
+  emitLabel(Symbol);
+
+  Symbol->setType(ELF::STT_NOTYPE);
+  Symbol->setBinding(ELF::STB_LOCAL);
+}
+
+void CSKYTargetELFStreamer::emitTargetAttributes(const MCSubtargetInfo &STI) {
+  StringRef CPU = STI.getCPU();
+  CSKY::ArchKind ArchID = CSKY::parseCPUArch(CPU);
+
+  if (ArchID == CSKY::ArchKind::CK804)
+    ArchID = CSKY::ArchKind::CK803;
+
+  StringRef CPU_ARCH = CSKY::getArchName(ArchID);
+
+  if (ArchID == CSKY::ArchKind::INVALID) {
+    CPU = "ck810";
+    CPU_ARCH = "ck810";
+  }
+  emitTextAttribute(CSKYAttrs::CSKY_ARCH_NAME, CPU_ARCH);
+  emitTextAttribute(CSKYAttrs::CSKY_CPU_NAME, CPU);
+
+  unsigned ISAFlag = 0;
+  if (STI.hasFeature(CSKY::HasE1))
+    ISAFlag |= CSKYAttrs::V2_ISA_E1;
+
+  if (STI.hasFeature(CSKY::HasE2))
+    ISAFlag |= CSKYAttrs::V2_ISA_1E2;
+
+  if (STI.hasFeature(CSKY::Has2E3))
+    ISAFlag |= CSKYAttrs::V2_ISA_2E3;
+
+  if (STI.hasFeature(CSKY::HasMP))
+    ISAFlag |= CSKYAttrs::ISA_MP;
+
+  if (STI.hasFeature(CSKY::Has3E3r1))
+    ISAFlag |= CSKYAttrs::V2_ISA_3E3R1;
+
+  if (STI.hasFeature(CSKY::Has3r1E3r2))
+    ISAFlag |= CSKYAttrs::V2_ISA_3E3R2;
+
+  if (STI.hasFeature(CSKY::Has3r2E3r3))
+    ISAFlag |= CSKYAttrs::V2_ISA_3E3R3;
+
+  if (STI.hasFeature(CSKY::Has3E7))
+    ISAFlag |= CSKYAttrs::V2_ISA_3E7;
+
+  if (STI.hasFeature(CSKY::HasMP1E2))
+    ISAFlag |= CSKYAttrs::ISA_MP_1E2;
+
+  if (STI.hasFeature(CSKY::Has7E10))
+    ISAFlag |= CSKYAttrs::V2_ISA_7E10;
+
+  if (STI.hasFeature(CSKY::Has10E60))
+    ISAFlag |= CSKYAttrs::V2_ISA_10E60;
+
+  if (STI.hasFeature(CSKY::FeatureTrust))
+    ISAFlag |= CSKYAttrs::ISA_TRUST;
+
+  if (STI.hasFeature(CSKY::FeatureJAVA))
+    ISAFlag |= CSKYAttrs::ISA_JAVA;
+
+  if (STI.hasFeature(CSKY::FeatureCache))
+    ISAFlag |= CSKYAttrs::ISA_CACHE;
+
+  if (STI.hasFeature(CSKY::FeatureNVIC))
+    ISAFlag |= CSKYAttrs::ISA_NVIC;
+
+  if (STI.hasFeature(CSKY::FeatureDSP))
+    ISAFlag |= CSKYAttrs::ISA_DSP;
+
+  if (STI.hasFeature(CSKY::HasDSP1E2))
+    ISAFlag |= CSKYAttrs::ISA_DSP_1E2;
+
+  if (STI.hasFeature(CSKY::HasDSPE60))
+    ISAFlag |= CSKYAttrs::V2_ISA_DSPE60;
+
+  if (STI.hasFeature(CSKY::FeatureDSPV2))
+    ISAFlag |= CSKYAttrs::ISA_DSP_ENHANCE;
+
+  if (STI.hasFeature(CSKY::FeatureDSP_Silan))
+    ISAFlag |= CSKYAttrs::ISA_DSP_SILAN;
+
+  if (STI.hasFeature(CSKY::FeatureVDSPV1_128))
+    ISAFlag |= CSKYAttrs::ISA_VDSP;
+
+  if (STI.hasFeature(CSKY::FeatureVDSPV2))
+    ISAFlag |= CSKYAttrs::ISA_VDSP_2;
+
+  if (STI.hasFeature(CSKY::HasVDSP2E3))
+    ISAFlag |= CSKYAttrs::ISA_VDSP_2E3;
+
+  if (STI.hasFeature(CSKY::HasVDSP2E60F))
+    ISAFlag |= CSKYAttrs::ISA_VDSP_2E60F;
+
+  emitAttribute(CSKYAttrs::CSKY_ISA_FLAGS, ISAFlag);
+
+  unsigned ISAExtFlag = 0;
+  if (STI.hasFeature(CSKY::HasFLOATE1))
+    ISAExtFlag |= CSKYAttrs::ISA_FLOAT_E1;
+
+  if (STI.hasFeature(CSKY::HasFLOAT1E2))
+    ISAExtFlag |= CSKYAttrs::ISA_FLOAT_1E2;
+
+  if (STI.hasFeature(CSKY::HasFLOAT1E3))
+    ISAExtFlag |= CSKYAttrs::ISA_FLOAT_1E3;
+
+  if (STI.hasFeature(CSKY::HasFLOAT3E4))
+    ISAExtFlag |= CSKYAttrs::ISA_FLOAT_3E4;
+
+  if (STI.hasFeature(CSKY::HasFLOAT7E60))
+    ISAExtFlag |= CSKYAttrs::ISA_FLOAT_7E60;
+
+  emitAttribute(CSKYAttrs::CSKY_ISA_EXT_FLAGS, ISAExtFlag);
+
+  if (STI.hasFeature(CSKY::FeatureDSP))
+    emitAttribute(CSKYAttrs::CSKY_DSP_VERSION,
+                  CSKYAttrs::DSP_VERSION_EXTENSION);
+  if (STI.hasFeature(CSKY::FeatureDSPV2))
+    emitAttribute(CSKYAttrs::CSKY_DSP_VERSION, CSKYAttrs::DSP_VERSION_2);
+
+  if (STI.hasFeature(CSKY::FeatureVDSPV2))
+    emitAttribute(CSKYAttrs::CSKY_VDSP_VERSION, CSKYAttrs::VDSP_VERSION_2);
+
+  if (STI.hasFeature(CSKY::FeatureFPUV2_SF) ||
+      STI.hasFeature(CSKY::FeatureFPUV2_DF))
+    emitAttribute(CSKYAttrs::CSKY_FPU_VERSION, CSKYAttrs::FPU_VERSION_2);
+  else if (STI.hasFeature(CSKY::FeatureFPUV3_HF) ||
+           STI.hasFeature(CSKY::FeatureFPUV3_SF) ||
+           STI.hasFeature(CSKY::FeatureFPUV3_DF))
+    emitAttribute(CSKYAttrs::CSKY_FPU_VERSION, CSKYAttrs::FPU_VERSION_3);
+
+  bool hasAnyFloatExt = STI.hasFeature(CSKY::FeatureFPUV2_SF) ||
+                        STI.hasFeature(CSKY::FeatureFPUV2_DF) ||
+                        STI.hasFeature(CSKY::FeatureFPUV3_HF) ||
+                        STI.hasFeature(CSKY::FeatureFPUV3_SF) ||
+                        STI.hasFeature(CSKY::FeatureFPUV3_DF);
+
+  if (hasAnyFloatExt && STI.hasFeature(CSKY::ModeHardFloat) &&
+      STI.hasFeature(CSKY::ModeHardFloatABI))
+    emitAttribute(CSKYAttrs::CSKY_FPU_ABI, CSKYAttrs::FPU_ABI_HARD);
+  else if (hasAnyFloatExt && STI.hasFeature(CSKY::ModeHardFloat))
+    emitAttribute(CSKYAttrs::CSKY_FPU_ABI, CSKYAttrs::FPU_ABI_SOFTFP);
+  else
+    emitAttribute(CSKYAttrs::CSKY_FPU_ABI, CSKYAttrs::FPU_ABI_SOFT);
+
+  unsigned HardFPFlag = 0;
+  if (STI.hasFeature(CSKY::FeatureFPUV3_HF))
+    HardFPFlag |= CSKYAttrs::FPU_HARDFP_HALF;
+  if (STI.hasFeature(CSKY::FeatureFPUV2_SF) ||
+      STI.hasFeature(CSKY::FeatureFPUV3_SF))
+    HardFPFlag |= CSKYAttrs::FPU_HARDFP_SINGLE;
+  if (STI.hasFeature(CSKY::FeatureFPUV2_DF) ||
+      STI.hasFeature(CSKY::FeatureFPUV3_DF))
+    HardFPFlag |= CSKYAttrs::FPU_HARDFP_DOUBLE;
+
+  if (HardFPFlag != 0) {
+    emitAttribute(CSKYAttrs::CSKY_FPU_DENORMAL, CSKYAttrs::NEEDED);
+    emitAttribute(CSKYAttrs::CSKY_FPU_EXCEPTION, CSKYAttrs::NEEDED);
+    emitTextAttribute(CSKYAttrs::CSKY_FPU_NUMBER_MODULE, "IEEE 754");
+    emitAttribute(CSKYAttrs::CSKY_FPU_HARDFP, HardFPFlag);
+  }
+}

diff  --git a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYELFStreamer.h b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYELFStreamer.h
new file mode 100644
index 0000000000000..17f96ea6e1fd8
--- /dev/null
+++ b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYELFStreamer.h
@@ -0,0 +1,148 @@
+//===-- CSKYELFStreamer.h - CSKY ELF Target Streamer -----------*- C++ -*--===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_CSKY_CSKYELFSTREAMER_H
+#define LLVM_LIB_TARGET_CSKY_CSKYELFSTREAMER_H
+
+#include "CSKYTargetStreamer.h"
+#include "llvm/MC/MCCodeEmitter.h"
+#include "llvm/MC/MCELFStreamer.h"
+#include "llvm/MC/MCObjectWriter.h"
+
+namespace llvm {
+
+class CSKYTargetELFStreamer : public CSKYTargetStreamer {
+private:
+  enum class AttributeType { Hidden, Numeric, Text, NumericAndText };
+
+  struct AttributeItem {
+    AttributeType Type;
+    unsigned Tag;
+    unsigned IntValue;
+    std::string StringValue;
+  };
+
+  StringRef CurrentVendor;
+  SmallVector<AttributeItem, 64> Contents;
+
+  MCSection *AttributeSection = nullptr;
+
+  AttributeItem *getAttributeItem(unsigned Attribute) {
+    for (size_t i = 0; i < Contents.size(); ++i)
+      if (Contents[i].Tag == Attribute)
+        return &Contents[i];
+    return nullptr;
+  }
+
+  void setAttributeItem(unsigned Attribute, unsigned Value,
+                        bool OverwriteExisting) {
+    // Look for existing attribute item.
+    if (AttributeItem *Item = getAttributeItem(Attribute)) {
+      if (!OverwriteExisting)
+        return;
+      Item->Type = AttributeType::Numeric;
+      Item->IntValue = Value;
+      return;
+    }
+
+    // Create new attribute item.
+    Contents.push_back({AttributeType::Numeric, Attribute, Value, ""});
+  }
+
+  void setAttributeItem(unsigned Attribute, StringRef Value,
+                        bool OverwriteExisting) {
+    // Look for existing attribute item.
+    if (AttributeItem *Item = getAttributeItem(Attribute)) {
+      if (!OverwriteExisting)
+        return;
+      Item->Type = AttributeType::Text;
+      Item->StringValue = std::string(Value);
+      return;
+    }
+
+    // Create new attribute item.
+    Contents.push_back({AttributeType::Text, Attribute, 0, std::string(Value)});
+  }
+
+  void setAttributeItems(unsigned Attribute, unsigned IntValue,
+                         StringRef StringValue, bool OverwriteExisting) {
+    // Look for existing attribute item.
+    if (AttributeItem *Item = getAttributeItem(Attribute)) {
+      if (!OverwriteExisting)
+        return;
+      Item->Type = AttributeType::NumericAndText;
+      Item->IntValue = IntValue;
+      Item->StringValue = std::string(StringValue);
+      return;
+    }
+
+    // Create new attribute item.
+    Contents.push_back({AttributeType::NumericAndText, Attribute, IntValue,
+                        std::string(StringValue)});
+  }
+
+  void emitAttribute(unsigned Attribute, unsigned Value) override;
+  void emitTextAttribute(unsigned Attribute, StringRef String) override;
+  void finishAttributeSection() override;
+  size_t calculateContentSize() const;
+
+  void emitTargetAttributes(const MCSubtargetInfo &STI) override;
+
+public:
+  MCELFStreamer &getStreamer();
+  CSKYTargetELFStreamer(MCStreamer &S, const MCSubtargetInfo &STI);
+};
+
+class CSKYELFStreamer : public MCELFStreamer {
+  int64_t MappingSymbolCounter = 0;
+
+  void EmitMappingSymbol(StringRef Name);
+
+public:
+  friend class CSKYTargetELFStreamer;
+
+  enum ElfMappingSymbol { EMS_None, EMS_Text, EMS_Data };
+
+  ElfMappingSymbol State;
+
+  CSKYELFStreamer(MCContext &Context, std::unique_ptr<MCAsmBackend> TAB,
+                  std::unique_ptr<MCObjectWriter> OW,
+                  std::unique_ptr<MCCodeEmitter> Emitter)
+      : MCELFStreamer(Context, std::move(TAB), std::move(OW),
+                      std::move(Emitter)),
+        State(EMS_None) {}
+
+  ~CSKYELFStreamer() override = default;
+
+  void emitFill(const MCExpr &NumBytes, uint64_t FillValue,
+                SMLoc Loc) override {
+    EmitMappingSymbol("$d");
+    MCObjectStreamer::emitFill(NumBytes, FillValue, Loc);
+  }
+  void emitBytes(StringRef Data) override {
+    EmitMappingSymbol("$d");
+    MCELFStreamer::emitBytes(Data);
+  }
+  void emitInstruction(const MCInst &Inst,
+                       const MCSubtargetInfo &STI) override {
+    EmitMappingSymbol("$t");
+    MCELFStreamer::emitInstruction(Inst, STI);
+  }
+  void emitValueImpl(const MCExpr *Value, unsigned Size, SMLoc Loc) override {
+    EmitMappingSymbol("$d");
+    MCELFStreamer::emitValueImpl(Value, Size, Loc);
+  }
+  void reset() {
+    MappingSymbolCounter = 0;
+    State = EMS_None;
+    MCELFStreamer::reset();
+  }
+};
+
+} // namespace llvm
+#endif

diff  --git a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCTargetDesc.cpp b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCTargetDesc.cpp
index 7e8b278eb6bf6..c41a20060e484 100644
--- a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCTargetDesc.cpp
+++ b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCTargetDesc.cpp
@@ -12,9 +12,11 @@
 
 #include "CSKYMCTargetDesc.h"
 #include "CSKYAsmBackend.h"
+#include "CSKYELFStreamer.h"
 #include "CSKYInstPrinter.h"
 #include "CSKYMCAsmInfo.h"
 #include "CSKYMCCodeEmitter.h"
+#include "CSKYTargetStreamer.h"
 #include "TargetInfo/CSKYTargetInfo.h"
 #include "llvm/MC/MCAssembler.h"
 #include "llvm/MC/MCInstrInfo.h"
@@ -73,6 +75,38 @@ static MCSubtargetInfo *createCSKYMCSubtargetInfo(const Triple &TT,
   return createCSKYMCSubtargetInfoImpl(TT, CPUName, /*TuneCPU=*/CPUName, FS);
 }
 
+static MCTargetStreamer *
+createCSKYObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) {
+  const Triple &TT = STI.getTargetTriple();
+  if (TT.isOSBinFormatELF())
+    return new CSKYTargetELFStreamer(S, STI);
+  return nullptr;
+}
+
+static MCStreamer *createELFStreamer(const Triple &T, MCContext &Ctx,
+                                     std::unique_ptr<MCAsmBackend> &&MAB,
+                                     std::unique_ptr<MCObjectWriter> &&OW,
+                                     std::unique_ptr<MCCodeEmitter> &&Emitter,
+                                     bool RelaxAll) {
+  CSKYELFStreamer *S = new CSKYELFStreamer(Ctx, std::move(MAB), std::move(OW),
+                                           std::move(Emitter));
+
+  if (RelaxAll)
+    S->getAssembler().setRelaxAll(true);
+  return S;
+}
+
+static MCTargetStreamer *createCSKYAsmTargetStreamer(MCStreamer &S,
+                                                     formatted_raw_ostream &OS,
+                                                     MCInstPrinter *InstPrinter,
+                                                     bool isVerboseAsm) {
+  return new CSKYTargetAsmStreamer(S, OS);
+}
+
+static MCTargetStreamer *createCSKYNullTargetStreamer(MCStreamer &S) {
+  return new CSKYTargetStreamer(S);
+}
+
 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeCSKYTargetMC() {
   auto &CSKYTarget = getTheCSKYTarget();
   TargetRegistry::RegisterMCAsmBackend(CSKYTarget, createCSKYAsmBackend);
@@ -83,4 +117,12 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeCSKYTargetMC() {
   TargetRegistry::RegisterMCInstPrinter(CSKYTarget, createCSKYMCInstPrinter);
   TargetRegistry::RegisterMCSubtargetInfo(CSKYTarget,
                                           createCSKYMCSubtargetInfo);
+  TargetRegistry::RegisterELFStreamer(CSKYTarget, createELFStreamer);
+  TargetRegistry::RegisterObjectTargetStreamer(CSKYTarget,
+                                               createCSKYObjectTargetStreamer);
+  TargetRegistry::RegisterAsmTargetStreamer(CSKYTarget,
+                                            createCSKYAsmTargetStreamer);
+  // Register the null target streamer.
+  TargetRegistry::RegisterNullTargetStreamer(CSKYTarget,
+                                             createCSKYNullTargetStreamer);
 }

diff  --git a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCTargetDesc.h b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCTargetDesc.h
index 04949126ef4bc..4b8c45e95b74b 100644
--- a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCTargetDesc.h
+++ b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCTargetDesc.h
@@ -34,8 +34,7 @@ MCAsmBackend *createCSKYAsmBackend(const Target &T, const MCSubtargetInfo &STI,
                                    const MCRegisterInfo &MRI,
                                    const MCTargetOptions &Options);
 
-MCCodeEmitter *createCSKYMCCodeEmitter(const MCInstrInfo &MCII,
-                                       MCContext &Ctx);
+MCCodeEmitter *createCSKYMCCodeEmitter(const MCInstrInfo &MCII, MCContext &Ctx);
 } // namespace llvm
 
 #define GET_REGINFO_ENUM

diff  --git a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYTargetStreamer.cpp b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYTargetStreamer.cpp
new file mode 100644
index 0000000000000..bc12dc7b7ff98
--- /dev/null
+++ b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYTargetStreamer.cpp
@@ -0,0 +1,142 @@
+//===-- CSKYTargetStreamer.h - CSKY Target Streamer ----------*- C++ -*----===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "CSKYTargetStreamer.h"
+#include "CSKYSubtarget.h"
+#include "llvm/CodeGen/TargetSubtargetInfo.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCSectionELF.h"
+#include "llvm/Support/FormattedStream.h"
+
+using namespace llvm;
+
+//
+// ConstantPool implementation
+//
+// Emit the contents of the constant pool using the provided streamer.
+void CSKYConstantPool::emitAll(MCStreamer &Streamer) {
+  if (Entries.empty())
+    return;
+
+  if (CurrentSection != nullptr)
+    Streamer.SwitchSection(CurrentSection);
+
+  Streamer.emitDataRegion(MCDR_DataRegion);
+  for (const ConstantPoolEntry &Entry : Entries) {
+    Streamer.emitCodeAlignment(
+        Entry.Size,
+        Streamer.getContext().getSubtargetInfo()); // align naturally
+    Streamer.emitLabel(Entry.Label);
+    Streamer.emitValue(Entry.Value, Entry.Size, Entry.Loc);
+  }
+  Streamer.emitDataRegion(MCDR_DataRegionEnd);
+  Entries.clear();
+}
+
+const MCExpr *CSKYConstantPool::addEntry(MCStreamer &Streamer,
+                                         const MCExpr *Value, unsigned Size,
+                                         SMLoc Loc, const MCExpr *AdjustExpr) {
+  if (CurrentSection == nullptr)
+    CurrentSection = Streamer.getCurrentSectionOnly();
+
+  auto &Context = Streamer.getContext();
+
+  const MCConstantExpr *C = dyn_cast<MCConstantExpr>(Value);
+
+  // Check if there is existing entry for the same constant. If so, reuse it.
+  auto Itr = C ? CachedEntries.find(C->getValue()) : CachedEntries.end();
+  if (Itr != CachedEntries.end())
+    return Itr->second;
+
+  MCSymbol *CPEntryLabel = Context.createTempSymbol();
+  const auto SymRef = MCSymbolRefExpr::create(CPEntryLabel, Context);
+
+  if (AdjustExpr) {
+    const CSKYMCExpr *CSKYExpr = cast<CSKYMCExpr>(Value);
+
+    Value = MCBinaryExpr::createSub(AdjustExpr, SymRef, Context);
+    Value = MCBinaryExpr::createSub(CSKYExpr->getSubExpr(), Value, Context);
+    Value = CSKYMCExpr::create(Value, CSKYExpr->getKind(), Context);
+  }
+
+  Entries.push_back(ConstantPoolEntry(CPEntryLabel, Value, Size, Loc));
+
+  if (C)
+    CachedEntries[C->getValue()] = SymRef;
+  return SymRef;
+}
+
+bool CSKYConstantPool::empty() { return Entries.empty(); }
+
+void CSKYConstantPool::clearCache() {
+  CurrentSection = nullptr;
+  CachedEntries.clear();
+}
+
+CSKYTargetStreamer::CSKYTargetStreamer(MCStreamer &S)
+    : MCTargetStreamer(S), ConstantPool(new CSKYConstantPool()) {}
+
+const MCExpr *
+CSKYTargetStreamer::addConstantPoolEntry(const MCExpr *Expr, SMLoc Loc,
+                                         const MCExpr *AdjustExpr) {
+  auto ELFRefKind = CSKYMCExpr::VK_CSKY_Invalid;
+  ConstantCounter++;
+
+  const MCExpr *OrigExpr = Expr;
+
+  if (const CSKYMCExpr *CE = dyn_cast<CSKYMCExpr>(Expr)) {
+    Expr = CE->getSubExpr();
+    ELFRefKind = CE->getKind();
+  }
+
+  if (const MCSymbolRefExpr *SymExpr = dyn_cast<MCSymbolRefExpr>(Expr)) {
+    const MCSymbol *Sym = &SymExpr->getSymbol();
+
+    SymbolIndex Index = {Sym, ELFRefKind};
+
+    if (ConstantMap.find(Index) == ConstantMap.end()) {
+      ConstantMap[Index] =
+          ConstantPool->addEntry(getStreamer(), OrigExpr, 4, Loc, AdjustExpr);
+    }
+    return ConstantMap[Index];
+  }
+
+  return ConstantPool->addEntry(getStreamer(), Expr, 4, Loc, AdjustExpr);
+}
+
+void CSKYTargetStreamer::emitCurrentConstantPool() {
+  ConstantPool->emitAll(Streamer);
+  ConstantPool->clearCache();
+}
+
+// finish() - write out any non-empty assembler constant pools.
+void CSKYTargetStreamer::finish() {
+  if (ConstantCounter != 0) {
+    ConstantPool->emitAll(Streamer);
+  }
+
+  finishAttributeSection();
+}
+
+void CSKYTargetStreamer::emitTargetAttributes(const MCSubtargetInfo &STI) {}
+
+void CSKYTargetStreamer::emitAttribute(unsigned Attribute, unsigned Value) {}
+void CSKYTargetStreamer::emitTextAttribute(unsigned Attribute,
+                                           StringRef String) {}
+void CSKYTargetStreamer::finishAttributeSection() {}
+
+void CSKYTargetAsmStreamer::emitAttribute(unsigned Attribute, unsigned Value) {
+  OS << "\t.csky_attribute\t" << Attribute << ", " << Twine(Value) << "\n";
+}
+
+void CSKYTargetAsmStreamer::emitTextAttribute(unsigned Attribute,
+                                              StringRef String) {
+  OS << "\t.csky_attribute\t" << Attribute << ", \"" << String << "\"\n";
+}
+
+void CSKYTargetAsmStreamer::finishAttributeSection() {}

diff  --git a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYTargetStreamer.h b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYTargetStreamer.h
new file mode 100644
index 0000000000000..270d48d5939c7
--- /dev/null
+++ b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYTargetStreamer.h
@@ -0,0 +1,110 @@
+//===-- CSKYTargetStreamer.h - CSKY Target Streamer ----------*- C++ -*----===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_CSKY_CSKYTARGETSTREAMER_H
+#define LLVM_LIB_TARGET_CSKY_CSKYTARGETSTREAMER_H
+
+#include "MCTargetDesc/CSKYMCExpr.h"
+#include "llvm/MC/ConstantPools.h"
+#include "llvm/MC/MCStreamer.h"
+
+namespace llvm {
+
+class CSKYConstantPool {
+  using EntryVecTy = SmallVector<ConstantPoolEntry, 4>;
+  EntryVecTy Entries;
+  std::map<int64_t, const MCSymbolRefExpr *> CachedEntries;
+
+  MCSection *CurrentSection = nullptr;
+
+public:
+  // Initialize a new empty constant pool
+  CSKYConstantPool() = default;
+
+  // Add a new entry to the constant pool in the next slot.
+  // \param Value is the new entry to put in the constant pool.
+  // \param Size is the size in bytes of the entry
+  //
+  // \returns a MCExpr that references the newly inserted value
+  const MCExpr *addEntry(MCStreamer &Streamer, const MCExpr *Value,
+                         unsigned Size, SMLoc Loc, const MCExpr *AdjustExpr);
+
+  void emitAll(MCStreamer &Streamer);
+
+  // Return true if the constant pool is empty
+  bool empty();
+
+  void clearCache();
+};
+
+class CSKYTargetStreamer : public MCTargetStreamer {
+public:
+  typedef struct {
+    const MCSymbol *sym;
+    CSKYMCExpr::VariantKind kind;
+  } SymbolIndex;
+
+protected:
+  std::unique_ptr<CSKYConstantPool> ConstantPool;
+
+  DenseMap<SymbolIndex, const MCExpr *> ConstantMap;
+
+  unsigned ConstantCounter = 0;
+
+public:
+  CSKYTargetStreamer(MCStreamer &S);
+
+  virtual void emitTextAttribute(unsigned Attribute, StringRef String);
+  virtual void emitAttribute(unsigned Attribute, unsigned Value);
+  virtual void finishAttributeSection();
+
+  virtual void emitTargetAttributes(const MCSubtargetInfo &STI);
+  /// Add a new entry to the constant pool for the current section and return an
+  /// MCExpr that can be used to refer to the constant pool location.
+  const MCExpr *addConstantPoolEntry(const MCExpr *, SMLoc Loc,
+                                     const MCExpr *AdjustExpr = nullptr);
+
+  void emitCurrentConstantPool();
+
+  void finish() override;
+};
+
+template <> struct DenseMapInfo<CSKYTargetStreamer::SymbolIndex> {
+  static inline CSKYTargetStreamer::SymbolIndex getEmptyKey() {
+    return {nullptr, CSKYMCExpr::VK_CSKY_Invalid};
+  }
+  static inline CSKYTargetStreamer::SymbolIndex getTombstoneKey() {
+    return {nullptr, CSKYMCExpr::VK_CSKY_Invalid};
+  }
+  static unsigned getHashValue(const CSKYTargetStreamer::SymbolIndex &V) {
+    return hash_combine(DenseMapInfo<const MCSymbol *>::getHashValue(V.sym),
+                        DenseMapInfo<int>::getHashValue(V.kind));
+  }
+  static bool isEqual(const CSKYTargetStreamer::SymbolIndex &A,
+                      const CSKYTargetStreamer::SymbolIndex &B) {
+    return A.sym == B.sym && A.kind == B.kind;
+  }
+};
+
+class formatted_raw_ostream;
+
+class CSKYTargetAsmStreamer : public CSKYTargetStreamer {
+  formatted_raw_ostream &OS;
+
+  void emitAttribute(unsigned Attribute, unsigned Value) override;
+  void emitTextAttribute(unsigned Attribute, StringRef String) override;
+  void finishAttributeSection() override;
+
+public:
+  CSKYTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS)
+      : CSKYTargetStreamer(S), OS(OS) {}
+};
+
+} // namespace llvm
+
+#endif // LLVM_LIB_TARGET_CSKY_CSKYTARGETSTREAMER_H

diff  --git a/llvm/test/MC/CSKY/attribute.s b/llvm/test/MC/CSKY/attribute.s
new file mode 100644
index 0000000000000..39ba477314ce9
--- /dev/null
+++ b/llvm/test/MC/CSKY/attribute.s
@@ -0,0 +1,42 @@
+## Test llvm-mc could handle .attribute correctly.
+
+# RUN: llvm-mc %s -triple=csky -filetype=asm | FileCheck %s
+
+.csky_attribute CSKY_ARCH_NAME, "ck810"
+# CHECK: attribute      4, "ck810"
+
+.csky_attribute CSKY_CPU_NAME, "ck810"
+# CHECK: attribute      5, "ck810"
+
+.csky_attribute CSKY_ISA_FLAGS, 0x333f
+# CHECK: attribute      6, 13119 
+
+.csky_attribute CSKY_ISA_EXT_FLAGS, 0x333f
+# CHECK: attribute      7, 13119 
+
+.csky_attribute CSKY_DSP_VERSION, 1
+# CHECK: attribute      8, 1 
+
+.csky_attribute CSKY_VDSP_VERSION, 1
+# CHECK: attribute      9, 1 
+
+.csky_attribute CSKY_FPU_VERSION, 1
+# CHECK: attribute      16, 1 
+
+.csky_attribute CSKY_FPU_ABI, 1
+# CHECK: attribute      17, 1 
+
+.csky_attribute CSKY_FPU_ROUNDING, 1
+# CHECK: attribute      18, 1 
+
+.csky_attribute CSKY_FPU_DENORMAL, 1
+# CHECK: attribute      19, 1 
+
+.csky_attribute CSKY_FPU_EXCEPTION, 1
+# CHECK: attribute      20, 1 
+
+.csky_attribute CSKY_FPU_NUMBER_MODULE, "IEEE 754"
+# CHECK: attribute      21, "IEEE 754"
+
+.csky_attribute CSKY_FPU_HARDFP, 1
+# CHECK: attribute      22, 1 

diff  --git a/llvm/test/MC/CSKY/invalid-attribute.s b/llvm/test/MC/CSKY/invalid-attribute.s
new file mode 100644
index 0000000000000..a6558e75f82a1
--- /dev/null
+++ b/llvm/test/MC/CSKY/invalid-attribute.s
@@ -0,0 +1,39 @@
+## Negative tests:
+##  - Feed integer value to string type attribute.
+##  - Feed string value to integer type attribute.
+##  - Invalid arch string.
+
+# RUN: not llvm-mc %s -triple=csky -filetype=asm 2>&1 | FileCheck %s
+
+.csky_attribute CSKY_ARCH_NAME, "foo"
+# CHECK: [[@LINE-1]]:33: error: unknown arch name 
+
+.csky_attribute CSKY_CPU_NAME, "foo"
+# CHECK: [[@LINE-1]]:32: error: unknown cpu name
+
+.csky_attribute CSKY_DSP_VERSION, "1"
+# CHECK: [[@LINE-1]]:35: error: expected numeric constant
+
+.csky_attribute CSKY_VDSP_VERSION, "1"
+# CHECK: [[@LINE-1]]:36: error: expected numeric constant
+
+.csky_attribute CSKY_FPU_VERSION, "1"
+# CHECK: [[@LINE-1]]:35: error: expected numeric constant
+
+.csky_attribute CSKY_FPU_ABI, "1"
+# CHECK: [[@LINE-1]]:31: error: expected numeric constant
+
+.csky_attribute CSKY_FPU_ROUNDING, "1"
+# CHECK: [[@LINE-1]]:36: error: expected numeric constant
+
+.csky_attribute CSKY_FPU_DENORMAL, "1"
+# CHECK: [[@LINE-1]]:36: error: expected numeric constant
+
+.csky_attribute CSKY_FPU_EXCEPTION, "1"
+# CHECK: [[@LINE-1]]:37: error: expected numeric constant
+
+.csky_attribute CSKY_FPU_NUMBER_MODULE, 4
+# CHECK: [[@LINE-1]]:41: error: expected string constant
+
+.csky_attribute CSKY_FPU_HARDFP, "1"
+# CHECK: [[@LINE-1]]:34: error: expected numeric constant


        


More information about the llvm-commits mailing list