text: /*========================== begin_copyright_notice ============================
  
  Copyright (C) 2017-2021 Intel Corporation
  
  SPDX-License-Identifier: MIT
  
  ============================= end_copyright_notice ===========================*/
  
  /*========================== begin_copyright_notice ============================
  
  This file is distributed under the University of Illinois Open Source License.
  See LICENSE.TXT for details.
  
  ============================= end_copyright_notice ===========================*/
  
  #include "llvm/Config/llvm-config.h"
  #include "common/LLVMWarningsPush.hpp"
  #include "llvm/IR/DataLayout.h"
  #include "llvm/IR/GlobalValue.h"
  #include "llvm/MC/MCAsmBackend.h"
  #include "llvmWrapper/ADT/STLExtras.h"
  #include "llvm/MC/MCAsmInfoELF.h"
  #include "llvm/MC/MCCodeEmitter.h"
  #include "llvm/MC/MCContext.h"
  #include "llvm/MC/MCExpr.h"
  #include "llvm/MC/MCELFObjectWriter.h"
  #include "llvm/MC/MCObjectFileInfo.h"
  #include "llvm/MC/MCObjectWriter.h"
  #include "llvm/MC/MCRegisterInfo.h"
  #include "llvm/MC/MCSection.h"
  #include "llvm/MC/MCStreamer.h"
  #include "llvm/MC/MCSymbol.h"
  #include "llvm/MC/MCValue.h"
  #include "llvm/Support/TargetRegistry.h"
  #include "llvm/Support/SourceMgr.h"
  #include "common/LLVMWarningsPop.hpp"
  
  #include "DIE.hpp"
  #include "StreamEmitter.hpp"
  #include "DwarfDebug.hpp"
  
  #include "Probe/Assertion.h"
  
  #define DEBUG_TYPE "dwarfdebug"
  
  using namespace llvm;
  using namespace IGC;
  
  namespace IGC
  {
      ///////////////////////////////////////////////////////////////////////////////
      // Following classes extend abstract MC classes.
      // These classes are needed to create concrete instance of MCStreamer.
      ///////////////////////////////////////////////////////////////////////////////
  
      class VISAMCAsmInfo : public MCAsmInfoELF
      {
      public:
          VISAMCAsmInfo(unsigned int pointerSize) : MCAsmInfoELF()
          {
              DwarfUsesRelocationsAcrossSections = true;
              CodePointerSize = pointerSize;
          }
      };
  
      class VISAELFObjectWriter : public MCELFObjectTargetWriter
      {
      public:
          VISAELFObjectWriter(bool is64Bit, uint8_t osABI,
              uint16_t eMachine, bool hasRelocationAddend) :
              MCELFObjectTargetWriter(is64Bit, osABI, eMachine, hasRelocationAddend)
          {
          }
  
          unsigned getRelocType(MCContext& Ctx, const MCValue& Target,
              const MCFixup& Fixup, bool IsPCRel) const {
              MCSymbolRefExpr::VariantKind modifier = Target.isAbsolute() ?
                  MCSymbolRefExpr::VK_None : Target.getSymA()->getKind();
              unsigned type = ELF::R_X86_64_NONE;
              if (is64Bit())
              {
                  if (IsPCRel)
                  {
                      switch ((unsigned)Fixup.getKind())
                      {
                      default: IGC_ASSERT_EXIT_MESSAGE(0, "invalid fixup kind!");
  
                      case FK_Data_8: type = ELF::R_X86_64_PC64; break;
                      case FK_Data_4: type = ELF::R_X86_64_PC32; break;
                      case FK_Data_2: type = ELF::R_X86_64_PC16; break;
  
                      case FK_PCRel_8:
                          IGC_ASSERT(modifier == MCSymbolRefExpr::VK_None);
                          type = ELF::R_X86_64_PC64;
                          break;
                      case FK_PCRel_4:
                          switch (modifier)
                          {
                          default:
                              IGC_ASSERT_EXIT_MESSAGE(0, "Unimplemented");
                          case MCSymbolRefExpr::VK_None:
                              type = ELF::R_X86_64_PC32;
                              break;
                          case MCSymbolRefExpr::VK_PLT:
                              type = ELF::R_X86_64_PLT32;
                              break;
                          case MCSymbolRefExpr::VK_GOTPCREL:
                              type = ELF::R_X86_64_GOTPCREL;
                              break;
                          case MCSymbolRefExpr::VK_GOTTPOFF:
                              type = ELF::R_X86_64_GOTTPOFF;
                              break;
                          case MCSymbolRefExpr::VK_TLSGD:
                              type = ELF::R_X86_64_TLSGD;
                              break;
                          case MCSymbolRefExpr::VK_TLSLD:
                              type = ELF::R_X86_64_TLSLD;
                              break;
                          }
                          break;
                      case FK_PCRel_2:
                          IGC_ASSERT(modifier == MCSymbolRefExpr::VK_None);
                          type = ELF::R_X86_64_PC16;
                          break;
                      case FK_PCRel_1:
                          IGC_ASSERT(modifier == MCSymbolRefExpr::VK_None);
                          type = ELF::R_X86_64_PC8;
                          break;
                      }
                  }
                  else
                  {
                      switch ((unsigned)Fixup.getKind())
                      {
                      default: IGC_ASSERT_EXIT_MESSAGE(0, "invalid fixup kind!");
                      case FK_Data_8:
                          switch (modifier)
                          {
                          default:
                              IGC_ASSERT_EXIT_MESSAGE(0, "Unimplemented");
                          case MCSymbolRefExpr::VK_None:
                              type = ELF::R_X86_64_64;
                              break;
                          case MCSymbolRefExpr::VK_GOT:
                              type = ELF::R_X86_64_GOT64;
                              break;
                          case MCSymbolRefExpr::VK_GOTOFF:
                              type = ELF::R_X86_64_GOTOFF64;
                              break;
                          case MCSymbolRefExpr::VK_TPOFF:
                              type = ELF::R_X86_64_TPOFF64;
                              break;
                          case MCSymbolRefExpr::VK_DTPOFF:
                              type = ELF::R_X86_64_DTPOFF64;
                              break;
                          }
                          break;
                      case FK_Data_4:
                          type = ELF::R_X86_64_32;
                          break;
                      case FK_Data_2: type = ELF::R_X86_64_16; break;
                      case FK_PCRel_1:
                      case FK_Data_1: type = ELF::R_X86_64_8; break;
                      }
                  }
              }
              else
              {
                  if (IsPCRel)
                  {
                      switch ((unsigned)Fixup.getKind())
                      {
                      default: IGC_ASSERT_EXIT_MESSAGE(0, "invalid fixup kind!");
  
                      case FK_PCRel_4:
                      case FK_Data_4:
                          switch (modifier)
                          {
                          default:
                              IGC_ASSERT_EXIT_MESSAGE(0, "Unimplemented");
                          case MCSymbolRefExpr::VK_None:
                              type = ELF::R_386_PC32;
                              break;
                          case MCSymbolRefExpr::VK_PLT:
                              type = ELF::R_386_PLT32;
                              break;
                          }
                          break;
                      }
                  }
                  else
                  {
                      switch ((unsigned)Fixup.getKind())
                      {
                      default: IGC_ASSERT_EXIT_MESSAGE(0, "invalid fixup kind!");
  
                      case FK_PCRel_4:
                      case FK_Data_4:
                          switch (modifier)
                          {
                          default:
                              IGC_ASSERT_EXIT_MESSAGE(0, "Unimplemented");
                          case MCSymbolRefExpr::VK_None:
                              type = ELF::R_386_32;
                              break;
                          case MCSymbolRefExpr::VK_GOT:
                              type = ELF::R_386_GOT32;
                              break;
                          case MCSymbolRefExpr::VK_GOTOFF:
                              type = ELF::R_386_GOTOFF;
                              break;
                          case MCSymbolRefExpr::VK_TLSGD:
                              type = ELF::R_386_TLS_GD;
                              break;
                          case MCSymbolRefExpr::VK_TPOFF:
                              type = ELF::R_386_TLS_LE_32;
                              break;
                          case MCSymbolRefExpr::VK_INDNTPOFF:
                              type = ELF::R_386_TLS_IE;
                              break;
                          case MCSymbolRefExpr::VK_NTPOFF:
                              type = ELF::R_386_TLS_LE;
                              break;
                          case MCSymbolRefExpr::VK_GOTNTPOFF:
                              type = ELF::R_386_TLS_GOTIE;
                              break;
                          case MCSymbolRefExpr::VK_TLSLDM:
                              type = ELF::R_386_TLS_LDM;
                              break;
                          case MCSymbolRefExpr::VK_DTPOFF:
                              type = ELF::R_386_TLS_LDO_32;
                              break;
                          case MCSymbolRefExpr::VK_GOTTPOFF:
                              type = ELF::R_386_TLS_IE_32;
                              break;
                          }
                          break;
                      case FK_Data_2: type = ELF::R_386_16; break;
                      case FK_PCRel_1:
                      case FK_Data_1: type = ELF::R_386_8; break;
                      }
                  }
              }
  
              return type;
          }
      };
  
      class VISAAsmBackend : public MCAsmBackend
      {
          StringRef m_targetTriple;
          bool m_is64Bit;
      public:
          VISAAsmBackend(StringRef targetTriple, bool is64Bit)
              : MCAsmBackend(support::endianness::little),
              m_targetTriple(targetTriple), m_is64Bit(is64Bit) {}
  
          unsigned getNumFixupKinds() const override
          {
              return 0;
          }
  
          static unsigned getFixupKindLog2Size(unsigned Kind)
          {
              switch (Kind)
              {
              default: IGC_ASSERT_EXIT_MESSAGE(0, "invalid fixup kind!");
              case FK_PCRel_1:
              case FK_SecRel_1:
              case FK_Data_1: return 0;
              case FK_PCRel_2:
              case FK_SecRel_2:
              case FK_Data_2: return 1;
              case FK_PCRel_4:
              case FK_SecRel_4:
              case FK_Data_4: return 2;
              case FK_PCRel_8:
              case FK_SecRel_8:
              case FK_Data_8: return 3;
              }
          }
  
          void applyFixup(const MCAssembler & Asm, const MCFixup & fixup,
                          const MCValue & Target, MutableArrayRef<char> Data,
                          uint64_t value, bool IsResolved,
                          const MCSubtargetInfo * STI) const override
          {
              unsigned size = 1 << getFixupKindLog2Size(fixup.getKind());
  
              IGC_ASSERT_MESSAGE(fixup.getOffset() + size <= Data.size(), "Invalid fixup offset!");
  
              // Check that uppper bits are either all zeros or all ones.
              // Specifically ignore overflow/underflow as long as the leakage is
              // limited to the lower bits. This is to remain compatible with
              // other assemblers.
              IGC_ASSERT_MESSAGE(isIntN(size * 8 + 1, value), "value does not fit in the fixup field");
  
              for (unsigned i = 0; i != size; ++i)
              {
                  Data[fixup.getOffset() + i] = uint8_t(value >> (i * 8));
              }
          }
  
          bool mayNeedRelaxation(const MCInst & inst, const MCSubtargetInfo & STI) const override
          {
              // TODO: implement this
              IGC_ASSERT_EXIT_MESSAGE(0, "Unimplemented");
              return false;
          }
  
          bool fixupNeedsRelaxation(const MCFixup& fixup,
              uint64_t value,
              const MCRelaxableFragment* pDF,
              const MCAsmLayout& layout) const override
          {
              // TODO: implement this
              IGC_ASSERT_EXIT_MESSAGE(0, "Unimplemented");
              return false;
          }
  
  #if LLVM_VERSION_MAJOR <= 10
          void relaxInstruction(const MCInst& inst, const MCSubtargetInfo& STI,
              MCInst& res) const override
          {
              // TODO: implement this
              IGC_ASSERT_EXIT_MESSAGE(0, "Unimplemented");
          }
  #endif
  
          bool writeNopData(raw_ostream & OS, uint64_t Count) const override
          {
              const char nop = (char)0x90;
              for (uint64_t i = 0; i < Count; ++i)
              {
                  OS.write(&nop, 1);
              }
              return true;
          }
  
          /// createObjectWriter - Create a new MCObjectWriter instance for use by the
          /// assembler backend to emit the final object file.
          std::unique_ptr<MCObjectWriter> createObjectWriter(llvm::raw_pwrite_stream & os) const
          {
              Triple triple(m_targetTriple);
              uint8_t osABI = MCELFObjectTargetWriter::getOSABI(triple.getOS());
              uint16_t eMachine = m_is64Bit ? ELF::EM_X86_64 : ELF::EM_386;
              // Only i386 uses Rel instead of RelA.
              bool hasRelocationAddend = eMachine != ELF::EM_386;
              std::unique_ptr<MCELFObjectTargetWriter> pMOTW
                  = IGCLLVM::make_unique<VISAELFObjectWriter>(m_is64Bit, osABI, eMachine, hasRelocationAddend);
              return createELFObjectWriter(std::move(pMOTW), os,  /*IsLittleEndian=*/true);
          }
  
          std::unique_ptr<MCObjectTargetWriter> createObjectTargetWriter() const override
          {
              // TODO: implement this
              IGC_ASSERT_EXIT_MESSAGE(0, "Unimplemented");
          }
      };
  
      class VISAMCCodeEmitter : public MCCodeEmitter
      {
          /// EncodeInstruction - Encode the given \p inst to bytes on the output
          /// stream \p OS.
          virtual void encodeInstruction(const MCInst& inst, raw_ostream& os, SmallVectorImpl<MCFixup>& fixups,
              const MCSubtargetInfo& m) const
          {
              // TODO: implement this
              IGC_ASSERT_EXIT_MESSAGE(0, "Unimplemented");
          }
  
          void operator=(const VISAMCCodeEmitter&)
          {
              // TODO: implement this
              IGC_ASSERT_EXIT_MESSAGE(0, "Unimplemented");
          }
  
      };
  
  } // namespace IGC
  
  StreamEmitter::StreamEmitter(raw_pwrite_stream& outStream,
                               const std::string& dataLayout,
                               const std::string& targetTriple,
                               const StreamEmitter::Settings &Options) :
      m_targetTriple(targetTriple), m_setCounter(0),
      StreamOptions(Options)
  {
      m_pDataLayout = new DataLayout(dataLayout);
      m_pSrcMgr = new SourceMgr();
      m_pAsmInfo = new VISAMCAsmInfo(GetPointerSize());
      m_pObjFileInfo = new IGCLLVM::MCObjectFileInfo();
  
      MCRegisterInfo* regInfo = nullptr;
      Triple triple = Triple(GetTargetTriple());
  
      // Create new MC context
      m_pContext = IGCLLVM::CreateMCContext(triple, (const llvm::MCAsmInfo*)m_pAsmInfo, regInfo, m_pObjFileInfo, m_pSrcMgr);
  
      m_pObjFileInfo->InitMCObjectFileInfo(triple, false, *m_pContext);
  
      bool is64Bit = GetPointerSize() == 8;
      uint8_t osABI = MCELFObjectTargetWriter::getOSABI(triple.getOS());
      // Earlier eMachine was set to ELF::EM_X86_64 or ELF::EM_386
      // This creates a problem for gdb so it is now set to 182
      // which is an encoding reserved for Intel. It is not part of
      // the enum so its value in inlined.
  #define EM_INTEL_GEN 182
      uint16_t eMachine = EM_INTEL_GEN;
      if (StreamOptions.EnforceAMD64Machine)
          eMachine = ELF::EM_X86_64;
      bool hasRelocationAddend = is64Bit;
      std::unique_ptr<MCAsmBackend> pAsmBackend
          = IGCLLVM::make_unique<VISAAsmBackend>(GetTargetTriple(), is64Bit);
      std::unique_ptr<MCELFObjectTargetWriter> pTargetObjectWriter
          = IGCLLVM::make_unique<VISAELFObjectWriter>(is64Bit, osABI, eMachine, hasRelocationAddend);
      std::unique_ptr<MCObjectWriter> pObjectWriter
          = createELFObjectWriter(std::move(pTargetObjectWriter), outStream, true);
      std::unique_ptr<MCCodeEmitter> pCodeEmitter
          = IGCLLVM::make_unique<VISAMCCodeEmitter>();
  
      bool isRelaxAll = false;
      bool isNoExecStack = false;
      m_pMCStreamer = createELFStreamer(*m_pContext,
          std::move(pAsmBackend), std::move(pObjectWriter), std::move(pCodeEmitter), isRelaxAll);
  
      m_pMCStreamer->InitSections(isNoExecStack);
  }
  
  StreamEmitter::~StreamEmitter()
  {
      delete m_pMCStreamer;
      delete m_pContext;
      delete m_pSrcMgr;
      delete m_pAsmInfo;
      delete m_pObjFileInfo;
      delete m_pDataLayout;
  }
  
  unsigned int StreamEmitter::GetPointerSize() const
  {
      return m_pDataLayout->getPointerSize();
  }
  
  bool StreamEmitter::IsLittleEndian() const
  {
      return m_pDataLayout->isLittleEndian();
  }
  
  const MCSection* StreamEmitter::GetTextSection() const
  {
      return GetObjFileLowering().getTextSection();
  }
  
  const MCSection* StreamEmitter::GetDataSection() const
  {
      return GetObjFileLowering().getDataSection();
  }
  
  const MCSection* StreamEmitter::GetDwarfAbbrevSection() const
  {
      return GetObjFileLowering().getDwarfAbbrevSection();
  }
  
  const MCSection* StreamEmitter::GetDwarfInfoSection() const
  {
      return GetObjFileLowering().getDwarfInfoSection();
  }
  
  const MCSection* StreamEmitter::GetDwarfLineSection() const
  {
      return GetObjFileLowering().getDwarfLineSection();
  }
  
  const MCSection* StreamEmitter::GetDwarfLocSection() const
  {
      return GetObjFileLowering().getDwarfLocSection();
  }
  
  const MCSection* StreamEmitter::GetDwarfMacroInfoSection() const
  {
      //return GetObjFileLowering().getDwarfMacroInfoSection();
      return nullptr;
  }
  
  const MCSection* StreamEmitter::GetDwarfRangesSection() const
  {
      return GetObjFileLowering().getDwarfRangesSection();
  }
  
  const MCSection* StreamEmitter::GetDwarfStrSection() const
  {
      return GetObjFileLowering().getDwarfStrSection();
  }
  
  const MCSection* StreamEmitter::GetDwarfFrameSection() const
  {
      return GetObjFileLowering().getDwarfFrameSection();
  }
  
  void StreamEmitter::SwitchSection(const MCSection* pSection, const MCExpr* pSubsection) const
  {
      m_pMCStreamer->SwitchSection(const_cast<MCSection*>(pSection), pSubsection);
  }
  
  MCSymbol* StreamEmitter::GetSymbol(const GlobalValue* pGV) const
  {
      /*
      //Original code (as reference)
      SmallString<60> NameStr;
      M.getNameWithPrefix(NameStr, pGV, false);
      return m_pContext->GetOrCreateSymbol(NameStr.str());
      */
      IGC_ASSERT_MESSAGE(pGV->hasName(), "TODO: fix this case");
      return m_pContext->getOrCreateSymbol(Twine(m_pAsmInfo->getPrivateGlobalPrefix()) + pGV->getName());
  }
  
  MCSymbol* StreamEmitter::GetTempSymbol(StringRef name, uint64_t id) const
  {
      return m_pContext->getOrCreateSymbol(Twine(m_pAsmInfo->getPrivateGlobalPrefix()) + name + Twine(id));
  }
  
  MCSymbol* StreamEmitter::GetTempSymbol(StringRef name) const
  {
      return m_pContext->getOrCreateSymbol(Twine(m_pAsmInfo->getPrivateGlobalPrefix()) + name);
  }
  
  MCSymbol* StreamEmitter::CreateTempSymbol() const
  {
      return m_pContext->createTempSymbol();
  }
  
  unsigned StreamEmitter::GetDwarfCompileUnitID() const
  {
      return m_pContext->getDwarfCompileUnitID();
  }
  
  void StreamEmitter::SetDwarfCompileUnitID(unsigned cuIndex) const
  {
      m_pContext->setDwarfCompileUnitID(cuIndex);
  }
  
  void StreamEmitter::EmitBytes(StringRef data, unsigned addrSpace) const
  {
  #if LLVM_VERSION_MAJOR <= 10
      m_pMCStreamer->EmitBytes(data);
  #else
      m_pMCStreamer->emitBytes(data);
  #endif
  }
  
  void StreamEmitter::EmitValue(const MCExpr* value, unsigned size, unsigned addrSpace) const
  {
  
  #if LLVM_VERSION_MAJOR <= 10
      m_pMCStreamer->EmitValue(value, size);
  #else
      m_pMCStreamer->emitValue(value, size);
  #endif
  }
  
  void StreamEmitter::EmitIntValue(uint64_t value, unsigned size, unsigned addrSpace) const
  {
  #if LLVM_VERSION_MAJOR <= 10
      m_pMCStreamer->EmitIntValue(value, size);
  #else
      m_pMCStreamer->emitIntValue(value, size);
  #endif
  }
  
  void StreamEmitter::EmitInt8(int value) const
  {
      EmitIntValue(value, 1);
  }
  
  void StreamEmitter::EmitInt16(int value) const
  {
      EmitIntValue(value, 2);
  }
  
  void StreamEmitter::EmitInt32(int value) const
  {
      EmitIntValue(value, 4);
  }
  
  void StreamEmitter::EmitSLEB128(int64_t value, const char* /*desc*/) const
  {
  #if LLVM_VERSION_MAJOR <= 10
      m_pMCStreamer->EmitSLEB128IntValue(value);
  #else
      m_pMCStreamer->emitSLEB128IntValue(value);
  #endif
  }
  
  void StreamEmitter::EmitULEB128(uint64_t value, llvm::StringRef /*desc*/, unsigned padTo) const
  {
  #if LLVM_VERSION_MAJOR <= 10
          m_pMCStreamer->EmitULEB128IntValue(value);
  #else
          m_pMCStreamer->emitULEB128IntValue(value);
  #endif
  }
  
  void StreamEmitter::EmitLabel(MCSymbol* pLabel) const
  {
  #if LLVM_VERSION_MAJOR <= 10
          m_pMCStreamer->EmitLabel(pLabel);
  #else
          m_pMCStreamer->emitLabel(pLabel);
  #endif
  }
  
  void StreamEmitter::EmitLabelDifference(const MCSymbol* pHi, const MCSymbol* pLo, unsigned size) const
  {
      const MCExpr* hiExpr = MCSymbolRefExpr::create(pHi, *m_pContext);
      const MCExpr* loExpr = MCSymbolRefExpr::create(pLo, *m_pContext);
  
      // Get the pHi-pLo expression.
      const MCExpr* pDiff = MCBinaryExpr::createSub(hiExpr, loExpr, *m_pContext);
  
      if (!m_pAsmInfo->doesSetDirectiveSuppressReloc())
      {
  #if LLVM_VERSION_MAJOR <= 10
          m_pMCStreamer->EmitValue(pDiff, size);
  #else
          m_pMCStreamer->emitValue(pDiff, size);
  #endif
          return;
      }
  
      // Otherwise, emit with .set (aka assignment).
      MCSymbol* pSetLabel = GetTempSymbol("set", m_setCounter++);
  
  #if LLVM_VERSION_MAJOR <= 10
      m_pMCStreamer->EmitAssignment(pSetLabel, pDiff);
  #else
      m_pMCStreamer->emitAssignment(pSetLabel, pDiff);
  #endif
  
  #if LLVM_VERSION_MAJOR <= 10
          m_pMCStreamer->EmitSymbolValue(pSetLabel, size);
  #else
          m_pMCStreamer->emitSymbolValue(pSetLabel, size);
  #endif
  }
  
  void StreamEmitter::EmitLabelOffsetDifference(const MCSymbol* pHi, uint64_t Offset, const MCSymbol* pLo, unsigned size) const
  {
      const MCExpr* pHiExpr = MCSymbolRefExpr::create(pHi, *m_pContext);
      const MCExpr* pLoExpr = MCSymbolRefExpr::create(pLo, *m_pContext);
      const MCExpr* pOffsetExpr = MCConstantExpr::create(Offset, *m_pContext);
  
      // Emit pHi+Offset - pLo
      // Get the pHi+Offset expression.
      const MCExpr* pPlus = MCBinaryExpr::createAdd(pHiExpr, pOffsetExpr, *m_pContext);
  
      // Get the pHi+Offset-pLo expression.
      const MCExpr* pDiff = MCBinaryExpr::createSub(pPlus, pLoExpr, *m_pContext);
  
      if (!m_pAsmInfo->doesSetDirectiveSuppressReloc())
      {
  #if LLVM_VERSION_MAJOR <= 10
          m_pMCStreamer->EmitValue(pDiff, size);
  #else
          m_pMCStreamer->emitValue(pDiff, size);
  #endif
          return;
      }
      // Otherwise, emit with .set (aka assignment).
      MCSymbol* pSetLabel = GetTempSymbol("set", m_setCounter++);
  
  #if LLVM_VERSION_MAJOR <= 10
      m_pMCStreamer->EmitAssignment(pSetLabel, pDiff);
  #else
      m_pMCStreamer->emitAssignment(pSetLabel, pDiff);
  #endif
  
  #if LLVM_VERSION_MAJOR <= 10
      m_pMCStreamer->EmitSymbolValue(pSetLabel, size);
  #else
      m_pMCStreamer->emitSymbolValue(pSetLabel, size);
  #endif
  }
  
  void StreamEmitter::EmitLabelPlusOffset(const MCSymbol* pLabel, uint64_t Offset, unsigned size, bool /*isSectionRelative*/) const
  {
      // Emit pLabel+Offset (or just pLabel if Offset is zero)
      const MCExpr* pLabelExpr = MCSymbolRefExpr::create(pLabel, *m_pContext);
      const MCExpr* pOffsetExpr = MCConstantExpr::create(Offset, *m_pContext);
  
      const MCExpr* pExpr = (Offset) ? MCBinaryExpr::createAdd(pLabelExpr, pOffsetExpr, *m_pContext) : pLabelExpr;
  
  #if LLVM_VERSION_MAJOR <= 10
      m_pMCStreamer->EmitValue(pExpr, size);
  #else
      m_pMCStreamer->emitValue(pExpr, size);
  #endif
  }
  
  void StreamEmitter::EmitLabelReference(const MCSymbol* pLabel, unsigned size, bool isSectionRelative) const
  {
      EmitLabelPlusOffset(pLabel, 0, size, isSectionRelative);
  }
  
  void StreamEmitter::EmitELFDiffSize(MCSymbol* pLabel, const MCSymbol* pHi, const MCSymbol* pLo) const
  {
      const MCExpr* hiExpr = MCSymbolRefExpr::create(pHi, *m_pContext);
      const MCExpr* loExpr = MCSymbolRefExpr::create(pLo, *m_pContext);
  
      // Get the pHi-pLo expression.
      const MCExpr* pDiff = MCBinaryExpr::createSub(hiExpr, loExpr, *m_pContext);
  
      m_pMCStreamer->emitELFSize(pLabel, pDiff);
  }
  
  void StreamEmitter::EmitSymbolValue(const MCSymbol* pSym, unsigned size, unsigned addrSpace) const
  {
  #if LLVM_VERSION_MAJOR <= 10
      m_pMCStreamer->EmitSymbolValue(pSym, size);
  #else
      m_pMCStreamer->emitSymbolValue(pSym, size);
  #endif
  }
  
  void StreamEmitter::EmitSectionOffset(const MCSymbol* pLabel, const MCSymbol* pSectionLabel) const
  {
      // Get the section that we're referring to, based on pSectionLabel.
      const MCSection& section = pSectionLabel->getSection();
  
      // If pLabel has already been emitted, verify that it is in the same section as
      // section label for sanity.
      IGC_ASSERT_MESSAGE((!pLabel->isInSection() || &pLabel->getSection() == &section), "section offset using wrong section base for label");
  
      // If the section in question will end up with an address of 0 anyway, we can
      // just emit an absolute reference to save a relocation.
  #if 0
      if (section.isBaseAddressKnownZero())
      {
          m_pMCStreamer->EmitSymbolValue(pLabel, 4);
          return;
      }
  #endif
  
      // Otherwise, emit it as a label difference from the start of the section.
      EmitLabelDifference(pLabel, pSectionLabel, 4);
  }
  
  void StreamEmitter::EmitDwarfRegOp(unsigned reg, unsigned offset, bool indirect) const
  {
      auto regEncoded = GetEncodedRegNum<RegisterNumbering::GRFBase>(reg);
      if (indirect)
      {
          if (regEncoded < 32)
          {
              EmitInt8(dwarf::DW_OP_breg0 + regEncoded);
          }
          else
          {
              // Emit ("DW_OP_bregx");
              EmitInt8(dwarf::DW_OP_bregx);
              EmitULEB128(regEncoded);
          }
          EmitSLEB128(offset);
      }
      else
      {
          if (regEncoded < 32)
          {
              EmitInt8(dwarf::DW_OP_reg0 + regEncoded);
          }
          else
          {
              // Emit ("DW_OP_regx");
              EmitInt8(dwarf::DW_OP_regx);
              EmitULEB128(regEncoded);
          }
      }
  }
  
  bool StreamEmitter::EmitDwarfFileDirective(unsigned fileNo, StringRef directory, StringRef filename, unsigned cuID) const
  {
  #if LLVM_VERSION_MAJOR <= 10
      return (m_pMCStreamer->EmitDwarfFileDirective(fileNo, directory, filename, llvm::None, llvm::None, cuID) != 0);
  #else
      return (m_pMCStreamer->emitDwarfFileDirective(fileNo, directory, filename, llvm::None, llvm::None, cuID) != 0);
  #endif
  }
  
  void StreamEmitter::EmitDwarfLocDirective(unsigned fileNo, unsigned line, unsigned column, unsigned flags,
      unsigned isa, unsigned discriminator, StringRef fileName) const
  {
  #if LLVM_VERSION_MAJOR <= 10
      m_pMCStreamer->EmitDwarfLocDirective(fileNo, line, column, flags, isa, discriminator, fileName);
  #else
      m_pMCStreamer->emitDwarfLocDirective(fileNo, line, column, flags, isa, discriminator, fileName);
  #endif
  }
  
  void StreamEmitter::SetMCLineTableSymbol(MCSymbol* pSym, unsigned id) const
  {
      //    m_pContext->setMCLineTableSymbol(pSym, id);
  }
  
  void StreamEmitter::Finalize() const
  {
      m_pMCStreamer->Finish();
      m_pMCStreamer->reset();
  }
  
  const MCObjectFileInfo& StreamEmitter::GetObjFileLowering() const
  {
      IGC_ASSERT_MESSAGE(m_pObjFileInfo, "Object File Lowering was not initialized");
      return *m_pObjFileInfo;
  }
  
  void StreamEmitter::verifyRegisterLocationSize(const IGC::DbgVariable& VarVal,
                                                 const IGC::DwarfDebug& DD,
                                                 unsigned MaxGRFSpaceInBits,
                                                 uint64_t ExpectedSize)
  {
      if (!GetEmitterSettings().EnableDebugInfoValidation)
          return;
  
      auto* DbgInst = VarVal.getDbgInst();
      IGC_ASSERT(DbgInst);
      Value* IRLoc = IGCLLVM::getVariableLocation(DbgInst);
      auto* Ty = IRLoc->getType();
      IGC_ASSERT(Ty->isSingleValueType());
  
      if (Ty->isPointerTy())
          return; // no validation for pointers (for now)
  
      auto* Expr = DbgInst->getExpression();
      if (Expr->isFragment() || Expr->isImplicit())
      {
          // TODO: implement some sanity checks
          return;
      }
      DiagnosticBuff Diag;
      auto DwarfTypeSize = VarVal.getBasicSize(&DD);
      if (DwarfTypeSize != ExpectedSize) {
          Diag.out() << "ValidationFailure [regLocSize] -- DWARF Type Size: " <<
              DwarfTypeSize << ", expected: " << ExpectedSize << "\n";
      }
      if (ExpectedSize > MaxGRFSpaceInBits) {
          Diag.out() << "ValidationFailure [GRFSpace] -- Available GRF space: " <<
              MaxGRFSpaceInBits << ", while expected value size: " <<
              ExpectedSize << "\n";
      }
  
      // Dump DbgVariable if errors were reported
      verificationReport(VarVal, Diag);
  }
  
  void StreamEmitter::verifyRegisterLocationExpr(const DbgVariable& DV,
                                                 const DwarfDebug& DD)
  {
      if (!GetEmitterSettings().EnableDebugInfoValidation)
          return;
  
      // TODO: add checks for locations other than llvm.dbg.value
      if (DV.currentLocationIsMemoryAddress())
          return;
  
      auto* DbgInst = DV.getDbgInst();
      if (!isa<llvm::DbgValueInst>(DbgInst))
          return;
  
      DiagnosticBuff Diag;
      if (!DV.currentLocationIsImplicit() &&
          !DV.currentLocationIsSimpleIndirectValue())
      {
          if (DbgInst->getExpression()->isComplex())
          {
              Diag.out() << "ValidationFailure [UnexpectedComlexExpression]" <<
                 " for a simple register location\n";
          }
      }
      verificationReport(DV, Diag);
  }
  
  void StreamEmitter::reportUsabilityIssue(llvm::StringRef Msg,
                                           const llvm::Value* Ctx)
  {
      if (!GetEmitterSettings().EnableDebugInfoValidation)
          return;
  
      DiagnosticBuff Diag;
      Diag.out() << "ValidationFailure [UsabilityIssue] " <<
          Msg << "\n";
  
      if (Ctx)
      {
          Ctx->print(Diag.out());
          Diag.out() << "\n";
      }
  
      verificationReport(Diag);
  }
  
  void StreamEmitter::verificationReport(const DbgVariable& VarVal,
                                         DiagnosticBuff& Diag)
  {
      if (Diag.out().tell() == 0)
          return;
  
      VarVal.print(Diag.out());
      Diag.out() << "==============\n";
  
      verificationReport(Diag);
  }
  
  void StreamEmitter::verificationReport(DiagnosticBuff& Diag)
  {
      if (Diag.out().tell() == 0)
          return;
  
      const auto& ErrMsg = Diag.out().str();
  
      ErrorLog.append(ErrMsg);
      LLVM_DEBUG(dbgs() << ErrMsg);
  }
  
  