| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<MCFixup, 0> 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<MCAsmBackend> &&MAB, | ||
| std::unique_ptr<MCObjectWriter> &&OW, | ||
| std::unique_ptr<MCCodeEmitter> &&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; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<MCSPIRVObjectTargetWriter> TargetObjectWriter; | ||
|
|
||
| public: | ||
| SPIRVObjectWriter(std::unique_ptr<MCSPIRVObjectTargetWriter> 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<uint32_t>(MagicNumber); | ||
| W.write<uint32_t>(VersionNumber); | ||
| W.write<uint32_t>(GeneratorMagicNumber); | ||
| W.write<uint32_t>(Bound); | ||
| W.write<uint32_t>(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<MCObjectWriter> | ||
| llvm::createSPIRVObjectWriter(std::unique_ptr<MCSPIRVObjectTargetWriter> MOTW, | ||
| raw_pwrite_stream &OS) { | ||
| return std::make_unique<SPIRVObjectWriter>(std::move(MOTW), OS); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| add_llvm_component_group(SPIRV) | ||
|
|
||
| set(LLVM_TARGET_DEFINITIONS SPIRV.td) | ||
|
|
||
| tablegen(LLVM SPIRVGenAsmWriter.inc -gen-asm-writer) | ||
| tablegen(LLVM SPIRVGenGlobalISel.inc -gen-global-isel) | ||
| tablegen(LLVM SPIRVGenInstrInfo.inc -gen-instr-info) | ||
| tablegen(LLVM SPIRVGenMCCodeEmitter.inc -gen-emitter) | ||
| tablegen(LLVM SPIRVGenRegisterBank.inc -gen-register-bank) | ||
| tablegen(LLVM SPIRVGenRegisterInfo.inc -gen-register-info) | ||
| tablegen(LLVM SPIRVGenSubtargetInfo.inc -gen-subtarget) | ||
|
|
||
| add_public_tablegen_target(SPIRVCommonTableGen) | ||
|
|
||
| add_llvm_target(SPIRVCodeGen | ||
| SPIRVAsmPrinter.cpp | ||
| SPIRVCallLowering.cpp | ||
| SPIRVGlobalRegistry.cpp | ||
| SPIRVInstrInfo.cpp | ||
| SPIRVInstructionSelector.cpp | ||
| SPIRVISelLowering.cpp | ||
| SPIRVLegalizerInfo.cpp | ||
| SPIRVMCInstLower.cpp | ||
| SPIRVModuleAnalysis.cpp | ||
| SPIRVRegisterBankInfo.cpp | ||
| SPIRVRegisterInfo.cpp | ||
| SPIRVSubtarget.cpp | ||
| SPIRVTargetMachine.cpp | ||
| SPIRVUtils.cpp | ||
|
|
||
| LINK_COMPONENTS | ||
| Analysis | ||
| AsmPrinter | ||
| CodeGen | ||
| Core | ||
| GlobalISel | ||
| MC | ||
| SPIRVDesc | ||
| SPIRVInfo | ||
| SelectionDAG | ||
| Support | ||
| Target | ||
|
|
||
| ADD_TO_COMPONENT | ||
| SPIRV | ||
| ) | ||
|
|
||
| add_subdirectory(MCTargetDesc) | ||
| add_subdirectory(TargetInfo) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| add_llvm_component_library(LLVMSPIRVDesc | ||
| SPIRVBaseInfo.cpp | ||
| SPIRVMCAsmInfo.cpp | ||
| SPIRVMCTargetDesc.cpp | ||
| SPIRVTargetStreamer.cpp | ||
| SPIRVAsmBackend.cpp | ||
| SPIRVMCCodeEmitter.cpp | ||
| SPIRVObjectTargetWriter.cpp | ||
| SPIRVInstPrinter.cpp | ||
|
|
||
| LINK_COMPONENTS | ||
| MC | ||
| SPIRVInfo | ||
| Support | ||
|
|
||
| ADD_TO_COMPONENT | ||
| SPIRV | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<char> Data, | ||
| uint64_t Value, bool IsResolved, | ||
| const MCSubtargetInfo *STI) const override {} | ||
|
|
||
| std::unique_ptr<MCObjectTargetWriter> | ||
| 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); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<const char *, uint64_t> 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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<MCFixup> &Fixups, | ||
| const MCSubtargetInfo &STI) const; | ||
|
|
||
| void encodeInstruction(const MCInst &MI, raw_ostream &OS, | ||
| SmallVectorImpl<MCFixup> &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<uint32_t>(Register::virtReg2Index(Op.getReg()) + 1); | ||
| } else if (Op.isImm()) { | ||
| OSE.write<uint32_t>(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<MCFixup> &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<uint32_t>(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" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<MCAsmBackend> &&MAB, | ||
| std::unique_ptr<MCObjectWriter> &&OW, | ||
| std::unique_ptr<MCCodeEmitter> &&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<SPIRVMCAsmInfo> 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); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 <memory> | ||
|
|
||
| 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<MCObjectTargetWriter> 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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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<MCObjectTargetWriter> llvm::createSPIRVObjectTargetWriter() { | ||
| return std::make_unique<SPIRVObjectTargetWriter>(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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() {} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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_ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| //===-- SPIRV.h - Top-level interface for SPIR-V representation -*- 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_SPIRV_SPIRV_H | ||
| #define LLVM_LIB_TARGET_SPIRV_SPIRV_H | ||
|
|
||
| #include "MCTargetDesc/SPIRVMCTargetDesc.h" | ||
| #include "llvm/CodeGen/MachineFunctionPass.h" | ||
| #include "llvm/Target/TargetMachine.h" | ||
|
|
||
| namespace llvm { | ||
| class SPIRVTargetMachine; | ||
| class SPIRVSubtarget; | ||
| class InstructionSelector; | ||
| class RegisterBankInfo; | ||
|
|
||
| InstructionSelector * | ||
| createSPIRVInstructionSelector(const SPIRVTargetMachine &TM, | ||
| const SPIRVSubtarget &Subtarget, | ||
| const RegisterBankInfo &RBI); | ||
|
|
||
| void initializeSPIRVModuleAnalysisPass(PassRegistry &); | ||
| } // namespace llvm | ||
|
|
||
| #endif // LLVM_LIB_TARGET_SPIRV_SPIRV_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| //===-- SPIRV.td - Describe the SPIR-V Target Machine ------*- tablegen -*-===// | ||
| // | ||
| // 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/Target/Target.td" | ||
|
|
||
| include "SPIRVRegisterInfo.td" | ||
| include "SPIRVRegisterBanks.td" | ||
| include "SPIRVInstrInfo.td" | ||
|
|
||
| def SPIRVInstrInfo : InstrInfo; | ||
|
|
||
| class Proc<string Name, list<SubtargetFeature> Features> | ||
| : Processor<Name, NoItineraries, Features>; | ||
|
|
||
| def : Proc<"generic", []>; | ||
|
|
||
| def SPIRV10 : SubtargetFeature<"spirv1.0", "SPIRVVersion", "10", | ||
| "Use SPIR-V version 1.0">; | ||
| def SPIRV11 : SubtargetFeature<"spirv1.1", "SPIRVVersion", "11", | ||
| "Use SPIR-V version 1.1">; | ||
| def SPIRV12 : SubtargetFeature<"spirv1.2", "SPIRVVersion", "12", | ||
| "Use SPIR-V version 1.2">; | ||
| def SPIRV13 : SubtargetFeature<"spirv1.3", "SPIRVVersion", "13", | ||
| "Use SPIR-V version 1.3">; | ||
| def SPIRV14 : SubtargetFeature<"spirv1.4", "SPIRVVersion", "14", | ||
| "Use SPIR-V version 1.4">; | ||
| def SPIRV15 : SubtargetFeature<"spirv1.5", "SPIRVVersion", "15", | ||
| "Use SPIR-V version 1.5">; | ||
|
|
||
| def SPIRVInstPrinter : AsmWriter { | ||
| string AsmWriterClassName = "InstPrinter"; | ||
| bit isMCAsmWriter = 1; | ||
| } | ||
|
|
||
| def SPIRV : Target { | ||
| let InstructionSet = SPIRVInstrInfo; | ||
| let AssemblyWriters = [SPIRVInstPrinter]; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,348 @@ | ||
| //===-- SPIRVAsmPrinter.cpp - SPIR-V LLVM assembly 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This file contains a printer that converts from our internal representation | ||
| // of machine-dependent LLVM code to the SPIR-V assembly language. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "MCTargetDesc/SPIRVInstPrinter.h" | ||
| #include "SPIRV.h" | ||
| #include "SPIRVInstrInfo.h" | ||
| #include "SPIRVMCInstLower.h" | ||
| #include "SPIRVModuleAnalysis.h" | ||
| #include "SPIRVSubtarget.h" | ||
| #include "SPIRVTargetMachine.h" | ||
| #include "SPIRVUtils.h" | ||
| #include "TargetInfo/SPIRVTargetInfo.h" | ||
| #include "llvm/ADT/DenseMap.h" | ||
| #include "llvm/CodeGen/AsmPrinter.h" | ||
| #include "llvm/CodeGen/MachineConstantPool.h" | ||
| #include "llvm/CodeGen/MachineFunctionPass.h" | ||
| #include "llvm/CodeGen/MachineInstr.h" | ||
| #include "llvm/CodeGen/MachineModuleInfo.h" | ||
| #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" | ||
| #include "llvm/MC/MCAsmInfo.h" | ||
| #include "llvm/MC/MCInst.h" | ||
| #include "llvm/MC/MCStreamer.h" | ||
| #include "llvm/MC/MCSymbol.h" | ||
| #include "llvm/MC/TargetRegistry.h" | ||
| #include "llvm/Support/raw_ostream.h" | ||
|
|
||
| using namespace llvm; | ||
|
|
||
| #define DEBUG_TYPE "asm-printer" | ||
|
|
||
| namespace { | ||
| class SPIRVAsmPrinter : public AsmPrinter { | ||
| public: | ||
| explicit SPIRVAsmPrinter(TargetMachine &TM, | ||
| std::unique_ptr<MCStreamer> Streamer) | ||
| : AsmPrinter(TM, std::move(Streamer)), ST(nullptr), TII(nullptr) {} | ||
| bool ModuleSectionsEmitted; | ||
| const SPIRVSubtarget *ST; | ||
| const SPIRVInstrInfo *TII; | ||
|
|
||
| StringRef getPassName() const override { return "SPIRV Assembly Printer"; } | ||
| void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &O); | ||
| bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, | ||
| const char *ExtraCode, raw_ostream &O) override; | ||
|
|
||
| void outputMCInst(MCInst &Inst); | ||
| void outputInstruction(const MachineInstr *MI); | ||
| void outputModuleSection(SPIRV::ModuleSectionType MSType); | ||
| void outputEntryPoints(); | ||
| void outputDebugSourceAndStrings(const Module &M); | ||
| void outputOpMemoryModel(); | ||
| void outputOpFunctionEnd(); | ||
| void outputExtFuncDecls(); | ||
| void outputModuleSections(); | ||
|
|
||
| void emitInstruction(const MachineInstr *MI) override; | ||
| void emitFunctionEntryLabel() override {} | ||
| void emitFunctionHeader() override; | ||
| void emitFunctionBodyStart() override {} | ||
| void emitFunctionBodyEnd() override; | ||
| void emitBasicBlockStart(const MachineBasicBlock &MBB) override; | ||
| void emitBasicBlockEnd(const MachineBasicBlock &MBB) override {} | ||
| void emitGlobalVariable(const GlobalVariable *GV) override {} | ||
| void emitOpLabel(const MachineBasicBlock &MBB); | ||
| void emitEndOfAsmFile(Module &M) override; | ||
| bool doInitialization(Module &M) override; | ||
|
|
||
| void getAnalysisUsage(AnalysisUsage &AU) const override; | ||
| SPIRV::ModuleAnalysisInfo *MAI; | ||
| }; | ||
| } // namespace | ||
|
|
||
| void SPIRVAsmPrinter::getAnalysisUsage(AnalysisUsage &AU) const { | ||
| AU.addRequired<SPIRVModuleAnalysis>(); | ||
| AU.addPreserved<SPIRVModuleAnalysis>(); | ||
| AsmPrinter::getAnalysisUsage(AU); | ||
| } | ||
|
|
||
| // If the module has no functions, we need output global info anyway. | ||
| void SPIRVAsmPrinter::emitEndOfAsmFile(Module &M) { | ||
| if (ModuleSectionsEmitted == false) { | ||
| outputModuleSections(); | ||
| ModuleSectionsEmitted = true; | ||
| } | ||
| } | ||
|
|
||
| void SPIRVAsmPrinter::emitFunctionHeader() { | ||
| if (ModuleSectionsEmitted == false) { | ||
| outputModuleSections(); | ||
| ModuleSectionsEmitted = true; | ||
| } | ||
| // Get the subtarget from the current MachineFunction. | ||
| ST = &MF->getSubtarget<SPIRVSubtarget>(); | ||
| TII = ST->getInstrInfo(); | ||
| const Function &F = MF->getFunction(); | ||
|
|
||
| if (isVerbose()) { | ||
| OutStreamer->GetCommentOS() | ||
| << "-- Begin function " | ||
| << GlobalValue::dropLLVMManglingEscape(F.getName()) << '\n'; | ||
| } | ||
|
|
||
| auto Section = getObjFileLowering().SectionForGlobal(&F, TM); | ||
| MF->setSection(Section); | ||
| } | ||
|
|
||
| void SPIRVAsmPrinter::outputOpFunctionEnd() { | ||
| MCInst FunctionEndInst; | ||
| FunctionEndInst.setOpcode(SPIRV::OpFunctionEnd); | ||
| outputMCInst(FunctionEndInst); | ||
| } | ||
|
|
||
| // Emit OpFunctionEnd at the end of MF and clear BBNumToRegMap. | ||
| void SPIRVAsmPrinter::emitFunctionBodyEnd() { | ||
| outputOpFunctionEnd(); | ||
| MAI->BBNumToRegMap.clear(); | ||
| } | ||
|
|
||
| void SPIRVAsmPrinter::emitOpLabel(const MachineBasicBlock &MBB) { | ||
| MCInst LabelInst; | ||
| LabelInst.setOpcode(SPIRV::OpLabel); | ||
| LabelInst.addOperand(MCOperand::createReg(MAI->getOrCreateMBBRegister(MBB))); | ||
| outputMCInst(LabelInst); | ||
| } | ||
|
|
||
| void SPIRVAsmPrinter::emitBasicBlockStart(const MachineBasicBlock &MBB) { | ||
| // If it's the first MBB in MF, it has OpFunction and OpFunctionParameter, so | ||
| // OpLabel should be output after them. | ||
| if (MBB.getNumber() == MF->front().getNumber()) { | ||
| for (const MachineInstr &MI : MBB) | ||
| if (MI.getOpcode() == SPIRV::OpFunction) | ||
| return; | ||
| // TODO: this case should be checked by the verifier. | ||
| report_fatal_error("OpFunction is expected in the front MBB of MF"); | ||
| } | ||
| emitOpLabel(MBB); | ||
| } | ||
|
|
||
| void SPIRVAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, | ||
| raw_ostream &O) { | ||
| const MachineOperand &MO = MI->getOperand(OpNum); | ||
|
|
||
| switch (MO.getType()) { | ||
| case MachineOperand::MO_Register: | ||
| O << SPIRVInstPrinter::getRegisterName(MO.getReg()); | ||
| break; | ||
|
|
||
| case MachineOperand::MO_Immediate: | ||
| O << MO.getImm(); | ||
| break; | ||
|
|
||
| case MachineOperand::MO_FPImmediate: | ||
| O << MO.getFPImm(); | ||
| break; | ||
|
|
||
| case MachineOperand::MO_MachineBasicBlock: | ||
| O << *MO.getMBB()->getSymbol(); | ||
| break; | ||
|
|
||
| case MachineOperand::MO_GlobalAddress: | ||
| O << *getSymbol(MO.getGlobal()); | ||
| break; | ||
|
|
||
| case MachineOperand::MO_BlockAddress: { | ||
| MCSymbol *BA = GetBlockAddressSymbol(MO.getBlockAddress()); | ||
| O << BA->getName(); | ||
| break; | ||
| } | ||
|
|
||
| case MachineOperand::MO_ExternalSymbol: | ||
| O << *GetExternalSymbolSymbol(MO.getSymbolName()); | ||
| break; | ||
|
|
||
| case MachineOperand::MO_JumpTableIndex: | ||
| case MachineOperand::MO_ConstantPoolIndex: | ||
| default: | ||
| llvm_unreachable("<unknown operand type>"); | ||
| } | ||
| } | ||
|
|
||
| bool SPIRVAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, | ||
| const char *ExtraCode, raw_ostream &O) { | ||
| if (ExtraCode && ExtraCode[0]) | ||
| return true; // Invalid instruction - SPIR-V does not have special modifiers | ||
|
|
||
| printOperand(MI, OpNo, O); | ||
| return false; | ||
| } | ||
|
|
||
| static bool isFuncOrHeaderInstr(const MachineInstr *MI, | ||
| const SPIRVInstrInfo *TII) { | ||
| return TII->isHeaderInstr(*MI) || MI->getOpcode() == SPIRV::OpFunction || | ||
| MI->getOpcode() == SPIRV::OpFunctionParameter; | ||
| } | ||
|
|
||
| void SPIRVAsmPrinter::outputMCInst(MCInst &Inst) { | ||
| OutStreamer->emitInstruction(Inst, *OutContext.getSubtargetInfo()); | ||
| } | ||
|
|
||
| void SPIRVAsmPrinter::outputInstruction(const MachineInstr *MI) { | ||
| SPIRVMCInstLower MCInstLowering; | ||
| MCInst TmpInst; | ||
| MCInstLowering.lower(MI, TmpInst, MAI); | ||
| outputMCInst(TmpInst); | ||
| } | ||
|
|
||
| void SPIRVAsmPrinter::emitInstruction(const MachineInstr *MI) { | ||
| if (!MAI->getSkipEmission(MI)) | ||
| outputInstruction(MI); | ||
|
|
||
| // Output OpLabel after OpFunction and OpFunctionParameter in the first MBB. | ||
| const MachineInstr *NextMI = MI->getNextNode(); | ||
| if (!MAI->hasMBBRegister(*MI->getParent()) && isFuncOrHeaderInstr(MI, TII) && | ||
| (!NextMI || !isFuncOrHeaderInstr(NextMI, TII))) { | ||
| assert(MI->getParent()->getNumber() == MF->front().getNumber() && | ||
| "OpFunction is not in the front MBB of MF"); | ||
| emitOpLabel(*MI->getParent()); | ||
| } | ||
| } | ||
|
|
||
| void SPIRVAsmPrinter::outputModuleSection(SPIRV::ModuleSectionType MSType) { | ||
| for (MachineInstr *MI : MAI->getMSInstrs(MSType)) | ||
| outputInstruction(MI); | ||
| } | ||
|
|
||
| void SPIRVAsmPrinter::outputDebugSourceAndStrings(const Module &M) { | ||
| // Output OpSource. | ||
| MCInst Inst; | ||
| Inst.setOpcode(SPIRV::OpSource); | ||
| Inst.addOperand(MCOperand::createImm(static_cast<unsigned>(MAI->SrcLang))); | ||
| Inst.addOperand( | ||
| MCOperand::createImm(static_cast<unsigned>(MAI->SrcLangVersion))); | ||
| outputMCInst(Inst); | ||
| } | ||
|
|
||
| void SPIRVAsmPrinter::outputOpMemoryModel() { | ||
| MCInst Inst; | ||
| Inst.setOpcode(SPIRV::OpMemoryModel); | ||
| Inst.addOperand(MCOperand::createImm(static_cast<unsigned>(MAI->Addr))); | ||
| Inst.addOperand(MCOperand::createImm(static_cast<unsigned>(MAI->Mem))); | ||
| outputMCInst(Inst); | ||
| } | ||
|
|
||
| // Before the OpEntryPoints' output, we need to add the entry point's | ||
| // interfaces. The interface is a list of IDs of global OpVariable instructions. | ||
| // These declare the set of global variables from a module that form | ||
| // the interface of this entry point. | ||
| void SPIRVAsmPrinter::outputEntryPoints() { | ||
| // Find all OpVariable IDs with required StorageClass. | ||
| DenseSet<Register> InterfaceIDs; | ||
| for (MachineInstr *MI : MAI->GlobalVarList) { | ||
| assert(MI->getOpcode() == SPIRV::OpVariable); | ||
| auto SC = static_cast<SPIRV::StorageClass>(MI->getOperand(2).getImm()); | ||
| // Before version 1.4, the interface's storage classes are limited to | ||
| // the Input and Output storage classes. Starting with version 1.4, | ||
| // the interface's storage classes are all storage classes used in | ||
| // declaring all global variables referenced by the entry point call tree. | ||
| if (ST->getSPIRVVersion() >= 14 || SC == SPIRV::StorageClass::Input || | ||
| SC == SPIRV::StorageClass::Output) { | ||
| MachineFunction *MF = MI->getMF(); | ||
| Register Reg = MAI->getRegisterAlias(MF, MI->getOperand(0).getReg()); | ||
| InterfaceIDs.insert(Reg); | ||
| } | ||
| } | ||
|
|
||
| // Output OpEntryPoints adding interface args to all of them. | ||
| for (MachineInstr *MI : MAI->getMSInstrs(SPIRV::MB_EntryPoints)) { | ||
| SPIRVMCInstLower MCInstLowering; | ||
| MCInst TmpInst; | ||
| MCInstLowering.lower(MI, TmpInst, MAI); | ||
| for (Register Reg : InterfaceIDs) { | ||
| assert(Reg.isValid()); | ||
| TmpInst.addOperand(MCOperand::createReg(Reg)); | ||
| } | ||
| outputMCInst(TmpInst); | ||
| } | ||
| } | ||
|
|
||
| void SPIRVAsmPrinter::outputExtFuncDecls() { | ||
| // Insert OpFunctionEnd after each declaration. | ||
| SmallVectorImpl<MachineInstr *>::iterator | ||
| I = MAI->getMSInstrs(SPIRV::MB_ExtFuncDecls).begin(), | ||
| E = MAI->getMSInstrs(SPIRV::MB_ExtFuncDecls).end(); | ||
| for (; I != E; ++I) { | ||
| outputInstruction(*I); | ||
| if ((I + 1) == E || (*(I + 1))->getOpcode() == SPIRV::OpFunction) | ||
| outputOpFunctionEnd(); | ||
| } | ||
| } | ||
|
|
||
| void SPIRVAsmPrinter::outputModuleSections() { | ||
| const Module *M = MMI->getModule(); | ||
| // Get the global subtarget to output module-level info. | ||
| ST = static_cast<const SPIRVTargetMachine &>(TM).getSubtargetImpl(); | ||
| TII = ST->getInstrInfo(); | ||
| MAI = &SPIRVModuleAnalysis::MAI; | ||
| assert(ST && TII && MAI && M && "Module analysis is required"); | ||
| // Output instructions according to the Logical Layout of a Module: | ||
| // TODO: 1,2. All OpCapability instructions, then optional OpExtension | ||
| // instructions. | ||
| // TODO: 3. Optional OpExtInstImport instructions. | ||
| // 4. The single required OpMemoryModel instruction. | ||
| outputOpMemoryModel(); | ||
| // 5. All entry point declarations, using OpEntryPoint. | ||
| outputEntryPoints(); | ||
| // 6. Execution-mode declarations, using OpExecutionMode or OpExecutionModeId. | ||
| // TODO: | ||
| // 7a. Debug: all OpString, OpSourceExtension, OpSource, and | ||
| // OpSourceContinued, without forward references. | ||
| outputDebugSourceAndStrings(*M); | ||
| // 7b. Debug: all OpName and all OpMemberName. | ||
| outputModuleSection(SPIRV::MB_DebugNames); | ||
| // 7c. Debug: all OpModuleProcessed instructions. | ||
| outputModuleSection(SPIRV::MB_DebugModuleProcessed); | ||
| // 8. All annotation instructions (all decorations). | ||
| outputModuleSection(SPIRV::MB_Annotations); | ||
| // 9. All type declarations (OpTypeXXX instructions), all constant | ||
| // instructions, and all global variable declarations. This section is | ||
| // the first section to allow use of: OpLine and OpNoLine debug information; | ||
| // non-semantic instructions with OpExtInst. | ||
| outputModuleSection(SPIRV::MB_TypeConstVars); | ||
| // 10. All function declarations (functions without a body). | ||
| outputExtFuncDecls(); | ||
| // 11. All function definitions (functions with a body). | ||
| // This is done in regular function output. | ||
| } | ||
|
|
||
| bool SPIRVAsmPrinter::doInitialization(Module &M) { | ||
| ModuleSectionsEmitted = false; | ||
| // We need to call the parent's one explicitly. | ||
| return AsmPrinter::doInitialization(M); | ||
| } | ||
|
|
||
| // Force static initialization. | ||
| extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSPIRVAsmPrinter() { | ||
| RegisterAsmPrinter<SPIRVAsmPrinter> X(getTheSPIRV32Target()); | ||
| RegisterAsmPrinter<SPIRVAsmPrinter> Y(getTheSPIRV64Target()); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,223 @@ | ||
| //===--- SPIRVCallLowering.cpp - Call lowering ------------------*- 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 lowering of LLVM calls to machine code calls for | ||
| // GlobalISel. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "SPIRVCallLowering.h" | ||
| #include "MCTargetDesc/SPIRVBaseInfo.h" | ||
| #include "SPIRV.h" | ||
| #include "SPIRVGlobalRegistry.h" | ||
| #include "SPIRVISelLowering.h" | ||
| #include "SPIRVRegisterInfo.h" | ||
| #include "SPIRVSubtarget.h" | ||
| #include "SPIRVUtils.h" | ||
| #include "llvm/CodeGen/FunctionLoweringInfo.h" | ||
|
|
||
| using namespace llvm; | ||
|
|
||
| SPIRVCallLowering::SPIRVCallLowering(const SPIRVTargetLowering &TLI, | ||
| const SPIRVSubtarget &ST, | ||
| SPIRVGlobalRegistry *GR) | ||
| : CallLowering(&TLI), ST(ST), GR(GR) {} | ||
|
|
||
| bool SPIRVCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder, | ||
| const Value *Val, ArrayRef<Register> VRegs, | ||
| FunctionLoweringInfo &FLI, | ||
| Register SwiftErrorVReg) const { | ||
| // Currently all return types should use a single register. | ||
| // TODO: handle the case of multiple registers. | ||
| if (VRegs.size() > 1) | ||
| return false; | ||
| if (Val) | ||
| return MIRBuilder.buildInstr(SPIRV::OpReturnValue) | ||
| .addUse(VRegs[0]) | ||
| .constrainAllUses(MIRBuilder.getTII(), *ST.getRegisterInfo(), | ||
| *ST.getRegBankInfo()); | ||
| MIRBuilder.buildInstr(SPIRV::OpReturn); | ||
| return true; | ||
| } | ||
|
|
||
| // Based on the LLVM function attributes, get a SPIR-V FunctionControl. | ||
| static uint32_t getFunctionControl(const Function &F) { | ||
| uint32_t FuncControl = static_cast<uint32_t>(SPIRV::FunctionControl::None); | ||
| if (F.hasFnAttribute(Attribute::AttrKind::AlwaysInline)) { | ||
| FuncControl |= static_cast<uint32_t>(SPIRV::FunctionControl::Inline); | ||
| } | ||
| if (F.hasFnAttribute(Attribute::AttrKind::ReadNone)) { | ||
| FuncControl |= static_cast<uint32_t>(SPIRV::FunctionControl::Pure); | ||
| } | ||
| if (F.hasFnAttribute(Attribute::AttrKind::ReadOnly)) { | ||
| FuncControl |= static_cast<uint32_t>(SPIRV::FunctionControl::Const); | ||
| } | ||
| if (F.hasFnAttribute(Attribute::AttrKind::NoInline)) { | ||
| FuncControl |= static_cast<uint32_t>(SPIRV::FunctionControl::DontInline); | ||
| } | ||
| return FuncControl; | ||
| } | ||
|
|
||
| bool SPIRVCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder, | ||
| const Function &F, | ||
| ArrayRef<ArrayRef<Register>> VRegs, | ||
| FunctionLoweringInfo &FLI) const { | ||
| assert(GR && "Must initialize the SPIRV type registry before lowering args."); | ||
|
|
||
| // Assign types and names to all args, and store their types for later. | ||
| SmallVector<Register, 4> ArgTypeVRegs; | ||
| if (VRegs.size() > 0) { | ||
| unsigned i = 0; | ||
| for (const auto &Arg : F.args()) { | ||
| // Currently formal args should use single registers. | ||
| // TODO: handle the case of multiple registers. | ||
| if (VRegs[i].size() > 1) | ||
| return false; | ||
| auto *SpirvTy = | ||
| GR->assignTypeToVReg(Arg.getType(), VRegs[i][0], MIRBuilder); | ||
| ArgTypeVRegs.push_back(GR->getSPIRVTypeID(SpirvTy)); | ||
|
|
||
| if (Arg.hasName()) | ||
| buildOpName(VRegs[i][0], Arg.getName(), MIRBuilder); | ||
| if (Arg.getType()->isPointerTy()) { | ||
| auto DerefBytes = static_cast<unsigned>(Arg.getDereferenceableBytes()); | ||
| if (DerefBytes != 0) | ||
| buildOpDecorate(VRegs[i][0], MIRBuilder, | ||
| SPIRV::Decoration::MaxByteOffset, {DerefBytes}); | ||
| } | ||
| if (Arg.hasAttribute(Attribute::Alignment)) { | ||
| buildOpDecorate(VRegs[i][0], MIRBuilder, SPIRV::Decoration::Alignment, | ||
| {static_cast<unsigned>(Arg.getParamAlignment())}); | ||
| } | ||
| if (Arg.hasAttribute(Attribute::ReadOnly)) { | ||
| auto Attr = | ||
| static_cast<unsigned>(SPIRV::FunctionParameterAttribute::NoWrite); | ||
| buildOpDecorate(VRegs[i][0], MIRBuilder, | ||
| SPIRV::Decoration::FuncParamAttr, {Attr}); | ||
| } | ||
| if (Arg.hasAttribute(Attribute::ZExt)) { | ||
| auto Attr = | ||
| static_cast<unsigned>(SPIRV::FunctionParameterAttribute::Zext); | ||
| buildOpDecorate(VRegs[i][0], MIRBuilder, | ||
| SPIRV::Decoration::FuncParamAttr, {Attr}); | ||
| } | ||
| ++i; | ||
| } | ||
| } | ||
|
|
||
| // Generate a SPIR-V type for the function. | ||
| auto MRI = MIRBuilder.getMRI(); | ||
| Register FuncVReg = MRI->createGenericVirtualRegister(LLT::scalar(32)); | ||
| MRI->setRegClass(FuncVReg, &SPIRV::IDRegClass); | ||
|
|
||
| auto *FTy = F.getFunctionType(); | ||
| auto FuncTy = GR->assignTypeToVReg(FTy, FuncVReg, MIRBuilder); | ||
|
|
||
| // Build the OpTypeFunction declaring it. | ||
| Register ReturnTypeID = FuncTy->getOperand(1).getReg(); | ||
| uint32_t FuncControl = getFunctionControl(F); | ||
|
|
||
| MIRBuilder.buildInstr(SPIRV::OpFunction) | ||
| .addDef(FuncVReg) | ||
| .addUse(ReturnTypeID) | ||
| .addImm(FuncControl) | ||
| .addUse(GR->getSPIRVTypeID(FuncTy)); | ||
|
|
||
| // Add OpFunctionParameters. | ||
| const unsigned NumArgs = ArgTypeVRegs.size(); | ||
| for (unsigned i = 0; i < NumArgs; ++i) { | ||
| assert(VRegs[i].size() == 1 && "Formal arg has multiple vregs"); | ||
| MRI->setRegClass(VRegs[i][0], &SPIRV::IDRegClass); | ||
| MIRBuilder.buildInstr(SPIRV::OpFunctionParameter) | ||
| .addDef(VRegs[i][0]) | ||
| .addUse(ArgTypeVRegs[i]); | ||
| } | ||
| // Name the function. | ||
| if (F.hasName()) | ||
| buildOpName(FuncVReg, F.getName(), MIRBuilder); | ||
|
|
||
| // Handle entry points and function linkage. | ||
| if (F.getCallingConv() == CallingConv::SPIR_KERNEL) { | ||
| auto MIB = MIRBuilder.buildInstr(SPIRV::OpEntryPoint) | ||
| .addImm(static_cast<uint32_t>(SPIRV::ExecutionModel::Kernel)) | ||
| .addUse(FuncVReg); | ||
| addStringImm(F.getName(), MIB); | ||
| } else if (F.getLinkage() == GlobalValue::LinkageTypes::ExternalLinkage || | ||
| F.getLinkage() == GlobalValue::LinkOnceODRLinkage) { | ||
| auto LnkTy = F.isDeclaration() ? SPIRV::LinkageType::Import | ||
| : SPIRV::LinkageType::Export; | ||
| buildOpDecorate(FuncVReg, MIRBuilder, SPIRV::Decoration::LinkageAttributes, | ||
| {static_cast<uint32_t>(LnkTy)}, F.getGlobalIdentifier()); | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| bool SPIRVCallLowering::lowerCall(MachineIRBuilder &MIRBuilder, | ||
| CallLoweringInfo &Info) const { | ||
| // Currently call returns should have single vregs. | ||
| // TODO: handle the case of multiple registers. | ||
| if (Info.OrigRet.Regs.size() > 1) | ||
| return false; | ||
|
|
||
| Register ResVReg = | ||
| Info.OrigRet.Regs.empty() ? Register(0) : Info.OrigRet.Regs[0]; | ||
| // Emit a regular OpFunctionCall. If it's an externally declared function, | ||
| // be sure to emit its type and function declaration here. It will be | ||
| // hoisted globally later. | ||
| if (Info.Callee.isGlobal()) { | ||
| auto *CF = dyn_cast_or_null<const Function>(Info.Callee.getGlobal()); | ||
| // TODO: support constexpr casts and indirect calls. | ||
| if (CF == nullptr) | ||
| return false; | ||
| if (CF->isDeclaration()) { | ||
| // Emit the type info and forward function declaration to the first MBB | ||
| // to ensure VReg definition dependencies are valid across all MBBs. | ||
| MachineBasicBlock::iterator OldII = MIRBuilder.getInsertPt(); | ||
| MachineBasicBlock &OldBB = MIRBuilder.getMBB(); | ||
| MachineBasicBlock &FirstBB = *MIRBuilder.getMF().getBlockNumbered(0); | ||
| MIRBuilder.setInsertPt(FirstBB, FirstBB.instr_end()); | ||
|
|
||
| SmallVector<ArrayRef<Register>, 8> VRegArgs; | ||
| SmallVector<SmallVector<Register, 1>, 8> ToInsert; | ||
| for (const Argument &Arg : CF->args()) { | ||
| if (MIRBuilder.getDataLayout().getTypeStoreSize(Arg.getType()).isZero()) | ||
| continue; // Don't handle zero sized types. | ||
| ToInsert.push_back({MIRBuilder.getMRI()->createGenericVirtualRegister( | ||
| LLT::scalar(32))}); | ||
| VRegArgs.push_back(ToInsert.back()); | ||
| } | ||
| // TODO: Reuse FunctionLoweringInfo. | ||
| FunctionLoweringInfo FuncInfo; | ||
| lowerFormalArguments(MIRBuilder, *CF, VRegArgs, FuncInfo); | ||
| MIRBuilder.setInsertPt(OldBB, OldII); | ||
| } | ||
| } | ||
|
|
||
| // Make sure there's a valid return reg, even for functions returning void. | ||
| if (!ResVReg.isValid()) { | ||
| ResVReg = MIRBuilder.getMRI()->createVirtualRegister(&SPIRV::IDRegClass); | ||
| } | ||
| SPIRVType *RetType = | ||
| GR->assignTypeToVReg(Info.OrigRet.Ty, ResVReg, MIRBuilder); | ||
|
|
||
| // Emit the OpFunctionCall and its args. | ||
| auto MIB = MIRBuilder.buildInstr(SPIRV::OpFunctionCall) | ||
| .addDef(ResVReg) | ||
| .addUse(GR->getSPIRVTypeID(RetType)) | ||
| .add(Info.Callee); | ||
|
|
||
| for (const auto &Arg : Info.OrigArgs) { | ||
| // Currently call args should have single vregs. | ||
| if (Arg.Regs.size() > 1) | ||
| return false; | ||
| MIB.addUse(Arg.Regs[0]); | ||
| } | ||
| return MIB.constrainAllUses(MIRBuilder.getTII(), *ST.getRegisterInfo(), | ||
| *ST.getRegBankInfo()); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| //===--- SPIRVCallLowering.h - Call lowering --------------------*- 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 describes how to lower LLVM calls to machine code calls. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIB_TARGET_SPIRV_SPIRVCALLLOWERING_H | ||
| #define LLVM_LIB_TARGET_SPIRV_SPIRVCALLLOWERING_H | ||
|
|
||
| #include "llvm/CodeGen/GlobalISel/CallLowering.h" | ||
|
|
||
| namespace llvm { | ||
|
|
||
| class SPIRVGlobalRegistry; | ||
| class SPIRVSubtarget; | ||
| class SPIRVTargetLowering; | ||
|
|
||
| class SPIRVCallLowering : public CallLowering { | ||
| private: | ||
| const SPIRVSubtarget &ST; | ||
| // Used to create and assign function, argument, and return type information. | ||
| SPIRVGlobalRegistry *GR; | ||
|
|
||
| public: | ||
| SPIRVCallLowering(const SPIRVTargetLowering &TLI, const SPIRVSubtarget &ST, | ||
| SPIRVGlobalRegistry *GR); | ||
|
|
||
| // Built OpReturn or OpReturnValue. | ||
| bool lowerReturn(MachineIRBuilder &MIRBuiler, const Value *Val, | ||
| ArrayRef<Register> VRegs, FunctionLoweringInfo &FLI, | ||
| Register SwiftErrorVReg) const override; | ||
|
|
||
| // Build OpFunction, OpFunctionParameter, and any EntryPoint or Linkage data. | ||
| bool lowerFormalArguments(MachineIRBuilder &MIRBuilder, const Function &F, | ||
| ArrayRef<ArrayRef<Register>> VRegs, | ||
| FunctionLoweringInfo &FLI) const override; | ||
|
|
||
| // Build OpCall, or replace with a builtin function. | ||
| bool lowerCall(MachineIRBuilder &MIRBuilder, | ||
| CallLoweringInfo &Info) const override; | ||
| }; | ||
| } // end namespace llvm | ||
|
|
||
| #endif // LLVM_LIB_TARGET_SPIRV_SPIRVCALLLOWERING_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| //===-- SPIRVEnums.td - Describe SPIRV Enum Operands -------*- tablegen -*-===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // All SPIRV enums defined in SPIRVBaseInfo.h should have a corresponding enum | ||
| // operand here. This enables the correct PrintMethod to be defined so | ||
| // its name or mask bits can be automatically printed in SPIRVInstPrinter | ||
| // when referred to in SPIRVInstrInfo.td. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| class EnumOperand<string Name> : Operand<i32>{ | ||
| let PrintMethod = "print"#Name; | ||
| } | ||
|
|
||
| def ExtInst : EnumOperand<"ExtInst">; | ||
|
|
||
| def Capability : EnumOperand<"Capability">; | ||
| def SourceLanguage : EnumOperand<"SourceLanguage">; | ||
| def ExecutionModel : EnumOperand<"ExecutionModel">; | ||
| def AddressingModel : EnumOperand<"AddressingModel">; | ||
| def MemoryModel : EnumOperand<"MemoryModel">; | ||
| def ExecutionMode : EnumOperand<"ExecutionMode">; | ||
| def StorageClass : EnumOperand<"StorageClass">; | ||
| def Dim : EnumOperand<"Dim">; | ||
| def SamplerAddressingMode : EnumOperand<"SamplerAddressingMode">; | ||
| def SamplerFilterMode : EnumOperand<"SamplerFilterMode">; | ||
| def ImageFormat : EnumOperand<"ImageFormat">; | ||
| def ImageChannelOrder : EnumOperand<"ImageChannelOrder">; | ||
| def ImageChannelDataType : EnumOperand<"ImageChannelDataType">; | ||
| def ImageOperand : EnumOperand<"ImageOperand">; | ||
| def FPFastMathMode : EnumOperand<"FPFastMathMode">; | ||
| def FProundingMode : EnumOperand<"FPRoundingMode">; | ||
| def LinkageType : EnumOperand<"LinkageType">; | ||
| def AccessQualifier : EnumOperand<"AccessQualifier">; | ||
| def FunctionParameterAttribute : EnumOperand<"FunctionParameterAttribute">; | ||
| def Decoration : EnumOperand<"Decoration">; | ||
| def Builtin : EnumOperand<"Builtin">; | ||
| def SelectionControl: EnumOperand<"SelectionControl">; | ||
| def LoopControl: EnumOperand<"LoopControl">; | ||
| def FunctionControl : EnumOperand<"FunctionControl">; | ||
| def MemorySemantics : EnumOperand<"MemorySemantics">; | ||
| def MemoryOperand : EnumOperand<"MemoryOperand">; | ||
| def Scope : EnumOperand<"Scope">; | ||
| def GroupOperation : EnumOperand<"GroupOperation">; | ||
| def KernelEnqueueFlags : EnumOperand<"KernelEnqueueFlags">; | ||
| def KernelProfilingInfo : EnumOperand<"KernelProfilingInfo">; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| //===-- SPIRVFrameLowering.h - Define frame lowering for SPIR-V -*- 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 implements SPIRV-specific bits of TargetFrameLowering class. | ||
| // The target uses only virtual registers. It does not operate with stack frame | ||
| // explicitly and does not generate prologues/epilogues of functions. | ||
| // As a result, we are not required to implemented the frame lowering | ||
| // functionality substantially. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIB_TARGET_SPIRV_SPIRVFRAMELOWERING_H | ||
| #define LLVM_LIB_TARGET_SPIRV_SPIRVFRAMELOWERING_H | ||
|
|
||
| #include "llvm/CodeGen/TargetFrameLowering.h" | ||
| #include "llvm/Support/Alignment.h" | ||
|
|
||
| namespace llvm { | ||
| class SPIRVSubtarget; | ||
|
|
||
| class SPIRVFrameLowering : public TargetFrameLowering { | ||
| public: | ||
| explicit SPIRVFrameLowering(const SPIRVSubtarget &sti) | ||
| : TargetFrameLowering(TargetFrameLowering::StackGrowsDown, Align(8), 0) {} | ||
|
|
||
| void emitPrologue(MachineFunction &MF, | ||
| MachineBasicBlock &MBB) const override {} | ||
| void emitEpilogue(MachineFunction &MF, | ||
| MachineBasicBlock &MBB) const override {} | ||
|
|
||
| bool hasFP(const MachineFunction &MF) const override { return false; } | ||
| }; | ||
| } // namespace llvm | ||
| #endif // LLVM_LIB_TARGET_SPIRV_SPIRVFRAMELOWERING_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,174 @@ | ||
| //===-- SPIRVGlobalRegistry.h - SPIR-V Global Registry ----------*- 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // SPIRVGlobalRegistry is used to maintain rich type information required for | ||
| // SPIR-V even after lowering from LLVM IR to GMIR. It can convert an llvm::Type | ||
| // into an OpTypeXXX instruction, and map it to a virtual register. Also it | ||
| // builds and supports consistency of constants and global variables. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIB_TARGET_SPIRV_SPIRVTYPEMANAGER_H | ||
| #define LLVM_LIB_TARGET_SPIRV_SPIRVTYPEMANAGER_H | ||
|
|
||
| #include "MCTargetDesc/SPIRVBaseInfo.h" | ||
| #include "SPIRVInstrInfo.h" | ||
| #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" | ||
|
|
||
| namespace llvm { | ||
| using SPIRVType = const MachineInstr; | ||
|
|
||
| class SPIRVGlobalRegistry { | ||
| // Registers holding values which have types associated with them. | ||
| // Initialized upon VReg definition in IRTranslator. | ||
| // Do not confuse this with DuplicatesTracker as DT maps Type* to <MF, Reg> | ||
| // where Reg = OpType... | ||
| // while VRegToTypeMap tracks SPIR-V type assigned to other regs (i.e. not | ||
| // type-declaring ones) | ||
| DenseMap<MachineFunction *, DenseMap<Register, SPIRVType *>> VRegToTypeMap; | ||
|
|
||
| DenseMap<SPIRVType *, const Type *> SPIRVToLLVMType; | ||
|
|
||
| // Number of bits pointers and size_t integers require. | ||
| const unsigned PointerSize; | ||
|
|
||
| // Add a new OpTypeXXX instruction without checking for duplicates. | ||
| SPIRVType * | ||
| createSPIRVType(const Type *Type, MachineIRBuilder &MIRBuilder, | ||
| SPIRV::AccessQualifier AQ = SPIRV::AccessQualifier::ReadWrite, | ||
| bool EmitIR = true); | ||
|
|
||
| public: | ||
| SPIRVGlobalRegistry(unsigned PointerSize); | ||
|
|
||
| MachineFunction *CurMF; | ||
|
|
||
| // Get or create a SPIR-V type corresponding the given LLVM IR type, | ||
| // and map it to the given VReg by creating an ASSIGN_TYPE instruction. | ||
| SPIRVType *assignTypeToVReg( | ||
| const Type *Type, Register VReg, MachineIRBuilder &MIRBuilder, | ||
| SPIRV::AccessQualifier AQ = SPIRV::AccessQualifier::ReadWrite, | ||
| bool EmitIR = true); | ||
|
|
||
| // In cases where the SPIR-V type is already known, this function can be | ||
| // used to map it to the given VReg via an ASSIGN_TYPE instruction. | ||
| void assignSPIRVTypeToVReg(SPIRVType *Type, Register VReg, | ||
| MachineIRBuilder &MIRBuilder); | ||
|
|
||
| // Either generate a new OpTypeXXX instruction or return an existing one | ||
| // corresponding to the given LLVM IR type. | ||
| // EmitIR controls if we emit GMIR or SPV constants (e.g. for array sizes) | ||
| // because this method may be called from InstructionSelector and we don't | ||
| // want to emit extra IR instructions there. | ||
| SPIRVType *getOrCreateSPIRVType( | ||
| const Type *Type, MachineIRBuilder &MIRBuilder, | ||
| SPIRV::AccessQualifier AQ = SPIRV::AccessQualifier::ReadWrite, | ||
| bool EmitIR = true); | ||
|
|
||
| const Type *getTypeForSPIRVType(const SPIRVType *Ty) const { | ||
| auto Res = SPIRVToLLVMType.find(Ty); | ||
| assert(Res != SPIRVToLLVMType.end()); | ||
| return Res->second; | ||
| } | ||
|
|
||
| // Return the SPIR-V type instruction corresponding to the given VReg, or | ||
| // nullptr if no such type instruction exists. | ||
| SPIRVType *getSPIRVTypeForVReg(Register VReg) const; | ||
|
|
||
| // Whether the given VReg has a SPIR-V type mapped to it yet. | ||
| bool hasSPIRVTypeForVReg(Register VReg) const { | ||
| return getSPIRVTypeForVReg(VReg) != nullptr; | ||
| } | ||
|
|
||
| // Return the VReg holding the result of the given OpTypeXXX instruction. | ||
| Register getSPIRVTypeID(const SPIRVType *SpirvType) const { | ||
| assert(SpirvType && "Attempting to get type id for nullptr type."); | ||
| return SpirvType->defs().begin()->getReg(); | ||
| } | ||
|
|
||
| void setCurrentFunc(MachineFunction &MF) { CurMF = &MF; } | ||
|
|
||
| // Whether the given VReg has an OpTypeXXX instruction mapped to it with the | ||
| // given opcode (e.g. OpTypeFloat). | ||
| bool isScalarOfType(Register VReg, unsigned TypeOpcode) const; | ||
|
|
||
| // Return true if the given VReg's assigned SPIR-V type is either a scalar | ||
| // matching the given opcode, or a vector with an element type matching that | ||
| // opcode (e.g. OpTypeBool, or OpTypeVector %x 4, where %x is OpTypeBool). | ||
| bool isScalarOrVectorOfType(Register VReg, unsigned TypeOpcode) const; | ||
|
|
||
| // For vectors or scalars of ints/floats, return the scalar type's bitwidth. | ||
| unsigned getScalarOrVectorBitWidth(const SPIRVType *Type) const; | ||
|
|
||
| // For integer vectors or scalars, return whether the integers are signed. | ||
| bool isScalarOrVectorSigned(const SPIRVType *Type) const; | ||
|
|
||
| // Gets the storage class of the pointer type assigned to this vreg. | ||
| SPIRV::StorageClass getPointerStorageClass(Register VReg) const; | ||
|
|
||
| // Return the number of bits SPIR-V pointers and size_t variables require. | ||
| unsigned getPointerSize() const { return PointerSize; } | ||
|
|
||
| private: | ||
| SPIRVType *getOpTypeBool(MachineIRBuilder &MIRBuilder); | ||
|
|
||
| SPIRVType *getOpTypeInt(uint32_t Width, MachineIRBuilder &MIRBuilder, | ||
| bool IsSigned = false); | ||
|
|
||
| SPIRVType *getOpTypeFloat(uint32_t Width, MachineIRBuilder &MIRBuilder); | ||
|
|
||
| SPIRVType *getOpTypeVoid(MachineIRBuilder &MIRBuilder); | ||
|
|
||
| SPIRVType *getOpTypeVector(uint32_t NumElems, SPIRVType *ElemType, | ||
| MachineIRBuilder &MIRBuilder); | ||
|
|
||
| SPIRVType *getOpTypeArray(uint32_t NumElems, SPIRVType *ElemType, | ||
| MachineIRBuilder &MIRBuilder, bool EmitIR = true); | ||
|
|
||
| SPIRVType *getOpTypePointer(SPIRV::StorageClass SC, SPIRVType *ElemType, | ||
| MachineIRBuilder &MIRBuilder); | ||
|
|
||
| SPIRVType *getOpTypeFunction(SPIRVType *RetType, | ||
| const SmallVectorImpl<SPIRVType *> &ArgTypes, | ||
| MachineIRBuilder &MIRBuilder); | ||
| SPIRVType *restOfCreateSPIRVType(Type *LLVMTy, MachineInstrBuilder MIB); | ||
|
|
||
| public: | ||
| Register buildConstantInt(uint64_t Val, MachineIRBuilder &MIRBuilder, | ||
| SPIRVType *SpvType = nullptr, bool EmitIR = true); | ||
| Register buildConstantFP(APFloat Val, MachineIRBuilder &MIRBuilder, | ||
| SPIRVType *SpvType = nullptr); | ||
| Register | ||
| buildGlobalVariable(Register Reg, SPIRVType *BaseType, StringRef Name, | ||
| const GlobalValue *GV, SPIRV::StorageClass Storage, | ||
| const MachineInstr *Init, bool IsConst, bool HasLinkageTy, | ||
| SPIRV::LinkageType LinkageType, | ||
| MachineIRBuilder &MIRBuilder, bool IsInstSelector); | ||
|
|
||
| // Convenient helpers for getting types with check for duplicates. | ||
| SPIRVType *getOrCreateSPIRVIntegerType(unsigned BitWidth, | ||
| MachineIRBuilder &MIRBuilder); | ||
| SPIRVType *getOrCreateSPIRVIntegerType(unsigned BitWidth, MachineInstr &I, | ||
| const SPIRVInstrInfo &TII); | ||
| SPIRVType *getOrCreateSPIRVBoolType(MachineIRBuilder &MIRBuilder); | ||
| SPIRVType *getOrCreateSPIRVVectorType(SPIRVType *BaseType, | ||
| unsigned NumElements, | ||
| MachineIRBuilder &MIRBuilder); | ||
| SPIRVType *getOrCreateSPIRVVectorType(SPIRVType *BaseType, | ||
| unsigned NumElements, MachineInstr &I, | ||
| const SPIRVInstrInfo &TII); | ||
|
|
||
| SPIRVType *getOrCreateSPIRVPointerType( | ||
| SPIRVType *BaseType, MachineIRBuilder &MIRBuilder, | ||
| SPIRV::StorageClass SClass = SPIRV::StorageClass::Function); | ||
| SPIRVType *getOrCreateSPIRVPointerType( | ||
| SPIRVType *BaseType, MachineInstr &I, const SPIRVInstrInfo &TII, | ||
| SPIRV::StorageClass SClass = SPIRV::StorageClass::Function); | ||
| }; | ||
| } // end namespace llvm | ||
| #endif // LLLVM_LIB_TARGET_SPIRV_SPIRVTYPEMANAGER_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| //===- SPIRVISelLowering.cpp - SPIR-V DAG Lowering Impl ---------*- 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 SPIRVTargetLowering class. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "SPIRVISelLowering.h" | ||
| #include "SPIRV.h" | ||
|
|
||
| #define DEBUG_TYPE "spirv-lower" | ||
|
|
||
| using namespace llvm; | ||
|
|
||
| unsigned SPIRVTargetLowering::getNumRegistersForCallingConv( | ||
| LLVMContext &Context, CallingConv::ID CC, EVT VT) const { | ||
| // This code avoids CallLowering fail inside getVectorTypeBreakdown | ||
| // on v3i1 arguments. Maybe we need to return 1 for all types. | ||
| // TODO: remove it once this case is supported by the default implementation. | ||
| if (VT.isVector() && VT.getVectorNumElements() == 3 && | ||
| (VT.getVectorElementType() == MVT::i1 || | ||
| VT.getVectorElementType() == MVT::i8)) | ||
| return 1; | ||
| return getNumRegisters(Context, VT); | ||
| } | ||
|
|
||
| MVT SPIRVTargetLowering::getRegisterTypeForCallingConv(LLVMContext &Context, | ||
| CallingConv::ID CC, | ||
| EVT VT) const { | ||
| // This code avoids CallLowering fail inside getVectorTypeBreakdown | ||
| // on v3i1 arguments. Maybe we need to return i32 for all types. | ||
| // TODO: remove it once this case is supported by the default implementation. | ||
| if (VT.isVector() && VT.getVectorNumElements() == 3) { | ||
| if (VT.getVectorElementType() == MVT::i1) | ||
| return MVT::v4i1; | ||
| else if (VT.getVectorElementType() == MVT::i8) | ||
| return MVT::v4i8; | ||
| } | ||
| return getRegisterType(Context, VT); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| //===-- SPIRVISelLowering.h - SPIR-V DAG Lowering 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This file defines the interfaces that SPIR-V uses to lower LLVM code into a | ||
| // selection DAG. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIB_TARGET_SPIRV_SPIRVISELLOWERING_H | ||
| #define LLVM_LIB_TARGET_SPIRV_SPIRVISELLOWERING_H | ||
|
|
||
| #include "llvm/CodeGen/TargetLowering.h" | ||
|
|
||
| namespace llvm { | ||
| class SPIRVSubtarget; | ||
|
|
||
| class SPIRVTargetLowering : public TargetLowering { | ||
| public: | ||
| explicit SPIRVTargetLowering(const TargetMachine &TM, | ||
| const SPIRVSubtarget &STI) | ||
| : TargetLowering(TM) {} | ||
|
|
||
| // Stop IRTranslator breaking up FMA instrs to preserve types information. | ||
| bool isFMAFasterThanFMulAndFAdd(const MachineFunction &MF, | ||
| EVT) const override { | ||
| return true; | ||
| } | ||
|
|
||
| // This is to prevent sexts of non-i64 vector indices which are generated | ||
| // within general IRTranslator hence type generation for it is omitted. | ||
| MVT getVectorIdxTy(const DataLayout &DL) const override { | ||
| return MVT::getIntegerVT(32); | ||
| } | ||
| unsigned getNumRegistersForCallingConv(LLVMContext &Context, | ||
| CallingConv::ID CC, | ||
| EVT VT) const override; | ||
| MVT getRegisterTypeForCallingConv(LLVMContext &Context, CallingConv::ID CC, | ||
| EVT VT) const override; | ||
| }; | ||
| } // namespace llvm | ||
|
|
||
| #endif // LLVM_LIB_TARGET_SPIRV_SPIRVISELLOWERING_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| //===-- SPIRVInstrFormats.td - SPIR-V Instruction Formats --*- tablegen -*-===// | ||
| // | ||
| // 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 | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| def StringImm: Operand<i32>{ | ||
| let PrintMethod="printStringImm"; | ||
| } | ||
|
|
||
| class Op<bits<16> Opcode, dag outs, dag ins, string asmstr, list<dag> pattern = []> | ||
| : Instruction { | ||
| field bits<16> Inst; | ||
|
|
||
| let Inst = Opcode; | ||
|
|
||
| let Namespace = "SPIRV"; | ||
| let DecoderNamespace = "SPIRV"; | ||
|
|
||
| dag OutOperandList = outs; | ||
| dag InOperandList = ins; | ||
| let AsmString = asmstr; | ||
| let Pattern = pattern; | ||
| } | ||
|
|
||
| // Pseudo instructions | ||
| class Pseudo<dag outs, dag ins> : Op<0, outs, ins, ""> { | ||
| let isPseudo = 1; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,195 @@ | ||
| //===-- SPIRVInstrInfo.cpp - SPIR-V Instruction Information ------*- 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 SPIR-V implementation of the TargetInstrInfo class. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "SPIRVInstrInfo.h" | ||
| #include "SPIRV.h" | ||
| #include "llvm/ADT/SmallVector.h" | ||
| #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" | ||
| #include "llvm/CodeGen/MachineBasicBlock.h" | ||
| #include "llvm/IR/DebugLoc.h" | ||
| #include "llvm/Support/ErrorHandling.h" | ||
|
|
||
| #define GET_INSTRINFO_CTOR_DTOR | ||
| #include "SPIRVGenInstrInfo.inc" | ||
|
|
||
| using namespace llvm; | ||
|
|
||
| SPIRVInstrInfo::SPIRVInstrInfo() : SPIRVGenInstrInfo() {} | ||
|
|
||
| bool SPIRVInstrInfo::isConstantInstr(const MachineInstr &MI) const { | ||
| switch (MI.getOpcode()) { | ||
| case SPIRV::OpConstantTrue: | ||
| case SPIRV::OpConstantFalse: | ||
| case SPIRV::OpConstantI: | ||
| case SPIRV::OpConstantF: | ||
| case SPIRV::OpConstantComposite: | ||
| case SPIRV::OpConstantSampler: | ||
| case SPIRV::OpConstantNull: | ||
| case SPIRV::OpSpecConstantTrue: | ||
| case SPIRV::OpSpecConstantFalse: | ||
| case SPIRV::OpSpecConstant: | ||
| case SPIRV::OpSpecConstantComposite: | ||
| case SPIRV::OpSpecConstantOp: | ||
| case SPIRV::OpUndef: | ||
| return true; | ||
| default: | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| bool SPIRVInstrInfo::isTypeDeclInstr(const MachineInstr &MI) const { | ||
| auto &MRI = MI.getMF()->getRegInfo(); | ||
| if (MI.getNumDefs() >= 1 && MI.getOperand(0).isReg()) { | ||
| auto DefRegClass = MRI.getRegClassOrNull(MI.getOperand(0).getReg()); | ||
| return DefRegClass && DefRegClass->getID() == SPIRV::TYPERegClass.getID(); | ||
| } else { | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| bool SPIRVInstrInfo::isDecorationInstr(const MachineInstr &MI) const { | ||
| switch (MI.getOpcode()) { | ||
| case SPIRV::OpDecorate: | ||
| case SPIRV::OpDecorateId: | ||
| case SPIRV::OpDecorateString: | ||
| case SPIRV::OpMemberDecorate: | ||
| case SPIRV::OpMemberDecorateString: | ||
| return true; | ||
| default: | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| bool SPIRVInstrInfo::isHeaderInstr(const MachineInstr &MI) const { | ||
| switch (MI.getOpcode()) { | ||
| case SPIRV::OpCapability: | ||
| case SPIRV::OpExtension: | ||
| case SPIRV::OpExtInstImport: | ||
| case SPIRV::OpMemoryModel: | ||
| case SPIRV::OpEntryPoint: | ||
| case SPIRV::OpExecutionMode: | ||
| case SPIRV::OpExecutionModeId: | ||
| case SPIRV::OpString: | ||
| case SPIRV::OpSourceExtension: | ||
| case SPIRV::OpSource: | ||
| case SPIRV::OpSourceContinued: | ||
| case SPIRV::OpName: | ||
| case SPIRV::OpMemberName: | ||
| case SPIRV::OpModuleProcessed: | ||
| return true; | ||
| default: | ||
| return isTypeDeclInstr(MI) || isConstantInstr(MI) || isDecorationInstr(MI); | ||
| } | ||
| } | ||
|
|
||
| // Analyze the branching code at the end of MBB, returning | ||
| // true if it cannot be understood (e.g. it's a switch dispatch or isn't | ||
| // implemented for a target). Upon success, this returns false and returns | ||
| // with the following information in various cases: | ||
| // | ||
| // 1. If this block ends with no branches (it just falls through to its succ) | ||
| // just return false, leaving TBB/FBB null. | ||
| // 2. If this block ends with only an unconditional branch, it sets TBB to be | ||
| // the destination block. | ||
| // 3. If this block ends with a conditional branch and it falls through to a | ||
| // successor block, it sets TBB to be the branch destination block and a | ||
| // list of operands that evaluate the condition. These operands can be | ||
| // passed to other TargetInstrInfo methods to create new branches. | ||
| // 4. If this block ends with a conditional branch followed by an | ||
| // unconditional branch, it returns the 'true' destination in TBB, the | ||
| // 'false' destination in FBB, and a list of operands that evaluate the | ||
| // condition. These operands can be passed to other TargetInstrInfo | ||
| // methods to create new branches. | ||
| // | ||
| // Note that removeBranch and insertBranch must be implemented to support | ||
| // cases where this method returns success. | ||
| // | ||
| // If AllowModify is true, then this routine is allowed to modify the basic | ||
| // block (e.g. delete instructions after the unconditional branch). | ||
| // | ||
| // The CFG information in MBB.Predecessors and MBB.Successors must be valid | ||
| // before calling this function. | ||
| bool SPIRVInstrInfo::analyzeBranch(MachineBasicBlock &MBB, | ||
| MachineBasicBlock *&TBB, | ||
| MachineBasicBlock *&FBB, | ||
| SmallVectorImpl<MachineOperand> &Cond, | ||
| bool AllowModify) const { | ||
| TBB = nullptr; | ||
| FBB = nullptr; | ||
| if (MBB.empty()) | ||
| return false; | ||
| auto MI = MBB.getLastNonDebugInstr(); | ||
| if (!MI.isValid()) | ||
| return false; | ||
| if (MI->getOpcode() == SPIRV::OpBranch) { | ||
| TBB = MI->getOperand(0).getMBB(); | ||
| return false; | ||
| } else if (MI->getOpcode() == SPIRV::OpBranchConditional) { | ||
| Cond.push_back(MI->getOperand(0)); | ||
| TBB = MI->getOperand(1).getMBB(); | ||
| if (MI->getNumOperands() == 3) { | ||
| FBB = MI->getOperand(2).getMBB(); | ||
| } | ||
| return false; | ||
| } else { | ||
| return true; | ||
| } | ||
| } | ||
|
|
||
| // Remove the branching code at the end of the specific MBB. | ||
| // This is only invoked in cases where analyzeBranch returns success. It | ||
| // returns the number of instructions that were removed. | ||
| // If \p BytesRemoved is non-null, report the change in code size from the | ||
| // removed instructions. | ||
| unsigned SPIRVInstrInfo::removeBranch(MachineBasicBlock &MBB, | ||
| int *BytesRemoved) const { | ||
| report_fatal_error("Branch removal not supported, as MBB info not propagated" | ||
| " to OpPhi instructions. Try using -O0 instead."); | ||
| } | ||
|
|
||
| // Insert branch code into the end of the specified MachineBasicBlock. The | ||
| // operands to this method are the same as those returned by analyzeBranch. | ||
| // This is only invoked in cases where analyzeBranch returns success. It | ||
| // returns the number of instructions inserted. If \p BytesAdded is non-null, | ||
| // report the change in code size from the added instructions. | ||
| // | ||
| // It is also invoked by tail merging to add unconditional branches in | ||
| // cases where analyzeBranch doesn't apply because there was no original | ||
| // branch to analyze. At least this much must be implemented, else tail | ||
| // merging needs to be disabled. | ||
| // | ||
| // The CFG information in MBB.Predecessors and MBB.Successors must be valid | ||
| // before calling this function. | ||
| unsigned SPIRVInstrInfo::insertBranch( | ||
| MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, | ||
| ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const { | ||
| report_fatal_error("Branch insertion not supported, as MBB info not " | ||
| "propagated to OpPhi instructions. Try using " | ||
| "-O0 instead."); | ||
| } | ||
|
|
||
| void SPIRVInstrInfo::copyPhysReg(MachineBasicBlock &MBB, | ||
| MachineBasicBlock::iterator I, | ||
| const DebugLoc &DL, MCRegister DestReg, | ||
| MCRegister SrcReg, bool KillSrc) const { | ||
| // Actually we don't need this COPY instruction. However if we do nothing with | ||
| // it, post RA pseudo instrs expansion just removes it and we get the code | ||
| // with undef registers. Therefore, we need to replace all uses of dst with | ||
| // the src register. COPY instr itself will be safely removed later. | ||
| assert(I->isCopy() && "Copy instruction is expected"); | ||
| auto DstOp = I->getOperand(0); | ||
| auto SrcOp = I->getOperand(1); | ||
| assert(DstOp.isReg() && SrcOp.isReg() && | ||
| "Register operands are expected in COPY"); | ||
| auto &MRI = I->getMF()->getRegInfo(); | ||
| MRI.replaceRegWith(DstOp.getReg(), SrcOp.getReg()); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| //===-- SPIRVInstrInfo.h - SPIR-V Instruction Information -------*- 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 SPIR-V implementation of the TargetInstrInfo class. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_LIB_TARGET_SPIRV_SPIRVINSTRINFO_H | ||
| #define LLVM_LIB_TARGET_SPIRV_SPIRVINSTRINFO_H | ||
|
|
||
| #include "SPIRVRegisterInfo.h" | ||
| #include "llvm/CodeGen/TargetInstrInfo.h" | ||
|
|
||
| #define GET_INSTRINFO_HEADER | ||
| #include "SPIRVGenInstrInfo.inc" | ||
|
|
||
| namespace llvm { | ||
|
|
||
| class SPIRVInstrInfo : public SPIRVGenInstrInfo { | ||
| const SPIRVRegisterInfo RI; | ||
|
|
||
| public: | ||
| SPIRVInstrInfo(); | ||
|
|
||
| const SPIRVRegisterInfo &getRegisterInfo() const { return RI; } | ||
| bool isHeaderInstr(const MachineInstr &MI) const; | ||
| bool isConstantInstr(const MachineInstr &MI) const; | ||
| bool isTypeDeclInstr(const MachineInstr &MI) const; | ||
| bool isDecorationInstr(const MachineInstr &MI) const; | ||
|
|
||
| bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, | ||
| MachineBasicBlock *&FBB, | ||
| SmallVectorImpl<MachineOperand> &Cond, | ||
| bool AllowModify = false) const override; | ||
|
|
||
| unsigned removeBranch(MachineBasicBlock &MBB, | ||
| int *BytesRemoved = nullptr) const override; | ||
|
|
||
| unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, | ||
| MachineBasicBlock *FBB, ArrayRef<MachineOperand> Cond, | ||
| const DebugLoc &DL, | ||
| int *BytesAdded = nullptr) const override; | ||
| void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, | ||
| const DebugLoc &DL, MCRegister DestReg, MCRegister SrcReg, | ||
| bool KillSrc) const override; | ||
| }; | ||
| } // namespace llvm | ||
|
|
||
| #endif // LLVM_LIB_TARGET_SPIRV_SPIRVINSTRINFO_H |