diff --git a/llvm/lib/Target/SPIRV/CMakeLists.txt b/llvm/lib/Target/SPIRV/CMakeLists.txt --- a/llvm/lib/Target/SPIRV/CMakeLists.txt +++ b/llvm/lib/Target/SPIRV/CMakeLists.txt @@ -13,14 +13,26 @@ add_public_tablegen_target(SPIRVCommonTableGen) add_llvm_target(SPIRVCodeGen + SPIRVAsmPrinter.cpp + SPIRVCallLowering.cpp + SPIRVInstrInfo.cpp + SPIRVISelLowering.cpp + SPIRVMCInstLower.cpp + SPIRVRegisterBankInfo.cpp + SPIRVRegisterInfo.cpp + SPIRVSubtarget.cpp SPIRVTargetMachine.cpp LINK_COMPONENTS + Analysis + AsmPrinter CodeGen Core + GlobalISel MC SPIRVDesc SPIRVInfo + SelectionDAG Support Target diff --git a/llvm/lib/Target/SPIRV/SPIRV.h b/llvm/lib/Target/SPIRV/SPIRV.h new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/SPIRV/SPIRV.h @@ -0,0 +1,21 @@ +//===-- 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; +} // namespace llvm + +#endif // LLVM_LIB_TARGET_SPIRV_SPIRV_H diff --git a/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp @@ -0,0 +1,137 @@ +//===-- 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 "SPIRVTargetMachine.h" +#include "TargetInfo/SPIRVTargetInfo.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 Streamer) + : AsmPrinter(TM, std::move(Streamer)) {} + + 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 emitInstruction(const MachineInstr *MI) override; + + void emitFunctionEntryLabel() override {} + void emitFunctionHeader() override; + void emitFunctionBodyStart() override {} + void emitBasicBlockStart(const MachineBasicBlock &MBB) override {} + void emitBasicBlockEnd(const MachineBasicBlock &MBB) override {} + void emitGlobalVariable(const GlobalVariable *GV) override {} +}; +} // namespace + +void SPIRVAsmPrinter::emitFunctionHeader() { + 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::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(""); + } +} + +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; +} + +void SPIRVAsmPrinter::emitInstruction(const MachineInstr *MI) { + + SPIRVMCInstLower MCInstLowering; + MCInst TmpInst; + MCInstLowering.lower(MI, TmpInst); + EmitToStreamer(*OutStreamer, TmpInst); +} + +// Force static initialization. +extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSPIRVAsmPrinter() { + RegisterAsmPrinter X(getTheSPIRV32Target()); + RegisterAsmPrinter Y(getTheSPIRV64Target()); +} diff --git a/llvm/lib/Target/SPIRV/SPIRVCallLowering.h b/llvm/lib/Target/SPIRV/SPIRVCallLowering.h new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/SPIRV/SPIRVCallLowering.h @@ -0,0 +1,43 @@ +//===--- 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 SPIRVTargetLowering; + +class SPIRVCallLowering : public CallLowering { +private: +public: + SPIRVCallLowering(const SPIRVTargetLowering &TLI); + + // Built OpReturn or OpReturnValue. + bool lowerReturn(MachineIRBuilder &MIRBuiler, const Value *Val, + ArrayRef VRegs, FunctionLoweringInfo &FLI, + Register SwiftErrorVReg) const override; + + // Build OpFunction, OpFunctionParameter, and any EntryPoint or Linkage data. + bool lowerFormalArguments(MachineIRBuilder &MIRBuilder, const Function &F, + ArrayRef> 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 diff --git a/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp b/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp @@ -0,0 +1,112 @@ +//===--- 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 "SPIRV.h" +#include "SPIRVISelLowering.h" +#include "SPIRVRegisterInfo.h" +#include "SPIRVSubtarget.h" +#include "llvm/CodeGen/FunctionLoweringInfo.h" +#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" + +using namespace llvm; + +SPIRVCallLowering::SPIRVCallLowering(const SPIRVTargetLowering &TLI) + : CallLowering(&TLI) {} + +bool SPIRVCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder, + const Value *Val, ArrayRef 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) { + MIRBuilder.buildInstr(SPIRV::OpReturnValue).addUse(VRegs[0]); + return true; + } + MIRBuilder.buildInstr(SPIRV::OpReturn); + return true; +} + +bool SPIRVCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder, + const Function &F, + ArrayRef> VRegs, + FunctionLoweringInfo &FLI) const { + auto MRI = MIRBuilder.getMRI(); + // Assign types and names to all args, and store their types for later. + SmallVector 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; + ArgTypeVRegs.push_back( + MRI->createGenericVirtualRegister(LLT::scalar(32))); + ++i; + } + } + + // Generate a SPIR-V type for the function. + Register FuncVReg = MRI->createGenericVirtualRegister(LLT::scalar(32)); + MRI->setRegClass(FuncVReg, &SPIRV::IDRegClass); + + MIRBuilder.buildInstr(SPIRV::OpFunction) + .addDef(FuncVReg) + .addUse(MRI->createGenericVirtualRegister(LLT::scalar(32))) + .addImm(0) + .addUse(MRI->createGenericVirtualRegister(LLT::scalar(32))); + + // 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]); + } + 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]; + // Make sure there's a valid return reg, even for functions returning void. + if (!ResVReg.isValid()) { + ResVReg = MIRBuilder.getMRI()->createVirtualRegister(&SPIRV::IDRegClass); + } + // Emit the OpFunctionCall and its args. + auto MIB = MIRBuilder.buildInstr(SPIRV::OpFunctionCall) + .addDef(ResVReg) + .addUse(MIRBuilder.getMRI()->createVirtualRegister( + &SPIRV::IDRegClass)) + .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 true; +} diff --git a/llvm/lib/Target/SPIRV/SPIRVFrameLowering.h b/llvm/lib/Target/SPIRV/SPIRVFrameLowering.h new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/SPIRV/SPIRVFrameLowering.h @@ -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 diff --git a/llvm/lib/Target/SPIRV/SPIRVISelLowering.h b/llvm/lib/Target/SPIRV/SPIRVISelLowering.h new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/SPIRV/SPIRVISelLowering.h @@ -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 diff --git a/llvm/lib/Target/SPIRV/SPIRVISelLowering.cpp b/llvm/lib/Target/SPIRV/SPIRVISelLowering.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/SPIRV/SPIRVISelLowering.cpp @@ -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); +} diff --git a/llvm/lib/Target/SPIRV/SPIRVInstrInfo.h b/llvm/lib/Target/SPIRV/SPIRVInstrInfo.h new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/SPIRV/SPIRVInstrInfo.h @@ -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 &Cond, + bool AllowModify = false) const override; + + unsigned removeBranch(MachineBasicBlock &MBB, + int *BytesRemoved = nullptr) const override; + + unsigned insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + MachineBasicBlock *FBB, ArrayRef 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 diff --git a/llvm/lib/Target/SPIRV/SPIRVInstrInfo.cpp b/llvm/lib/Target/SPIRV/SPIRVInstrInfo.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/SPIRV/SPIRVInstrInfo.cpp @@ -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 &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 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()); +} diff --git a/llvm/lib/Target/SPIRV/SPIRVMCInstLower.h b/llvm/lib/Target/SPIRV/SPIRVMCInstLower.h new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/SPIRV/SPIRVMCInstLower.h @@ -0,0 +1,25 @@ +//=- SPIRVMCInstLower.h -- Convert SPIR-V MachineInstr to MCInst --*- 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_SPIRVMCINSTLOWER_H +#define LLVM_LIB_TARGET_SPIRV_SPIRVMCINSTLOWER_H + +#include "llvm/Support/Compiler.h" + +namespace llvm { +class MCInst; +class MachineInstr; + +// This class is used to lower a MachineInstr into an MCInst. +class LLVM_LIBRARY_VISIBILITY SPIRVMCInstLower { +public: + void lower(const MachineInstr *MI, MCInst &OutMI) const; +}; +} // namespace llvm + +#endif // LLVM_LIB_TARGET_SPIRV_SPIRVMCINSTLOWER_H diff --git a/llvm/lib/Target/SPIRV/SPIRVMCInstLower.cpp b/llvm/lib/Target/SPIRV/SPIRVMCInstLower.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/SPIRV/SPIRVMCInstLower.cpp @@ -0,0 +1,44 @@ +//=- SPIRVMCInstLower.cpp - Convert SPIR-V MachineInstr to MCInst -*- 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 code to lower SPIR-V MachineInstrs to their corresponding +// MCInst records. +// +//===----------------------------------------------------------------------===// + +#include "SPIRVMCInstLower.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/IR/Constants.h" + +using namespace llvm; + +void SPIRVMCInstLower::lower(const MachineInstr *MI, MCInst &OutMI) const { + OutMI.setOpcode(MI->getOpcode()); + + for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { + const MachineOperand &MO = MI->getOperand(i); + + MCOperand MCOp; + switch (MO.getType()) { + default: + llvm_unreachable("unknown operand type"); + case MachineOperand::MO_Register: + MCOp = MCOperand::createReg(MO.getReg()); + break; + case MachineOperand::MO_Immediate: + MCOp = MCOperand::createImm(MO.getImm()); + break; + case MachineOperand::MO_FPImmediate: + MCOp = MCOperand::createDFPImm( + MO.getFPImm()->getValueAPF().convertToFloat()); + break; + } + + OutMI.addOperand(MCOp); + } +} diff --git a/llvm/lib/Target/SPIRV/SPIRVRegisterBankInfo.h b/llvm/lib/Target/SPIRV/SPIRVRegisterBankInfo.h new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/SPIRV/SPIRVRegisterBankInfo.h @@ -0,0 +1,38 @@ +//===- SPIRVRegisterBankInfo.h -----------------------------------*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares the targeting of the RegisterBankInfo class for SPIR-V. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_SPIRV_SPIRVREGISTERBANKINFO_H +#define LLVM_LIB_TARGET_SPIRV_SPIRVREGISTERBANKINFO_H + +#include "llvm/CodeGen/RegisterBankInfo.h" + +#define GET_REGBANK_DECLARATIONS +#include "SPIRVGenRegisterBank.inc" + +namespace llvm { + +class TargetRegisterInfo; + +class SPIRVGenRegisterBankInfo : public RegisterBankInfo { +protected: +#define GET_TARGET_REGBANK_CLASS +#include "SPIRVGenRegisterBank.inc" +}; + +// This class provides the information for the target register banks. +class SPIRVRegisterBankInfo final : public SPIRVGenRegisterBankInfo { +public: + const RegisterBank &getRegBankFromRegClass(const TargetRegisterClass &RC, + LLT Ty) const override; +}; +} // namespace llvm +#endif // LLVM_LIB_TARGET_SPIRV_SPIRVREGISTERBANKINFO_H diff --git a/llvm/lib/Target/SPIRV/SPIRVRegisterBankInfo.cpp b/llvm/lib/Target/SPIRV/SPIRVRegisterBankInfo.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/SPIRV/SPIRVRegisterBankInfo.cpp @@ -0,0 +1,47 @@ +//===- SPIRVRegisterBankInfo.cpp ------------------------------*- 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 targeting of the RegisterBankInfo class for SPIR-V. +// +//===----------------------------------------------------------------------===// + +#include "SPIRVRegisterBankInfo.h" +#include "SPIRVRegisterInfo.h" +#include "llvm/CodeGen/RegisterBank.h" + +#define GET_REGINFO_ENUM +#include "SPIRVGenRegisterInfo.inc" + +#define GET_TARGET_REGBANK_IMPL +#include "SPIRVGenRegisterBank.inc" + +using namespace llvm; + +// This required for .td selection patterns to work or we'd end up with RegClass +// checks being redundant as all the classes would be mapped to the same bank. +const RegisterBank & +SPIRVRegisterBankInfo::getRegBankFromRegClass(const TargetRegisterClass &RC, + LLT Ty) const { + switch (RC.getID()) { + case SPIRV::TYPERegClassID: + return SPIRV::TYPERegBank; + case SPIRV::pIDRegClassID: + case SPIRV::IDRegClassID: + return SPIRV::IDRegBank; + case SPIRV::fIDRegClassID: + return SPIRV::fIDRegBank; + case SPIRV::vIDRegClassID: + return SPIRV::vIDRegBank; + case SPIRV::vfIDRegClassID: + return SPIRV::vfIDRegBank; + case SPIRV::ANYIDRegClassID: + case SPIRV::ANYRegClassID: + return SPIRV::IDRegBank; + } + llvm_unreachable("Unknown register class"); +} diff --git a/llvm/lib/Target/SPIRV/SPIRVRegisterInfo.h b/llvm/lib/Target/SPIRV/SPIRVRegisterInfo.h new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/SPIRV/SPIRVRegisterInfo.h @@ -0,0 +1,36 @@ +//===-- SPIRVRegisterInfo.h - SPIR-V Register 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 TargetRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_SPIRV_SPIRVREGISTERINFO_H +#define LLVM_LIB_TARGET_SPIRV_SPIRVREGISTERINFO_H + +#include "llvm/CodeGen/TargetRegisterInfo.h" + +#define GET_REGINFO_HEADER +#include "SPIRVGenRegisterInfo.inc" + +namespace llvm { + +struct SPIRVRegisterInfo : public SPIRVGenRegisterInfo { + SPIRVRegisterInfo(); + const MCPhysReg *getCalleeSavedRegs(const MachineFunction *MF) const override; + BitVector getReservedRegs(const MachineFunction &MF) const override; + void eliminateFrameIndex(MachineBasicBlock::iterator MI, int SPAdj, + unsigned FIOperandNum, + RegScavenger *RS = nullptr) const override {} + Register getFrameRegister(const MachineFunction &MF) const override { + return 0; + } +}; +} // namespace llvm + +#endif // LLVM_LIB_TARGET_SPIRV_SPIRVREGISTERINFO_H diff --git a/llvm/lib/Target/SPIRV/SPIRVRegisterInfo.cpp b/llvm/lib/Target/SPIRV/SPIRVRegisterInfo.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/SPIRV/SPIRVRegisterInfo.cpp @@ -0,0 +1,32 @@ +//===-- SPIRVRegisterInfo.cpp - SPIR-V Register 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 TargetRegisterInfo class. +// +//===----------------------------------------------------------------------===// + +#include "SPIRVRegisterInfo.h" +#include "SPIRV.h" +#include "SPIRVSubtarget.h" +#include "llvm/CodeGen/MachineFunction.h" + +#define GET_REGINFO_TARGET_DESC +#include "SPIRVGenRegisterInfo.inc" +using namespace llvm; + +SPIRVRegisterInfo::SPIRVRegisterInfo() : SPIRVGenRegisterInfo(SPIRV::ID0) {} + +BitVector SPIRVRegisterInfo::getReservedRegs(const MachineFunction &MF) const { + return BitVector(getNumRegs()); +} + +const MCPhysReg * +SPIRVRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { + static const MCPhysReg CalleeSavedReg = {0}; + return &CalleeSavedReg; +} diff --git a/llvm/lib/Target/SPIRV/SPIRVSubtarget.h b/llvm/lib/Target/SPIRV/SPIRVSubtarget.h new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/SPIRV/SPIRVSubtarget.h @@ -0,0 +1,82 @@ +//===-- SPIRVSubtarget.h - SPIR-V Subtarget 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 declares the SPIR-V specific subclass of TargetSubtargetInfo. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_SPIRV_SPIRVSUBTARGET_H +#define LLVM_LIB_TARGET_SPIRV_SPIRVSUBTARGET_H + +#include "SPIRVCallLowering.h" +#include "SPIRVFrameLowering.h" +#include "SPIRVISelLowering.h" +#include "SPIRVInstrInfo.h" +#include "llvm/CodeGen/GlobalISel/CallLowering.h" +#include "llvm/CodeGen/GlobalISel/InstructionSelector.h" +#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h" +#include "llvm/CodeGen/SelectionDAGTargetInfo.h" +#include "llvm/CodeGen/TargetSubtargetInfo.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/Target/TargetMachine.h" + +#define GET_SUBTARGETINFO_HEADER +#include "SPIRVGenSubtargetInfo.inc" + +namespace llvm { +class StringRef; + +class SPIRVTargetMachine; + +class SPIRVSubtarget : public SPIRVGenSubtargetInfo { +private: + const unsigned PointerSize; + uint32_t SPIRVVersion; + + SPIRVInstrInfo InstrInfo; + SPIRVFrameLowering FrameLowering; + SPIRVTargetLowering TLInfo; + + // GlobalISel related APIs. + std::unique_ptr CallLoweringInfo; + std::unique_ptr RegBankInfo; + +public: + // This constructor initializes the data members to match that + // of the specified triple. + SPIRVSubtarget(const Triple &TT, const std::string &CPU, + const std::string &FS, const SPIRVTargetMachine &TM); + SPIRVSubtarget &initSubtargetDependencies(StringRef CPU, StringRef FS); + + // Parses features string setting specified subtarget options. + // The definition of this function is auto generated by tblgen. + void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS); + unsigned getPointerSize() const { return PointerSize; } + bool canDirectlyComparePointers() const; + uint32_t getSPIRVVersion() const { return SPIRVVersion; }; + + const CallLowering *getCallLowering() const override { + return CallLoweringInfo.get(); + } + const RegisterBankInfo *getRegBankInfo() const override { + return RegBankInfo.get(); + } + const SPIRVInstrInfo *getInstrInfo() const override { return &InstrInfo; } + const SPIRVFrameLowering *getFrameLowering() const override { + return &FrameLowering; + } + const SPIRVTargetLowering *getTargetLowering() const override { + return &TLInfo; + } + const SPIRVRegisterInfo *getRegisterInfo() const override { + return &InstrInfo.getRegisterInfo(); + } +}; +} // namespace llvm + +#endif // LLVM_LIB_TARGET_SPIRV_SPIRVSUBTARGET_H diff --git a/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp b/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp @@ -0,0 +1,61 @@ +//===-- SPIRVSubtarget.cpp - SPIR-V Subtarget 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 implements the SPIR-V specific subclass of TargetSubtargetInfo. +// +//===----------------------------------------------------------------------===// + +#include "SPIRVSubtarget.h" +#include "SPIRV.h" +#include "SPIRVRegisterBankInfo.h" +#include "SPIRVTargetMachine.h" +#include "llvm/MC/TargetRegistry.h" +#include "llvm/Support/Host.h" + +using namespace llvm; + +#define DEBUG_TYPE "spirv-subtarget" + +#define GET_SUBTARGETINFO_TARGET_DESC +#define GET_SUBTARGETINFO_CTOR +#include "SPIRVGenSubtargetInfo.inc" + +// Compare version numbers, but allow 0 to mean unspecified. +static bool isAtLeastVer(uint32_t Target, uint32_t VerToCompareTo) { + return Target == 0 || Target >= VerToCompareTo; +} + +static unsigned computePointerSize(const Triple &TT) { + const auto Arch = TT.getArch(); + // TODO: unify this with pointers legalization. + assert(TT.isSPIRV()); + return Arch == Triple::spirv32 ? 32 : 64; +} + +SPIRVSubtarget::SPIRVSubtarget(const Triple &TT, const std::string &CPU, + const std::string &FS, + const SPIRVTargetMachine &TM) + : SPIRVGenSubtargetInfo(TT, CPU, /*TuneCPU=*/CPU, FS), + PointerSize(computePointerSize(TT)), SPIRVVersion(0), InstrInfo(), + FrameLowering(initSubtargetDependencies(CPU, FS)), TLInfo(TM, *this) { + CallLoweringInfo = std::make_unique(TLInfo); + RegBankInfo = std::make_unique(); +} + +SPIRVSubtarget &SPIRVSubtarget::initSubtargetDependencies(StringRef CPU, + StringRef FS) { + ParseSubtargetFeatures(CPU, /*TuneCPU=*/CPU, FS); + if (SPIRVVersion == 0) + SPIRVVersion = 14; + return *this; +} + +// If the SPIR-V version is >= 1.4 we can call OpPtrEqual and OpPtrNotEqual. +bool SPIRVSubtarget::canDirectlyComparePointers() const { + return isAtLeastVer(SPIRVVersion, 14); +} diff --git a/llvm/lib/Target/SPIRV/SPIRVTargetMachine.h b/llvm/lib/Target/SPIRV/SPIRVTargetMachine.h --- a/llvm/lib/Target/SPIRV/SPIRVTargetMachine.h +++ b/llvm/lib/Target/SPIRV/SPIRVTargetMachine.h @@ -13,12 +13,13 @@ #ifndef LLVM_LIB_TARGET_SPIRV_SPIRVTARGETMACHINE_H #define LLVM_LIB_TARGET_SPIRV_SPIRVTARGETMACHINE_H -#include "llvm/IR/DataLayout.h" +#include "SPIRVSubtarget.h" #include "llvm/Target/TargetMachine.h" namespace llvm { class SPIRVTargetMachine : public LLVMTargetMachine { std::unique_ptr TLOF; + SPIRVSubtarget Subtarget; public: SPIRVTargetMachine(const Target &T, const Triple &TT, StringRef CPU, @@ -26,7 +27,16 @@ Optional RM, Optional CM, CodeGenOpt::Level OL, bool JIT); + const SPIRVSubtarget *getSubtargetImpl() const { return &Subtarget; } + + const SPIRVSubtarget *getSubtargetImpl(const Function &) const override { + return &Subtarget; + } + + TargetTransformInfo getTargetTransformInfo(const Function &F) const override; + TargetPassConfig *createPassConfig(PassManagerBase &PM) override; + bool usesPhysRegsForValues() const override { return false; } TargetLoweringObjectFile *getObjFileLowering() const override { return TLOF.get(); @@ -34,4 +44,4 @@ }; } // namespace llvm -#endif +#endif // LLVM_LIB_TARGET_SPIRV_SPIRVTARGETMACHINE_H diff --git a/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp b/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp --- a/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp @@ -11,10 +11,22 @@ //===----------------------------------------------------------------------===// #include "SPIRVTargetMachine.h" +#include "SPIRV.h" +#include "SPIRVTargetObjectFile.h" +#include "SPIRVTargetTransformInfo.h" #include "TargetInfo/SPIRVTargetInfo.h" +#include "llvm/CodeGen/GlobalISel/IRTranslator.h" +#include "llvm/CodeGen/GlobalISel/InstructionSelect.h" +#include "llvm/CodeGen/GlobalISel/Legalizer.h" +#include "llvm/CodeGen/GlobalISel/RegBankSelect.h" +#include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" #include "llvm/CodeGen/TargetPassConfig.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/InitializePasses.h" #include "llvm/MC/TargetRegistry.h" +#include "llvm/Pass.h" +#include "llvm/Target/TargetOptions.h" using namespace llvm; @@ -41,6 +53,9 @@ return *RM; } +// Pin SPIRVTargetObjectFile's vtables to this file. +SPIRVTargetObjectFile::~SPIRVTargetObjectFile() {} + SPIRVTargetMachine::SPIRVTargetMachine(const Target &T, const Triple &TT, StringRef CPU, StringRef FS, const TargetOptions &Options, @@ -50,8 +65,13 @@ : LLVMTargetMachine(T, computeDataLayout(TT), TT, CPU, FS, Options, getEffectiveRelocModel(RM), getEffectiveCodeModel(CM, CodeModel::Small), OL), - TLOF(std::make_unique()) { + TLOF(std::make_unique()), + Subtarget(TT, CPU.str(), FS.str(), *this) { initAsmInfo(); + setGlobalISel(true); + setFastISel(false); + setO0WantsFastISel(false); + setRequiresStructuredCFG(false); } namespace { @@ -64,9 +84,78 @@ SPIRVTargetMachine &getSPIRVTargetMachine() const { return getTM(); } + void addIRPasses() override; + void addISelPrepare() override; + + bool addIRTranslator() override; + bool addLegalizeMachineIR() override; + bool addRegBankSelect() override; + bool addGlobalInstructionSelect() override; + + FunctionPass *createTargetRegisterAllocator(bool) override; + void addFastRegAlloc() override {} + void addOptimizedRegAlloc() override {} + + void addPostRegAlloc() override; }; } // namespace +// We do not use physical registers, and maintain virtual registers throughout +// the entire pipeline, so return nullptr to disable register allocation. +FunctionPass *SPIRVPassConfig::createTargetRegisterAllocator(bool) { + return nullptr; +} + +// Disable passes that break from assuming no virtual registers exist. +void SPIRVPassConfig::addPostRegAlloc() { + // Do not work with vregs instead of physical regs. + disablePass(&MachineCopyPropagationID); + disablePass(&PostRAMachineSinkingID); + disablePass(&PostRASchedulerID); + disablePass(&FuncletLayoutID); + disablePass(&StackMapLivenessID); + disablePass(&PatchableFunctionID); + disablePass(&ShrinkWrapID); + disablePass(&LiveDebugValuesID); + + // Do not work with OpPhi. + disablePass(&BranchFolderPassID); + disablePass(&MachineBlockPlacementID); + + TargetPassConfig::addPostRegAlloc(); +} + +TargetTransformInfo +SPIRVTargetMachine::getTargetTransformInfo(const Function &F) const { + return TargetTransformInfo(SPIRVTTIImpl(this, F)); +} + TargetPassConfig *SPIRVTargetMachine::createPassConfig(PassManagerBase &PM) { return new SPIRVPassConfig(*this, PM); } + +void SPIRVPassConfig::addIRPasses() { TargetPassConfig::addIRPasses(); } + +void SPIRVPassConfig::addISelPrepare() { TargetPassConfig::addISelPrepare(); } + +bool SPIRVPassConfig::addIRTranslator() { + addPass(new IRTranslator(getOptLevel())); + return false; +} + +// Use a default legalizer. +bool SPIRVPassConfig::addLegalizeMachineIR() { + addPass(new Legalizer()); + return false; +} + +// Do not add a RegBankSelect pass, as we only ever need virtual registers. +bool SPIRVPassConfig::addRegBankSelect() { + disablePass(&RegBankSelect::ID); + return false; +} + +bool SPIRVPassConfig::addGlobalInstructionSelect() { + addPass(new InstructionSelect(getOptLevel())); + return false; +} diff --git a/llvm/lib/Target/SPIRV/SPIRVTargetObjectFile.h b/llvm/lib/Target/SPIRV/SPIRVTargetObjectFile.h new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/SPIRV/SPIRVTargetObjectFile.h @@ -0,0 +1,45 @@ +//===-- SPIRVTargetObjectFile.h - SPIRV Object Info -------------*- 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_SPIRVTARGETOBJECTFILE_H +#define LLVM_LIB_TARGET_SPIRV_SPIRVTARGETOBJECTFILE_H + +#include "llvm/MC/MCSection.h" +#include "llvm/MC/SectionKind.h" +#include "llvm/Target/TargetLoweringObjectFile.h" + +namespace llvm { + +class SPIRVTargetObjectFile : public TargetLoweringObjectFile { +public: + ~SPIRVTargetObjectFile() override; + + void Initialize(MCContext &ctx, const TargetMachine &TM) override { + TargetLoweringObjectFile::Initialize(ctx, TM); + } + // All words in a SPIR-V module (excepting the first 5 ones) are a linear + // sequence of instructions in a specific order. We put all the instructions + // in the single text section. + MCSection *getSectionForConstant(const DataLayout &DL, SectionKind Kind, + const Constant *C, + Align &Alignment) const override { + return TextSection; + } + MCSection *getExplicitSectionGlobal(const GlobalObject *GO, SectionKind Kind, + const TargetMachine &TM) const override { + return TextSection; + } + MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind, + const TargetMachine &TM) const override { + return TextSection; + } +}; + +} // end namespace llvm + +#endif // LLVM_LIB_TARGET_SPIRV_SPIRVTARGETOBJECTFILE_H diff --git a/llvm/lib/Target/SPIRV/SPIRVTargetTransformInfo.h b/llvm/lib/Target/SPIRV/SPIRVTargetTransformInfo.h new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/SPIRV/SPIRVTargetTransformInfo.h @@ -0,0 +1,44 @@ +//===- SPIRVTargetTransformInfo.h - SPIR-V specific TTI ---------*- 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 +// +//===----------------------------------------------------------------------===// +// \file +// This file contains a TargetTransformInfo::Concept conforming object specific +// to the SPIRV target machine. It uses the target's detailed information to +// provide more precise answers to certain TTI queries, while letting the +// target independent and default TTI implementations handle the rest. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_SPIRV_SPIRVTARGETTRANSFORMINFO_H +#define LLVM_LIB_TARGET_SPIRV_SPIRVTARGETTRANSFORMINFO_H + +#include "SPIRV.h" +#include "SPIRVTargetMachine.h" +#include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/CodeGen/BasicTTIImpl.h" + +namespace llvm { +class SPIRVTTIImpl : public BasicTTIImplBase { + using BaseT = BasicTTIImplBase; + + friend BaseT; + + const SPIRVSubtarget *ST; + const SPIRVTargetLowering *TLI; + + const TargetSubtargetInfo *getST() const { return ST; } + const SPIRVTargetLowering *getTLI() const { return TLI; } + +public: + explicit SPIRVTTIImpl(const SPIRVTargetMachine *TM, const Function &F) + : BaseT(TM, F.getParent()->getDataLayout()), ST(TM->getSubtargetImpl(F)), + TLI(ST->getTargetLowering()) {} +}; + +} // namespace llvm + +#endif // LLVM_LIB_TARGET_SPIRV_SPIRVTARGETTRANSFORMINFO_H