diff --git a/llvm/include/llvm/ADT/Triple.h b/llvm/include/llvm/ADT/Triple.h --- a/llvm/include/llvm/ADT/Triple.h +++ b/llvm/include/llvm/ADT/Triple.h @@ -266,6 +266,7 @@ ELF, GOFF, MachO, + SPIRV, Wasm, XCOFF, }; diff --git a/llvm/include/llvm/MC/MCContext.h b/llvm/include/llvm/MC/MCContext.h --- a/llvm/include/llvm/MC/MCContext.h +++ b/llvm/include/llvm/MC/MCContext.h @@ -52,6 +52,7 @@ class MCSectionELF; class MCSectionGOFF; class MCSectionMachO; +class MCSectionSPIRV; class MCSectionWasm; class MCSectionXCOFF; class MCStreamer; @@ -81,6 +82,7 @@ IsELF, IsGOFF, IsCOFF, + IsSPIRV, IsWasm, IsXCOFF, IsDXContainer @@ -129,6 +131,7 @@ SpecificBumpPtrAllocator ELFAllocator; SpecificBumpPtrAllocator MachOAllocator; SpecificBumpPtrAllocator GOFFAllocator; + SpecificBumpPtrAllocator SPIRVAllocator; SpecificBumpPtrAllocator WasmAllocator; SpecificBumpPtrAllocator XCOFFAllocator; SpecificBumpPtrAllocator MCInstAllocator; @@ -630,6 +633,8 @@ getAssociativeCOFFSection(MCSectionCOFF *Sec, const MCSymbol *KeySym, unsigned UniqueID = GenericSectionID); + MCSectionSPIRV *getSPIRVSection(); + MCSectionWasm *getWasmSection(const Twine &Section, SectionKind K, unsigned Flags = 0) { return getWasmSection(Section, K, Flags, nullptr); diff --git a/llvm/include/llvm/MC/MCObjectFileInfo.h b/llvm/include/llvm/MC/MCObjectFileInfo.h --- a/llvm/include/llvm/MC/MCObjectFileInfo.h +++ b/llvm/include/llvm/MC/MCObjectFileInfo.h @@ -448,6 +448,7 @@ void initELFMCObjectFileInfo(const Triple &T, bool Large); void initGOFFMCObjectFileInfo(const Triple &T); void initCOFFMCObjectFileInfo(const Triple &T); + void initSPIRVMCObjectFileInfo(const Triple &T); void initWasmMCObjectFileInfo(const Triple &T); void initXCOFFMCObjectFileInfo(const Triple &T); MCSection *getDwarfComdatSection(const char *Name, uint64_t Hash) const; diff --git a/llvm/include/llvm/MC/MCSPIRVObjectWriter.h b/llvm/include/llvm/MC/MCSPIRVObjectWriter.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/MC/MCSPIRVObjectWriter.h @@ -0,0 +1,40 @@ +//===-- llvm/MC/MCSPIRVObjectWriter.h - SPIR-V Object Writer -----*- 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_MC_MCSPIRVOBJECTWRITER_H +#define LLVM_MC_MCSPIRVOBJECTWRITER_H + +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/Support/raw_ostream.h" +#include + +namespace llvm { + +class MCSPIRVObjectTargetWriter : public MCObjectTargetWriter { +protected: + explicit MCSPIRVObjectTargetWriter() {} + +public: + Triple::ObjectFormatType getFormat() const override { return Triple::SPIRV; } + static bool classof(const MCObjectTargetWriter *W) { + return W->getFormat() == Triple::SPIRV; + } +}; + +/// Construct a new SPIR-V writer instance. +/// +/// \param MOTW - The target specific SPIR-V writer subclass. +/// \param OS - The stream to write to. +/// \returns The constructed object writer. +std::unique_ptr +createSPIRVObjectWriter(std::unique_ptr MOTW, + raw_pwrite_stream &OS); + +} // namespace llvm + +#endif diff --git a/llvm/include/llvm/MC/MCSPIRVStreamer.h b/llvm/include/llvm/MC/MCSPIRVStreamer.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/MC/MCSPIRVStreamer.h @@ -0,0 +1,50 @@ +//===- MCSPIRVStreamer.h - MCStreamer SPIR-V Object File Interface -*- 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 +// +//===----------------------------------------------------------------------===// +// +// Overrides MCObjectStreamer to disable all unnecessary features with stubs. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_MC_MCSPIRVSTREAMER_H +#define LLVM_MC_MCSPIRVSTREAMER_H + +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCObjectStreamer.h" +#include "llvm/MC/MCObjectWriter.h" + +namespace llvm { +class MCAssembler; +class MCExpr; +class MCInst; +class raw_ostream; + +class MCSPIRVStreamer : public MCObjectStreamer { +public: + MCSPIRVStreamer(MCContext &Context, std::unique_ptr TAB, + std::unique_ptr OW, + std::unique_ptr Emitter) + : MCObjectStreamer(Context, std::move(TAB), std::move(OW), + std::move(Emitter)) {} + + bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override { + return false; + } + void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) override {} + void emitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr, + uint64_t Size = 0, unsigned ByteAlignment = 0, + SMLoc Loc = SMLoc()) override {} + +private: + void emitInstToData(const MCInst &Inst, const MCSubtargetInfo &) override; +}; + +} // end namespace llvm + +#endif diff --git a/llvm/include/llvm/MC/MCSection.h b/llvm/include/llvm/MC/MCSection.h --- a/llvm/include/llvm/MC/MCSection.h +++ b/llvm/include/llvm/MC/MCSection.h @@ -46,7 +46,8 @@ SV_GOFF, SV_MachO, SV_Wasm, - SV_XCOFF + SV_XCOFF, + SV_SPIRV, }; /// Express the state of bundle locked groups while emitting code. diff --git a/llvm/include/llvm/MC/MCSectionSPIRV.h b/llvm/include/llvm/MC/MCSectionSPIRV.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/MC/MCSectionSPIRV.h @@ -0,0 +1,41 @@ +//===- MCSectionSPIRV.h - SPIR-V Machine Code Sections ----------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file declares the MCSectionSPIRV class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_MC_MCSECTIONSPIRV_H +#define LLVM_MC_MCSECTIONSPIRV_H + +#include "llvm/MC/MCSection.h" +#include "llvm/MC/SectionKind.h" + +namespace llvm { + +class MCSymbol; + +class MCSectionSPIRV final : public MCSection { + friend class MCContext; + + MCSectionSPIRV(SectionKind K, MCSymbol *Begin) + : MCSection(SV_SPIRV, "", K, Begin) {} + // TODO: Add StringRef Name to MCSectionSPIRV. + +public: + ~MCSectionSPIRV() = default; + void printSwitchToSection(const MCAsmInfo &MAI, const Triple &T, + raw_ostream &OS, + const MCExpr *Subsection) const override {} + bool useCodeAlign() const override { return false; } + bool isVirtualSection() const override { return false; } +}; + +} // end namespace llvm + +#endif // LLVM_MC_MCSECTIONSPIRV_H diff --git a/llvm/include/llvm/MC/TargetRegistry.h b/llvm/include/llvm/MC/TargetRegistry.h --- a/llvm/include/llvm/MC/TargetRegistry.h +++ b/llvm/include/llvm/MC/TargetRegistry.h @@ -109,6 +109,11 @@ std::unique_ptr &&OW, std::unique_ptr &&CE, bool RelaxAll); +MCStreamer *createSPIRVStreamer(MCContext &Ctx, + std::unique_ptr &&TAB, + std::unique_ptr &&OW, + std::unique_ptr &&CE, + bool RelaxAll); MCRelocationInfo *createMCRelocationInfo(const Triple &TT, MCContext &Ctx); @@ -201,6 +206,11 @@ std::unique_ptr &&TAB, std::unique_ptr &&OW, std::unique_ptr &&Emitter, bool RelaxAll); + using SPIRVStreamerCtorTy = + MCStreamer *(*)(const Triple &T, MCContext &Ctx, + std::unique_ptr &&TAB, + std::unique_ptr &&OW, + std::unique_ptr &&Emitter, bool RelaxAll); using NullTargetStreamerCtorTy = MCTargetStreamer *(*)(MCStreamer &S); using AsmTargetStreamerCtorTy = MCTargetStreamer *(*)( @@ -302,6 +312,7 @@ ELFStreamerCtorTy ELFStreamerCtorFn = nullptr; WasmStreamerCtorTy WasmStreamerCtorFn = nullptr; XCOFFStreamerCtorTy XCOFFStreamerCtorFn = nullptr; + SPIRVStreamerCtorTy SPIRVStreamerCtorFn = nullptr; /// Construction function for this target's null TargetStreamer, if /// registered (default = nullptr). @@ -574,6 +585,14 @@ S = createXCOFFStreamer(Ctx, std::move(TAB), std::move(OW), std::move(Emitter), RelaxAll); break; + case Triple::SPIRV: + if (SPIRVStreamerCtorFn) + S = SPIRVStreamerCtorFn(T, Ctx, std::move(TAB), std::move(OW), + std::move(Emitter), RelaxAll); + else + S = createSPIRVStreamer(Ctx, std::move(TAB), std::move(OW), + std::move(Emitter), RelaxAll); + break; } if (ObjectTargetStreamerCtorFn) ObjectTargetStreamerCtorFn(*S, STI); @@ -954,6 +973,10 @@ T.ELFStreamerCtorFn = Fn; } + static void RegisterSPIRVStreamer(Target &T, Target::SPIRVStreamerCtorTy Fn) { + T.SPIRVStreamerCtorFn = Fn; + } + static void RegisterWasmStreamer(Target &T, Target::WasmStreamerCtorTy Fn) { T.WasmStreamerCtorFn = Fn; } diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -4890,6 +4890,9 @@ case Triple::GOFF: llvm_unreachable("GOFF is not yet implemented"); break; + case Triple::SPIRV: + llvm_unreachable("SPIRV is not yet implemented"); + break; case Triple::XCOFF: llvm_unreachable("XCOFF is not yet implemented"); break; @@ -4912,6 +4915,9 @@ case Triple::GOFF: llvm_unreachable("GOFF is not yet implemented"); break; + case Triple::SPIRV: + llvm_unreachable("SPIRV is not yet implemented"); + break; case Triple::XCOFF: llvm_unreachable("XCOFF is not yet implemented"); break; diff --git a/llvm/lib/MC/CMakeLists.txt b/llvm/lib/MC/CMakeLists.txt --- a/llvm/lib/MC/CMakeLists.txt +++ b/llvm/lib/MC/CMakeLists.txt @@ -43,6 +43,7 @@ MCSectionWasm.cpp MCSectionXCOFF.cpp MCStreamer.cpp + MCSPIRVStreamer.cpp MCSubtargetInfo.cpp MCSymbol.cpp MCSymbolELF.cpp @@ -58,6 +59,7 @@ MCXCOFFObjectTargetWriter.cpp MCXCOFFStreamer.cpp MachObjectWriter.cpp + SPIRVObjectWriter.cpp StringTableBuilder.cpp SubtargetFeature.cpp TargetRegistry.cpp diff --git a/llvm/lib/MC/MCAsmBackend.cpp b/llvm/lib/MC/MCAsmBackend.cpp --- a/llvm/lib/MC/MCAsmBackend.cpp +++ b/llvm/lib/MC/MCAsmBackend.cpp @@ -13,6 +13,7 @@ #include "llvm/MC/MCFixupKindInfo.h" #include "llvm/MC/MCMachObjectWriter.h" #include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSPIRVObjectWriter.h" #include "llvm/MC/MCWasmObjectWriter.h" #include "llvm/MC/MCWinCOFFObjectWriter.h" #include "llvm/MC/MCXCOFFObjectWriter.h" @@ -39,6 +40,9 @@ case Triple::COFF: return createWinCOFFObjectWriter( cast(std::move(TW)), OS); + case Triple::SPIRV: + return createSPIRVObjectWriter( + cast(std::move(TW)), OS); case Triple::Wasm: return createWasmObjectWriter(cast(std::move(TW)), OS); diff --git a/llvm/lib/MC/MCContext.cpp b/llvm/lib/MC/MCContext.cpp --- a/llvm/lib/MC/MCContext.cpp +++ b/llvm/lib/MC/MCContext.cpp @@ -29,6 +29,7 @@ #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSectionGOFF.h" #include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCSectionSPIRV.h" #include "llvm/MC/MCSectionWasm.h" #include "llvm/MC/MCSectionXCOFF.h" #include "llvm/MC/MCStreamer.h" @@ -110,6 +111,9 @@ case Triple::DXContainer: Env = IsDXContainer; break; + case Triple::SPIRV: + Env = IsSPIRV; + break; case Triple::UnknownObjectFormat: report_fatal_error("Cannot initialize MC for unknown object file format."); break; @@ -147,6 +151,7 @@ WasmAllocator.DestroyAll(); XCOFFAllocator.DestroyAll(); MCInstAllocator.DestroyAll(); + SPIRVAllocator.DestroyAll(); MCSubtargetAllocator.DestroyAll(); InlineAsmUsedLabelNames.clear(); @@ -253,6 +258,9 @@ return createXCOFFSymbolImpl(Name, IsTemporary); case MCContext::IsDXContainer: break; + case MCContext::IsSPIRV: + return new (Name, *this) + MCSymbol(MCSymbol::SymbolKindUnset, Name, IsTemporary); } return new (Name, *this) MCSymbol(MCSymbol::SymbolKindUnset, Name, IsTemporary); @@ -812,6 +820,21 @@ return Result; } +MCSectionSPIRV *MCContext::getSPIRVSection() { + MCSymbol *Begin = nullptr; + MCSectionSPIRV *Result = new (SPIRVAllocator.Allocate()) + MCSectionSPIRV(SectionKind::getText(), Begin); + + auto *F = new MCDataFragment(); + Result->getFragmentList().insert(Result->begin(), F); + F->setParent(Result); + + if (Begin) + Begin->setFragment(F); + + return Result; +} + MCSubtargetInfo &MCContext::getSubtargetCopy(const MCSubtargetInfo &STI) { return *new (MCSubtargetAllocator.Allocate()) MCSubtargetInfo(STI); } diff --git a/llvm/lib/MC/MCObjectFileInfo.cpp b/llvm/lib/MC/MCObjectFileInfo.cpp --- a/llvm/lib/MC/MCObjectFileInfo.cpp +++ b/llvm/lib/MC/MCObjectFileInfo.cpp @@ -19,6 +19,7 @@ #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSectionGOFF.h" #include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCSectionSPIRV.h" #include "llvm/MC/MCSectionWasm.h" #include "llvm/MC/MCSectionXCOFF.h" #include "llvm/Support/Casting.h" @@ -804,6 +805,11 @@ SectionKind::getReadOnly()); } +void MCObjectFileInfo::initSPIRVMCObjectFileInfo(const Triple &T) { + // Put everything in a single binary section. + TextSection = Ctx->getSPIRVSection(); +} + void MCObjectFileInfo::initWasmMCObjectFileInfo(const Triple &T) { TextSection = Ctx->getWasmSection(".text", SectionKind::getText()); DataSection = Ctx->getWasmSection(".data", SectionKind::getData()); @@ -1032,6 +1038,9 @@ case MCContext::IsGOFF: initGOFFMCObjectFileInfo(TheTriple); break; + case MCContext::IsSPIRV: + initSPIRVMCObjectFileInfo(TheTriple); + break; case MCContext::IsWasm: initWasmMCObjectFileInfo(TheTriple); break; @@ -1055,6 +1064,7 @@ case Triple::MachO: case Triple::COFF: case Triple::GOFF: + case Triple::SPIRV: case Triple::XCOFF: case Triple::DXContainer: case Triple::UnknownObjectFormat: diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp --- a/llvm/lib/MC/MCParser/AsmParser.cpp +++ b/llvm/lib/MC/MCParser/AsmParser.cpp @@ -792,6 +792,10 @@ case MCContext::IsGOFF: PlatformParser.reset(createGOFFAsmParser()); break; + case MCContext::IsSPIRV: + report_fatal_error( + "Need to implement createSPIRVAsmParser for SPIRV format."); + break; case MCContext::IsWasm: PlatformParser.reset(createWasmAsmParser()); break; diff --git a/llvm/lib/MC/MCSPIRVStreamer.cpp b/llvm/lib/MC/MCSPIRVStreamer.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/MC/MCSPIRVStreamer.cpp @@ -0,0 +1,45 @@ +//===- lib/MC/MCSPIRVStreamer.cpp - SPIR-V Object Output ------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file assembles .s files and emits SPIR-V .o object files. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCSPIRVStreamer.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/TargetRegistry.h" + +using namespace llvm; + +void MCSPIRVStreamer::emitInstToData(const MCInst &Inst, + const MCSubtargetInfo &STI) { + MCAssembler &Assembler = getAssembler(); + SmallVector Fixups; + SmallString<256> Code; + raw_svector_ostream VecOS(Code); + Assembler.getEmitter().encodeInstruction(Inst, VecOS, Fixups, STI); + + // Append the encoded instruction to the current data fragment (or create a + // new such fragment if the current fragment is not a data fragment). + MCDataFragment *DF = getOrCreateDataFragment(); + + DF->setHasInstructions(STI); + DF->getContents().append(Code.begin(), Code.end()); +} + +MCStreamer *llvm::createSPIRVStreamer(MCContext &Context, + std::unique_ptr &&MAB, + std::unique_ptr &&OW, + std::unique_ptr &&CE, + bool RelaxAll) { + MCSPIRVStreamer *S = new MCSPIRVStreamer(Context, std::move(MAB), + std::move(OW), std::move(CE)); + if (RelaxAll) + S->getAssembler().setRelaxAll(true); + return S; +} diff --git a/llvm/lib/MC/SPIRVObjectWriter.cpp b/llvm/lib/MC/SPIRVObjectWriter.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/MC/SPIRVObjectWriter.cpp @@ -0,0 +1,76 @@ +//===- llvm/MC/MCSPIRVObjectWriter.cpp - SPIR-V Object Writer ----*- 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 "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCSPIRVObjectWriter.h" +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCValue.h" +#include "llvm/Support/EndianStream.h" + +using namespace llvm; + +class SPIRVObjectWriter : public MCObjectWriter { + ::support::endian::Writer W; + + /// The target specific SPIR-V writer instance. + std::unique_ptr TargetObjectWriter; + +public: + SPIRVObjectWriter(std::unique_ptr MOTW, + raw_pwrite_stream &OS) + : W(OS, support::little), TargetObjectWriter(std::move(MOTW)) {} + + ~SPIRVObjectWriter() override {} + +private: + void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout, + const MCFragment *Fragment, const MCFixup &Fixup, + MCValue Target, uint64_t &FixedValue) override {} + + void executePostLayoutBinding(MCAssembler &Asm, + const MCAsmLayout &Layout) override {} + + uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override; + void writeHeader(const MCAssembler &Asm); +}; + +void SPIRVObjectWriter::writeHeader(const MCAssembler &Asm) { + constexpr uint32_t MagicNumber = 0x07230203; + + // TODO: set the version on a min-necessary basis (just like the translator + // does) requires some refactoring of MCAssembler::VersionInfoType. + constexpr uint32_t Major = 1; + constexpr uint32_t Minor = 0; + constexpr uint32_t VersionNumber = 0 | (Major << 16) | (Minor << 8); + // TODO: check if we could use anything other than 0 (spec allows). + constexpr uint32_t GeneratorMagicNumber = 0; + // TODO: do not hardcode this as well. + constexpr uint32_t Bound = 900; + constexpr uint32_t Schema = 0; + + W.write(MagicNumber); + W.write(VersionNumber); + W.write(GeneratorMagicNumber); + W.write(Bound); + W.write(Schema); +} + +uint64_t SPIRVObjectWriter::writeObject(MCAssembler &Asm, + const MCAsmLayout &Layout) { + uint64_t StartOffset = W.OS.tell(); + writeHeader(Asm); + for (const MCSection &S : Asm) + Asm.writeSectionData(W.OS, &S, Layout); + return W.OS.tell() - StartOffset; +} + +std::unique_ptr +llvm::createSPIRVObjectWriter(std::unique_ptr MOTW, + raw_pwrite_stream &OS) { + return std::make_unique(std::move(MOTW), OS); +} diff --git a/llvm/lib/Support/Triple.cpp b/llvm/lib/Support/Triple.cpp --- a/llvm/lib/Support/Triple.cpp +++ b/llvm/lib/Support/Triple.cpp @@ -631,15 +631,16 @@ static Triple::ObjectFormatType parseFormat(StringRef EnvironmentName) { return StringSwitch(EnvironmentName) - // "xcoff" must come before "coff" because of the order-dependendent - // pattern matching. - .EndsWith("xcoff", Triple::XCOFF) - .EndsWith("coff", Triple::COFF) - .EndsWith("elf", Triple::ELF) - .EndsWith("goff", Triple::GOFF) - .EndsWith("macho", Triple::MachO) - .EndsWith("wasm", Triple::Wasm) - .Default(Triple::UnknownObjectFormat); + // "xcoff" must come before "coff" because of the order-dependendent + // pattern matching. + .EndsWith("xcoff", Triple::XCOFF) + .EndsWith("coff", Triple::COFF) + .EndsWith("elf", Triple::ELF) + .EndsWith("goff", Triple::GOFF) + .EndsWith("macho", Triple::MachO) + .EndsWith("wasm", Triple::Wasm) + .EndsWith("spirv", Triple::SPIRV) + .Default(Triple::UnknownObjectFormat); } static Triple::SubArchType parseSubArch(StringRef SubArchName) { @@ -740,14 +741,24 @@ static StringRef getObjectFormatTypeName(Triple::ObjectFormatType Kind) { switch (Kind) { - case Triple::UnknownObjectFormat: return ""; - case Triple::COFF: return "coff"; - case Triple::ELF: return "elf"; - case Triple::GOFF: return "goff"; - case Triple::MachO: return "macho"; - case Triple::Wasm: return "wasm"; - case Triple::XCOFF: return "xcoff"; - case Triple::DXContainer: return "dxcontainer"; + case Triple::UnknownObjectFormat: + return ""; + case Triple::COFF: + return "coff"; + case Triple::ELF: + return "elf"; + case Triple::GOFF: + return "goff"; + case Triple::MachO: + return "macho"; + case Triple::Wasm: + return "wasm"; + case Triple::XCOFF: + return "xcoff"; + case Triple::DXContainer: + return "dxcontainer"; + case Triple::SPIRV: + return "spirv"; } llvm_unreachable("unknown object format type"); } @@ -831,8 +842,7 @@ case Triple::spirv32: case Triple::spirv64: - // TODO: In future this will be Triple::SPIRV. - return Triple::UnknownObjectFormat; + return Triple::SPIRV; case Triple::dxil: return Triple::DXContainer; diff --git a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp --- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -6377,6 +6377,7 @@ CurrentFormat = WASM; break; case MCContext::IsGOFF: + case MCContext::IsSPIRV: case MCContext::IsXCOFF: case MCContext::IsDXContainer: llvm_unreachable("unexpected object format"); diff --git a/llvm/lib/Target/SPIRV/CMakeLists.txt b/llvm/lib/Target/SPIRV/CMakeLists.txt --- a/llvm/lib/Target/SPIRV/CMakeLists.txt +++ b/llvm/lib/Target/SPIRV/CMakeLists.txt @@ -18,6 +18,8 @@ LINK_COMPONENTS CodeGen Core + MC + SPIRVDesc SPIRVInfo Support Target @@ -26,4 +28,5 @@ SPIRV ) +add_subdirectory(MCTargetDesc) add_subdirectory(TargetInfo) diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/CMakeLists.txt b/llvm/lib/Target/SPIRV/MCTargetDesc/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/SPIRV/MCTargetDesc/CMakeLists.txt @@ -0,0 +1,17 @@ +add_llvm_component_library(LLVMSPIRVDesc + SPIRVMCAsmInfo.cpp + SPIRVMCTargetDesc.cpp + SPIRVTargetStreamer.cpp + SPIRVAsmBackend.cpp + SPIRVMCCodeEmitter.cpp + SPIRVObjectTargetWriter.cpp + SPIRVInstPrinter.cpp + + LINK_COMPONENTS + MC + SPIRVInfo + Support + + ADD_TO_COMPONENT + SPIRV + ) diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVAsmBackend.cpp b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVAsmBackend.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVAsmBackend.cpp @@ -0,0 +1,63 @@ +//===-- SPIRVAsmBackend.cpp - SPIR-V Assembler Backend ---------*- 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 "MCTargetDesc/SPIRVMCTargetDesc.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/Support/EndianStream.h" + +using namespace llvm; + +namespace { + +class SPIRVAsmBackend : public MCAsmBackend { +public: + SPIRVAsmBackend(support::endianness Endian) : MCAsmBackend(Endian) {} + + void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, MutableArrayRef Data, + uint64_t Value, bool IsResolved, + const MCSubtargetInfo *STI) const override {} + + std::unique_ptr + createObjectTargetWriter() const override { + return createSPIRVObjectTargetWriter(); + } + + // No instruction requires relaxation. + bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value, + const MCRelaxableFragment *DF, + const MCAsmLayout &Layout) const override { + return false; + } + + unsigned getNumFixupKinds() const override { return 1; } + + bool mayNeedRelaxation(const MCInst &Inst, + const MCSubtargetInfo &STI) const override { + return false; + } + + void relaxInstruction(MCInst &Inst, + const MCSubtargetInfo &STI) const override {} + + bool writeNopData(raw_ostream &OS, uint64_t Count, + const MCSubtargetInfo *STI) const override { + return false; + } +}; + +} // end anonymous namespace + +MCAsmBackend *llvm::createSPIRVAsmBackend(const Target &T, + const MCSubtargetInfo &STI, + const MCRegisterInfo &MRI, + const MCTargetOptions &) { + return new SPIRVAsmBackend(support::little); +} diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.h b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.h new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.h @@ -0,0 +1,94 @@ +//===-- SPIRVInstPrinter.h - Output SPIR-V MCInsts as ASM -------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This class prints a SPIR-V MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_SPIRV_INSTPRINTER_SPIRVINSTPRINTER_H +#define LLVM_LIB_TARGET_SPIRV_INSTPRINTER_SPIRVINSTPRINTER_H + +#include "llvm/MC/MCInstPrinter.h" + +namespace llvm { +class SPIRVInstPrinter : public MCInstPrinter { +private: + void recordOpExtInstImport(const MCInst *MI); + +public: + using MCInstPrinter::MCInstPrinter; + + void printInst(const MCInst *MI, uint64_t Address, StringRef Annot, + const MCSubtargetInfo &STI, raw_ostream &OS) override; + void printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O, + const char *Modifier = nullptr); + + void printStringImm(const MCInst *MI, unsigned OpNo, raw_ostream &O); + + void printOpDecorate(const MCInst *MI, raw_ostream &O); + void printOpExtInst(const MCInst *MI, raw_ostream &O); + void printRemainingVariableOps(const MCInst *MI, unsigned StartIndex, + raw_ostream &O, bool SkipFirstSpace = false, + bool SkipImmediates = false); + void printOpConstantVarOps(const MCInst *MI, unsigned StartIndex, + raw_ostream &O); + + void printExtInst(const MCInst *MI, unsigned OpNo, raw_ostream &O); + + // SPIR-V enumerations printing. + void printCapability(const MCInst *MI, unsigned OpNo, raw_ostream &O); + void printSourceLanguage(const MCInst *MI, unsigned OpNo, raw_ostream &O); + void printExecutionModel(const MCInst *MI, unsigned OpNo, raw_ostream &O); + void printAddressingModel(const MCInst *MI, unsigned OpNo, raw_ostream &O); + void printMemoryModel(const MCInst *MI, unsigned OpNo, raw_ostream &O); + void printExecutionMode(const MCInst *MI, unsigned OpNo, raw_ostream &O); + void printStorageClass(const MCInst *MI, unsigned OpNo, raw_ostream &O); + void printDim(const MCInst *MI, unsigned OpNo, raw_ostream &O); + + void printSamplerAddressingMode(const MCInst *MI, unsigned OpNo, + raw_ostream &O); + void printSamplerFilterMode(const MCInst *MI, unsigned OpNo, raw_ostream &O); + + void printImageFormat(const MCInst *MI, unsigned OpNo, raw_ostream &O); + void printImageChannelOrder(const MCInst *MI, unsigned OpNo, raw_ostream &O); + void printImageChannelDataType(const MCInst *MI, unsigned OpNo, + raw_ostream &O); + void printImageOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O); + + void printFPFastMathMode(const MCInst *MI, unsigned OpNo, raw_ostream &O); + void printFPRoundingMode(const MCInst *MI, unsigned OpNo, raw_ostream &O); + + void printLinkageType(const MCInst *MI, unsigned OpNo, raw_ostream &O); + void printAccessQualifier(const MCInst *MI, unsigned OpNo, raw_ostream &O); + void printFunctionParameterAttribute(const MCInst *MI, unsigned OpNo, + raw_ostream &O); + + void printDecoration(const MCInst *MI, unsigned OpNo, raw_ostream &O); + void printBuiltIn(const MCInst *MI, unsigned OpNo, raw_ostream &O); + + void printSelectionControl(const MCInst *MI, unsigned OpNo, raw_ostream &O); + void printLoopControl(const MCInst *MI, unsigned OpNo, raw_ostream &O); + void printFunctionControl(const MCInst *MI, unsigned OpNo, raw_ostream &O); + + void printMemorySemantics(const MCInst *MI, unsigned OpNo, raw_ostream &O); + void printMemoryOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O); + + void printScope(const MCInst *MI, unsigned OpNo, raw_ostream &O); + void printGroupOperation(const MCInst *MI, unsigned OpNo, raw_ostream &O); + + void printKernelEnqueueFlags(const MCInst *MI, unsigned OpNo, raw_ostream &O); + void printKernelProfilingInfo(const MCInst *MI, unsigned OpNo, + raw_ostream &O); + // Autogenerated by tblgen. + std::pair getMnemonic(const MCInst *MI) override; + void printInstruction(const MCInst *MI, uint64_t Address, raw_ostream &O); + static const char *getRegisterName(unsigned RegNo); +}; +} // namespace llvm + +#endif // LLVM_LIB_TARGET_SPIRV_INSTPRINTER_SPIRVINSTPRINTER_H diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp @@ -0,0 +1,157 @@ +//===-- SPIRVInstPrinter.cpp - Output SPIR-V MCInsts as ASM -----*- 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 +// +//===----------------------------------------------------------------------===// +// +// This class prints a SPIR-V MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +#include "SPIRVInstPrinter.h" +#include "llvm/CodeGen/Register.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FormattedStream.h" + +using namespace llvm; + +#define DEBUG_TYPE "asm-printer" + +// Include the auto-generated portion of the assembly writer. +#include "SPIRVGenAsmWriter.inc" + +void SPIRVInstPrinter::printRemainingVariableOps(const MCInst *MI, + unsigned StartIndex, + raw_ostream &O, + bool SkipFirstSpace, + bool SkipImmediates) { + const unsigned NumOps = MI->getNumOperands(); + for (unsigned i = StartIndex; i < NumOps; ++i) { + if (!SkipImmediates || !MI->getOperand(i).isImm()) { + if (!SkipFirstSpace || i != StartIndex) + O << ' '; + printOperand(MI, i, O); + } + } +} + +void SPIRVInstPrinter::printOpConstantVarOps(const MCInst *MI, + unsigned StartIndex, + raw_ostream &O) { + O << ' '; + if (MI->getNumOperands() - StartIndex == 2) { // Handle 64 bit literals. + uint64_t Imm = MI->getOperand(StartIndex).getImm(); + Imm |= (MI->getOperand(StartIndex + 1).getImm() << 32); + O << Imm; + } else { + printRemainingVariableOps(MI, StartIndex, O, true, false); + } +} + +void SPIRVInstPrinter::recordOpExtInstImport(const MCInst *MI) { + llvm_unreachable("Unimplemented recordOpExtInstImport"); +} + +void SPIRVInstPrinter::printInst(const MCInst *MI, uint64_t Address, + StringRef Annot, const MCSubtargetInfo &STI, + raw_ostream &OS) { + printInstruction(MI, Address, OS); + printAnnotation(OS, Annot); +} + +void SPIRVInstPrinter::printOpExtInst(const MCInst *MI, raw_ostream &O) { + llvm_unreachable("Unimplemented printOpExtInst"); +} + +void SPIRVInstPrinter::printOpDecorate(const MCInst *MI, raw_ostream &O) { + llvm_unreachable("Unimplemented printOpDecorate"); +} + +static void printExpr(const MCExpr *Expr, raw_ostream &O) { +#ifndef NDEBUG + const MCSymbolRefExpr *SRE; + + if (const MCBinaryExpr *BE = dyn_cast(Expr)) + SRE = cast(BE->getLHS()); + else + SRE = cast(Expr); + + MCSymbolRefExpr::VariantKind Kind = SRE->getKind(); + + assert(Kind == MCSymbolRefExpr::VK_None); +#endif + O << *Expr; +} + +void SPIRVInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, + raw_ostream &O, const char *Modifier) { + assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported"); + if (OpNo < MI->getNumOperands()) { + const MCOperand &Op = MI->getOperand(OpNo); + if (Op.isReg()) + O << '%' << (Register::virtReg2Index(Op.getReg()) + 1); + else if (Op.isImm()) + O << formatImm((int64_t)Op.getImm()); + else if (Op.isDFPImm()) + O << formatImm((double)Op.getDFPImm()); + else if (Op.isExpr()) + printExpr(Op.getExpr(), O); + else + llvm_unreachable("Unexpected operand type"); + } +} + +void SPIRVInstPrinter::printStringImm(const MCInst *MI, unsigned OpNo, + raw_ostream &O) { + llvm_unreachable("Unimplemented printStringImm"); +} + +void SPIRVInstPrinter::printExtInst(const MCInst *MI, unsigned OpNo, + raw_ostream &O) { + llvm_unreachable("Unimplemented printExtInst"); +} + +// Methods for printing textual names of SPIR-V enums. +#define GEN_INSTR_PRINTER_IMPL(EnumName) \ + void SPIRVInstPrinter::print##EnumName(const MCInst *MI, unsigned OpNo, \ + raw_ostream &O) { \ + llvm_unreachable("Unimplemented print" #EnumName); \ + } +GEN_INSTR_PRINTER_IMPL(Capability) +GEN_INSTR_PRINTER_IMPL(SourceLanguage) +GEN_INSTR_PRINTER_IMPL(ExecutionModel) +GEN_INSTR_PRINTER_IMPL(AddressingModel) +GEN_INSTR_PRINTER_IMPL(MemoryModel) +GEN_INSTR_PRINTER_IMPL(ExecutionMode) +GEN_INSTR_PRINTER_IMPL(StorageClass) +GEN_INSTR_PRINTER_IMPL(Dim) +GEN_INSTR_PRINTER_IMPL(SamplerAddressingMode) +GEN_INSTR_PRINTER_IMPL(SamplerFilterMode) +GEN_INSTR_PRINTER_IMPL(ImageFormat) +GEN_INSTR_PRINTER_IMPL(ImageChannelOrder) +GEN_INSTR_PRINTER_IMPL(ImageChannelDataType) +GEN_INSTR_PRINTER_IMPL(ImageOperand) +GEN_INSTR_PRINTER_IMPL(FPFastMathMode) +GEN_INSTR_PRINTER_IMPL(FPRoundingMode) +GEN_INSTR_PRINTER_IMPL(LinkageType) +GEN_INSTR_PRINTER_IMPL(AccessQualifier) +GEN_INSTR_PRINTER_IMPL(FunctionParameterAttribute) +GEN_INSTR_PRINTER_IMPL(Decoration) +GEN_INSTR_PRINTER_IMPL(BuiltIn) +GEN_INSTR_PRINTER_IMPL(SelectionControl) +GEN_INSTR_PRINTER_IMPL(LoopControl) +GEN_INSTR_PRINTER_IMPL(FunctionControl) +GEN_INSTR_PRINTER_IMPL(MemorySemantics) +GEN_INSTR_PRINTER_IMPL(MemoryOperand) +GEN_INSTR_PRINTER_IMPL(Scope) +GEN_INSTR_PRINTER_IMPL(GroupOperation) +GEN_INSTR_PRINTER_IMPL(KernelEnqueueFlags) +GEN_INSTR_PRINTER_IMPL(KernelProfilingInfo) diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCAsmInfo.h b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCAsmInfo.h new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCAsmInfo.h @@ -0,0 +1,29 @@ +//===-- SPIRVMCAsmInfo.h - SPIR-V asm properties --------------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains the declaration of the SPIRVMCAsmInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_SPIRV_MCTARGETDESC_SPIRVMCASMINFO_H +#define LLVM_LIB_TARGET_SPIRV_MCTARGETDESC_SPIRVMCASMINFO_H + +#include "llvm/MC/MCAsmInfo.h" + +namespace llvm { + +class Triple; + +class SPIRVMCAsmInfo : public MCAsmInfo { +public: + explicit SPIRVMCAsmInfo(const Triple &TT, const MCTargetOptions &Options); + bool shouldOmitSectionDirective(StringRef SectionName) const override; +}; +} // namespace llvm + +#endif // LLVM_LIB_TARGET_SPIRV_MCTARGETDESC_SPIRVMCASMINFO_H diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCAsmInfo.cpp b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCAsmInfo.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCAsmInfo.cpp @@ -0,0 +1,34 @@ +//===-- SPIRVMCAsmInfo.h - SPIR-V asm properties --------------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file contains the declarations of the SPIRVMCAsmInfo properties. +// +//===----------------------------------------------------------------------===// + +#include "SPIRVMCAsmInfo.h" +#include "llvm/ADT/Triple.h" + +using namespace llvm; + +SPIRVMCAsmInfo::SPIRVMCAsmInfo(const Triple &TT, + const MCTargetOptions &Options) { + IsLittleEndian = true; + + HasSingleParameterDotFile = false; + HasDotTypeDotSizeDirective = false; + + MinInstAlignment = 4; + + CodePointerSize = 4; + CommentString = ";"; + HasFunctionAlignment = false; +} + +bool SPIRVMCAsmInfo::shouldOmitSectionDirective(StringRef SectionName) const { + return true; +} diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCCodeEmitter.cpp b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCCodeEmitter.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCCodeEmitter.cpp @@ -0,0 +1,132 @@ +//===-- SPIRVMCCodeEmitter.cpp - Emit SPIR-V machine code -------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements the SPIRVMCCodeEmitter class. +// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/SPIRVMCTargetDesc.h" +#include "llvm/CodeGen/Register.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCFixup.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/EndianStream.h" + +using namespace llvm; + +#define DEBUG_TYPE "spirv-mccodeemitter" + +namespace { + +class SPIRVMCCodeEmitter : public MCCodeEmitter { + const MCInstrInfo &MCII; + +public: + SPIRVMCCodeEmitter(const MCInstrInfo &mcii) : MCII(mcii) {} + SPIRVMCCodeEmitter(const SPIRVMCCodeEmitter &) = delete; + void operator=(const SPIRVMCCodeEmitter &) = delete; + ~SPIRVMCCodeEmitter() override = default; + + // getBinaryCodeForInstr - TableGen'erated function for getting the + // binary encoding for an instruction. + uint64_t getBinaryCodeForInstr(const MCInst &MI, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + void encodeInstruction(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const override; + +private: + FeatureBitset computeAvailableFeatures(const FeatureBitset &FB) const; + void + verifyInstructionPredicates(const MCInst &MI, + const FeatureBitset &AvailableFeatures) const; +}; + +} // end anonymous namespace + +MCCodeEmitter *llvm::createSPIRVMCCodeEmitter(const MCInstrInfo &MCII, + MCContext &Ctx) { + return new SPIRVMCCodeEmitter(MCII); +} + +using EndianWriter = support::endian::Writer; + +// Check if the instruction has a type argument for operand 1, and defines an ID +// output register in operand 0. If so, we need to swap operands 0 and 1 so the +// type comes first in the output, despide coming second in the MCInst. +static bool hasType(const MCInst &MI, const MCInstrInfo &MII) { + MCInstrDesc MCDesc = MII.get(MI.getOpcode()); + // If we define an output, and have at least one other argument. + if (MCDesc.getNumDefs() == 1 && MCDesc.getNumOperands() >= 2) { + // Check if we define an ID, and take a type as operand 1. + auto DefOpInfo = MCDesc.opInfo_begin(); + auto FirstArgOpInfo = MCDesc.opInfo_begin() + 1; + return (DefOpInfo->RegClass == SPIRV::IDRegClassID || + DefOpInfo->RegClass == SPIRV::ANYIDRegClassID) && + FirstArgOpInfo->RegClass == SPIRV::TYPERegClassID; + } + return false; +} + +static void emitOperand(const MCOperand &Op, EndianWriter &OSE) { + if (Op.isReg()) { + // Emit the id index starting at 1 (0 is an invalid index). + OSE.write(Register::virtReg2Index(Op.getReg()) + 1); + } else if (Op.isImm()) { + OSE.write(Op.getImm()); + } else { + llvm_unreachable("Unexpected operand type in VReg"); + } +} + +// Emit the type in operand 1 before the ID in operand 0 it defines, and all +// remaining operands in the order they come naturally. +static void emitTypedInstrOperands(const MCInst &MI, EndianWriter &OSE) { + unsigned NumOps = MI.getNumOperands(); + emitOperand(MI.getOperand(1), OSE); + emitOperand(MI.getOperand(0), OSE); + for (unsigned i = 2; i < NumOps; ++i) + emitOperand(MI.getOperand(i), OSE); +} + +// Emit operands in the order they come naturally. +static void emitUntypedInstrOperands(const MCInst &MI, EndianWriter &OSE) { + for (const auto &Op : MI) + emitOperand(Op, OSE); +} + +void SPIRVMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + auto Features = computeAvailableFeatures(STI.getFeatureBits()); + verifyInstructionPredicates(MI, Features); + + EndianWriter OSE(OS, support::little); + + // Encode the first 32 SPIR-V bytes with the number of args and the opcode. + const uint64_t OpCode = getBinaryCodeForInstr(MI, Fixups, STI); + const uint32_t NumWords = MI.getNumOperands() + 1; + const uint32_t FirstWord = (NumWords << 16) | OpCode; + OSE.write(FirstWord); + + // Emit the instruction arguments (emitting the output type first if present). + if (hasType(MI, MCII)) + emitTypedInstrOperands(MI, OSE); + else + emitUntypedInstrOperands(MI, OSE); +} + +#define ENABLE_INSTR_PREDICATE_VERIFIER +#include "SPIRVGenMCCodeEmitter.inc" diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCTargetDesc.h b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCTargetDesc.h new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCTargetDesc.h @@ -0,0 +1,52 @@ +//===-- SPIRVMCTargetDesc.h - SPIR-V Target Descriptions --------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file provides SPIR-V specific target descriptions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_SPIRV_MCTARGETDESC_SPIRVMCTARGETDESC_H +#define LLVM_LIB_TARGET_SPIRV_MCTARGETDESC_SPIRVMCTARGETDESC_H + +#include "llvm/Support/DataTypes.h" +#include + +namespace llvm { +class MCAsmBackend; +class MCCodeEmitter; +class MCContext; +class MCInstrInfo; +class MCObjectTargetWriter; +class MCRegisterInfo; +class MCSubtargetInfo; +class MCTargetOptions; +class Target; + +MCCodeEmitter *createSPIRVMCCodeEmitter(const MCInstrInfo &MCII, + MCContext &Ctx); + +MCAsmBackend *createSPIRVAsmBackend(const Target &T, const MCSubtargetInfo &STI, + const MCRegisterInfo &MRI, + const MCTargetOptions &Options); + +std::unique_ptr createSPIRVObjectTargetWriter(); +} // namespace llvm + +// Defines symbolic names for SPIR-V registers. This defines a mapping from +// register name to register number. +#define GET_REGINFO_ENUM +#include "SPIRVGenRegisterInfo.inc" + +// Defines symbolic names for the SPIR-V instructions. +#define GET_INSTRINFO_ENUM +#include "SPIRVGenInstrInfo.inc" + +#define GET_SUBTARGETINFO_ENUM +#include "SPIRVGenSubtargetInfo.inc" + +#endif // LLVM_LIB_TARGET_SPIRV_MCTARGETDESC_SPIRVMCTARGETDESC_H diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCTargetDesc.cpp b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCTargetDesc.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCTargetDesc.cpp @@ -0,0 +1,102 @@ +//===-- SPIRVMCTargetDesc.cpp - SPIR-V Target Descriptions ----*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file provides SPIR-V specific target descriptions. +// +//===----------------------------------------------------------------------===// + +#include "SPIRVMCTargetDesc.h" +#include "SPIRVInstPrinter.h" +#include "SPIRVMCAsmInfo.h" +#include "SPIRVTargetStreamer.h" +#include "TargetInfo/SPIRVTargetInfo.h" +#include "llvm/MC/MCInstrAnalysis.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/TargetRegistry.h" + +#define GET_INSTRINFO_MC_DESC +#include "SPIRVGenInstrInfo.inc" + +#define GET_SUBTARGETINFO_MC_DESC +#include "SPIRVGenSubtargetInfo.inc" + +#define GET_REGINFO_MC_DESC +#include "SPIRVGenRegisterInfo.inc" + +using namespace llvm; + +static MCInstrInfo *createSPIRVMCInstrInfo() { + MCInstrInfo *X = new MCInstrInfo(); + InitSPIRVMCInstrInfo(X); + return X; +} + +static MCRegisterInfo *createSPIRVMCRegisterInfo(const Triple &TT) { + MCRegisterInfo *X = new MCRegisterInfo(); + return X; +} + +static MCSubtargetInfo * +createSPIRVMCSubtargetInfo(const Triple &TT, StringRef CPU, StringRef FS) { + return createSPIRVMCSubtargetInfoImpl(TT, CPU, /*TuneCPU*/ CPU, FS); +} + +static MCStreamer * +createSPIRVMCStreamer(const Triple &T, MCContext &Ctx, + std::unique_ptr &&MAB, + std::unique_ptr &&OW, + std::unique_ptr &&Emitter, bool RelaxAll) { + return createSPIRVStreamer(Ctx, std::move(MAB), std::move(OW), + std::move(Emitter), RelaxAll); +} + +static MCTargetStreamer *createTargetAsmStreamer(MCStreamer &S, + formatted_raw_ostream &, + MCInstPrinter *, bool) { + return new SPIRVTargetStreamer(S); +} + +static MCInstPrinter *createSPIRVMCInstPrinter(const Triple &T, + unsigned SyntaxVariant, + const MCAsmInfo &MAI, + const MCInstrInfo &MII, + const MCRegisterInfo &MRI) { + assert(SyntaxVariant == 0); + return new SPIRVInstPrinter(MAI, MII, MRI); +} + +namespace { + +class SPIRVMCInstrAnalysis : public MCInstrAnalysis { +public: + explicit SPIRVMCInstrAnalysis(const MCInstrInfo *Info) + : MCInstrAnalysis(Info) {} +}; + +} // end anonymous namespace + +static MCInstrAnalysis *createSPIRVInstrAnalysis(const MCInstrInfo *Info) { + return new SPIRVMCInstrAnalysis(Info); +} + +extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSPIRVTargetMC() { + for (Target *T : {&getTheSPIRV32Target(), &getTheSPIRV64Target()}) { + RegisterMCAsmInfo X(*T); + TargetRegistry::RegisterMCInstrInfo(*T, createSPIRVMCInstrInfo); + TargetRegistry::RegisterMCRegInfo(*T, createSPIRVMCRegisterInfo); + TargetRegistry::RegisterMCSubtargetInfo(*T, createSPIRVMCSubtargetInfo); + TargetRegistry::RegisterSPIRVStreamer(*T, createSPIRVMCStreamer); + TargetRegistry::RegisterMCInstPrinter(*T, createSPIRVMCInstPrinter); + TargetRegistry::RegisterMCInstrAnalysis(*T, createSPIRVInstrAnalysis); + TargetRegistry::RegisterMCCodeEmitter(*T, createSPIRVMCCodeEmitter); + TargetRegistry::RegisterMCAsmBackend(*T, createSPIRVAsmBackend); + TargetRegistry::RegisterAsmTargetStreamer(*T, createTargetAsmStreamer); + } +} diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVObjectTargetWriter.cpp b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVObjectTargetWriter.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVObjectTargetWriter.cpp @@ -0,0 +1,25 @@ +//===- SPIRVObjectTargetWriter.cpp - SPIR-V Object Target Writer *- 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 "SPIRVMCTargetDesc.h" +#include "llvm/MC/MCSPIRVObjectWriter.h" + +using namespace llvm; + +namespace { + +class SPIRVObjectTargetWriter : public MCSPIRVObjectTargetWriter { +public: + SPIRVObjectTargetWriter() = default; +}; + +} // namespace + +std::unique_ptr llvm::createSPIRVObjectTargetWriter() { + return std::make_unique(); +} diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVTargetStreamer.h b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVTargetStreamer.h new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVTargetStreamer.h @@ -0,0 +1,28 @@ +//===-- SPIRVTargetStreamer.h - SPIRV 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 LIB_TARGET_SPIRV_MCTARGETDESC_SPIRVTARGETSTREAMER_H +#define LIB_TARGET_SPIRV_MCTARGETDESC_SPIRVTARGETSTREAMER_H + +#include "llvm/MC/MCStreamer.h" + +namespace llvm { + +class MCSection; + +class SPIRVTargetStreamer : public MCTargetStreamer { +public: + SPIRVTargetStreamer(MCStreamer &S); + ~SPIRVTargetStreamer() override; + + void changeSection(const MCSection *CurSection, MCSection *Section, + const MCExpr *SubSection, raw_ostream &OS) override{}; +}; +} // namespace llvm + +#endif // LIB_TARGET_SPIRV_MCTARGETDESC_SPIRVTARGETSTREAMER_H_ diff --git a/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVTargetStreamer.cpp b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVTargetStreamer.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVTargetStreamer.cpp @@ -0,0 +1,18 @@ +//=====- SPIRVTargetStreamer.cpp - SPIRVTargetStreamer class ------------=====// +// +// 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 implements the SPIRVTargetStreamer class. +// +//===----------------------------------------------------------------------===// + +#include "SPIRVTargetStreamer.h" + +using namespace llvm; + +SPIRVTargetStreamer::SPIRVTargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {} +SPIRVTargetStreamer::~SPIRVTargetStreamer() {} diff --git a/llvm/lib/Target/SPIRV/TargetInfo/SPIRVTargetInfo.cpp b/llvm/lib/Target/SPIRV/TargetInfo/SPIRVTargetInfo.cpp --- a/llvm/lib/Target/SPIRV/TargetInfo/SPIRVTargetInfo.cpp +++ b/llvm/lib/Target/SPIRV/TargetInfo/SPIRVTargetInfo.cpp @@ -26,8 +26,3 @@ RegisterTarget Y(getTheSPIRV64Target(), "spirv64", "SPIR-V 64-bit", "SPIRV"); } - -// FIXME: Temporary stub - this function must be defined for linking -// to succeed and will be called unconditionally by llc, so must be a no-op. -// Remove once this function is properly implemented. -extern "C" void LLVMInitializeSPIRVTargetMC() {} diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp --- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -2110,6 +2110,7 @@ case Triple::MachO: return "__DATA,__asan_globals,regular"; case Triple::Wasm: case Triple::GOFF: + case Triple::SPIRV: case Triple::XCOFF: case Triple::DXContainer: report_fatal_error( diff --git a/llvm/unittests/ADT/TripleTest.cpp b/llvm/unittests/ADT/TripleTest.cpp --- a/llvm/unittests/ADT/TripleTest.cpp +++ b/llvm/unittests/ADT/TripleTest.cpp @@ -999,11 +999,13 @@ EXPECT_FALSE(T.isArch16Bit()); EXPECT_TRUE(T.isArch32Bit()); EXPECT_FALSE(T.isArch64Bit()); + EXPECT_TRUE(T.isSPIRV()); T.setArch(Triple::spirv64); EXPECT_FALSE(T.isArch16Bit()); EXPECT_FALSE(T.isArch32Bit()); EXPECT_TRUE(T.isArch64Bit()); + EXPECT_TRUE(T.isSPIRV()); T.setArch(Triple::sparc); EXPECT_FALSE(T.isArch16Bit()); @@ -1671,6 +1673,9 @@ EXPECT_EQ(Triple::ELF, Triple("csky-unknown-unknown").getObjectFormat()); EXPECT_EQ(Triple::ELF, Triple("csky-unknown-linux").getObjectFormat()); + EXPECT_EQ(Triple::SPIRV, Triple("spirv32-unknown-unknown").getObjectFormat()); + EXPECT_EQ(Triple::SPIRV, Triple("spirv64-unknown-unknown").getObjectFormat()); + EXPECT_EQ(Triple::ELF, Triple("loongarch32-unknown-unknown").getObjectFormat()); EXPECT_EQ(Triple::ELF, Triple("loongarch64-unknown-linux").getObjectFormat()); @@ -1702,6 +1707,9 @@ T.setObjectFormat(Triple::GOFF); EXPECT_EQ(Triple::GOFF, T.getObjectFormat()); + + T.setObjectFormat(Triple::SPIRV); + EXPECT_EQ(Triple::SPIRV, T.getObjectFormat()); } TEST(TripleTest, NormalizeWindows) {