10 changes: 10 additions & 0 deletions llvm/lib/MC/MCObjectFileInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -804,6 +805,11 @@ void MCObjectFileInfo::initCOFFMCObjectFileInfo(const Triple &T) {
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());
Expand Down Expand Up @@ -1032,6 +1038,9 @@ void MCObjectFileInfo::initMCObjectFileInfo(MCContext &MCCtx, bool PIC,
case MCContext::IsGOFF:
initGOFFMCObjectFileInfo(TheTriple);
break;
case MCContext::IsSPIRV:
initSPIRVMCObjectFileInfo(TheTriple);
break;
case MCContext::IsWasm:
initWasmMCObjectFileInfo(TheTriple);
break;
Expand All @@ -1055,6 +1064,7 @@ MCSection *MCObjectFileInfo::getDwarfComdatSection(const char *Name,
case Triple::MachO:
case Triple::COFF:
case Triple::GOFF:
case Triple::SPIRV:
case Triple::XCOFF:
case Triple::DXContainer:
case Triple::UnknownObjectFormat:
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/MC/MCParser/AsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -792,6 +792,10 @@ AsmParser::AsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out,
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;
Expand Down
45 changes: 45 additions & 0 deletions llvm/lib/MC/MCSPIRVStreamer.cpp
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;
}
76 changes: 76 additions & 0 deletions llvm/lib/MC/SPIRVObjectWriter.cpp
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);
}
48 changes: 29 additions & 19 deletions llvm/lib/Support/Triple.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -631,15 +631,16 @@ static Triple::EnvironmentType parseEnvironment(StringRef EnvironmentName) {

static Triple::ObjectFormatType parseFormat(StringRef EnvironmentName) {
return StringSwitch<Triple::ObjectFormatType>(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) {
Expand Down Expand Up @@ -740,14 +741,24 @@ static Triple::SubArchType parseSubArch(StringRef SubArchName) {

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");
}
Expand Down Expand Up @@ -831,8 +842,7 @@ static Triple::ObjectFormatType getDefaultFormat(const Triple &T) {

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;
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6377,6 +6377,7 @@ bool ARMAsmParser::parsePrefix(ARMMCExpr::VariantKind &RefKind) {
CurrentFormat = WASM;
break;
case MCContext::IsGOFF:
case MCContext::IsSPIRV:
case MCContext::IsXCOFF:
case MCContext::IsDXContainer:
llvm_unreachable("unexpected object format");
Expand Down
49 changes: 49 additions & 0 deletions llvm/lib/Target/SPIRV/CMakeLists.txt
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)
18 changes: 18 additions & 0 deletions llvm/lib/Target/SPIRV/MCTargetDesc/CMakeLists.txt
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
)
63 changes: 63 additions & 0 deletions llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVAsmBackend.cpp
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);
}
1,094 changes: 1,094 additions & 0 deletions llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVBaseInfo.cpp

Large diffs are not rendered by default.

739 changes: 739 additions & 0 deletions llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVBaseInfo.h

Large diffs are not rendered by default.

556 changes: 556 additions & 0 deletions llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.cpp

Large diffs are not rendered by default.

94 changes: 94 additions & 0 deletions llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVInstPrinter.h
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
34 changes: 34 additions & 0 deletions llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCAsmInfo.cpp
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;
}
29 changes: 29 additions & 0 deletions llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCAsmInfo.h
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
132 changes: 132 additions & 0 deletions llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCCodeEmitter.cpp
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"
102 changes: 102 additions & 0 deletions llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCTargetDesc.cpp
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);
}
}
52 changes: 52 additions & 0 deletions llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVMCTargetDesc.h
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
25 changes: 25 additions & 0 deletions llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVObjectTargetWriter.cpp
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>();
}
18 changes: 18 additions & 0 deletions llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVTargetStreamer.cpp
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() {}
28 changes: 28 additions & 0 deletions llvm/lib/Target/SPIRV/MCTargetDesc/SPIRVTargetStreamer.h
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_
30 changes: 30 additions & 0 deletions llvm/lib/Target/SPIRV/SPIRV.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
43 changes: 43 additions & 0 deletions llvm/lib/Target/SPIRV/SPIRV.td
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];
}
348 changes: 348 additions & 0 deletions llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp
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());
}
223 changes: 223 additions & 0 deletions llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp
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());
}
50 changes: 50 additions & 0 deletions llvm/lib/Target/SPIRV/SPIRVCallLowering.h
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
51 changes: 51 additions & 0 deletions llvm/lib/Target/SPIRV/SPIRVEnums.td
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">;
39 changes: 39 additions & 0 deletions llvm/lib/Target/SPIRV/SPIRVFrameLowering.h
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
453 changes: 453 additions & 0 deletions llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp

Large diffs are not rendered by default.

174 changes: 174 additions & 0 deletions llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.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
45 changes: 45 additions & 0 deletions llvm/lib/Target/SPIRV/SPIRVISelLowering.cpp
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);
}
47 changes: 47 additions & 0 deletions llvm/lib/Target/SPIRV/SPIRVISelLowering.h
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
31 changes: 31 additions & 0 deletions llvm/lib/Target/SPIRV/SPIRVInstrFormats.td
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;
}
195 changes: 195 additions & 0 deletions llvm/lib/Target/SPIRV/SPIRVInstrInfo.cpp
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());
}
54 changes: 54 additions & 0 deletions llvm/lib/Target/SPIRV/SPIRVInstrInfo.h
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
Loading