Index: llvm/lib/Target/SPIRV/CMakeLists.txt =================================================================== --- llvm/lib/Target/SPIRV/CMakeLists.txt +++ llvm/lib/Target/SPIRV/CMakeLists.txt @@ -13,6 +13,14 @@ 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 Index: llvm/lib/Target/SPIRV/SPIRV.h =================================================================== --- /dev/null +++ llvm/lib/Target/SPIRV/SPIRV.h @@ -0,0 +1,22 @@ +//===-- 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 SPIRVRegisterBankInfo; +class SPIRVSubtarget; +} // namespace llvm + +#endif // LLVM_LIB_TARGET_SPIRV_SPIRV_H Index: llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp =================================================================== --- /dev/null +++ llvm/lib/Target/SPIRV/SPIRVAsmPrinter.cpp @@ -0,0 +1,136 @@ +//===-- 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" void LLVMInitializeSPIRVAsmPrinter() { + RegisterAsmPrinter X(getTheSPIRV32Target()); + RegisterAsmPrinter Y(getTheSPIRV64Target()); +} Index: llvm/lib/Target/SPIRV/SPIRVCallLowering.h =================================================================== --- /dev/null +++ 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 Index: llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp =================================================================== --- /dev/null +++ llvm/lib/Target/SPIRV/SPIRVCallLowering.cpp @@ -0,0 +1,113 @@ +//===--- 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" +#include "llvm/Demangle/Demangle.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 { + assert(VRegs.size() < 2 && "All return types should use a single register"); + if (Val) { + MIRBuilder.buildInstr(SPIRV::OpReturnValue).addUse(VRegs[0]); + return true; + } else { + 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 = 0; + return FuncControl; +} + +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 int i = 0; + for (const auto &Arg : F.args()) { + assert(VRegs[i].size() == 1 && "Formal arg has multiple vregs"); + 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); + + uint32_t FuncControl = getFunctionControl(F); + + MIRBuilder.buildInstr(SPIRV::OpFunction) + .addDef(FuncVReg) + .addUse(MRI->createGenericVirtualRegister(LLT::scalar(32))) + .addImm(FuncControl) + .addUse(MRI->createGenericVirtualRegister(LLT::scalar(32))); + + // Add OpFunctionParameters + const unsigned int NumArgs = ArgTypeVRegs.size(); + for (unsigned int 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 { + auto FuncName = Info.Callee.getGlobal()->getGlobalIdentifier(); + + assert(Info.OrigRet.Regs.size() < 2 && "Call returns multiple vregs"); + + 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) { + assert(arg.Regs.size() == 1 && "Call arg has multiple VRegs"); + MIB.addUse(arg.Regs[0]); + } + return true; +} Index: llvm/lib/Target/SPIRV/SPIRVFrameLowering.h =================================================================== --- /dev/null +++ llvm/lib/Target/SPIRV/SPIRVFrameLowering.h @@ -0,0 +1,35 @@ +//===-- 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. +// +//===----------------------------------------------------------------------===// + +#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 Index: llvm/lib/Target/SPIRV/SPIRVISelLowering.h =================================================================== --- /dev/null +++ llvm/lib/Target/SPIRV/SPIRVISelLowering.h @@ -0,0 +1,53 @@ +//===-- 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; +#if 0 + bool getTgtMemIntrinsic(IntrinsicInfo &Info, const CallInst &I, + MachineFunction &MF, + unsigned Intrinsic) const override; +#endif +}; +} // namespace llvm + +#endif // LLVM_LIB_TARGET_SPIRV_SPIRVISELLOWERING_H Index: llvm/lib/Target/SPIRV/SPIRVISelLowering.cpp =================================================================== --- /dev/null +++ llvm/lib/Target/SPIRV/SPIRVISelLowering.cpp @@ -0,0 +1,71 @@ +//===- 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" +//#include "llvm/IR/IntrinsicsSPIRV.h" + +#define DEBUG_TYPE "spirv-lower" + +using namespace llvm; + +unsigned SPIRVTargetLowering::getNumRegistersForCallingConv( + LLVMContext &Context, CallingConv::ID CC, EVT VT) const { + // Avoid fail on v3i1 argument. Maybe we need to return 1 for all types. + 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 { + // Avoid fail on v3i1 argument. Maybe we need to return i32 for all types. + 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); +} + +#if 0 +bool SPIRVTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info, + const CallInst &I, + MachineFunction &MF, + unsigned Intrinsic) const { + unsigned AlignIdx = 3; + switch (Intrinsic) { + case Intrinsic::spv_load: + AlignIdx = 2; + LLVM_FALLTHROUGH; + case Intrinsic::spv_store: { + if (I.getNumOperands() >= AlignIdx + 1) { + auto *AlignOp = cast(I.getOperand(AlignIdx)); + Info.align = Align(AlignOp->getZExtValue()); + } + Info.flags = static_cast( + cast(I.getOperand(AlignIdx - 1))->getZExtValue()); + Info.memVT = MVT::i64; + // MVT::getVT(PtrTy->getElementType()); + return true; + break; + } + default: + break; + } + return false; +} +#endif Index: llvm/lib/Target/SPIRV/SPIRVInstrInfo.h =================================================================== --- /dev/null +++ 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 Index: llvm/lib/Target/SPIRV/SPIRVInstrInfo.cpp =================================================================== --- /dev/null +++ llvm/lib/Target/SPIRV/SPIRVInstrInfo.cpp @@ -0,0 +1,241 @@ +//===-- 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; +using namespace SPIRV; + +SPIRVInstrInfo::SPIRVInstrInfo() : SPIRVGenInstrInfo() {} + +bool SPIRVInstrInfo::isConstantInstr(const MachineInstr &MI) const { + switch (MI.getOpcode()) { + case OpConstantTrue: + case OpConstantFalse: + case OpConstantI: + case OpConstantF: + case OpConstantComposite: + case OpConstantSampler: + case OpConstantNull: + case OpSpecConstantTrue: + case OpSpecConstantFalse: + case OpSpecConstant: + case OpSpecConstantComposite: + case OpSpecConstantOp: + case 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() == TYPERegClass.getID(); + } else { + return false; + } +} + +bool SPIRVInstrInfo::isDecorationInstr(const MachineInstr &MI) const { + switch (MI.getOpcode()) { + case OpDecorate: + case OpDecorateId: + case OpDecorateString: + case OpMemberDecorate: + case OpMemberDecorateString: + return true; + default: + return false; + } +} + +bool SPIRVInstrInfo::isHeaderInstr(const MachineInstr &MI) const { + switch (MI.getOpcode()) { + case OpCapability: + case OpExtension: + case OpExtInstImport: + case OpMemoryModel: + case OpEntryPoint: + case OpExecutionMode: + case OpExecutionModeId: + case OpString: + case OpSourceExtension: + case OpSource: + case OpSourceContinued: + case OpName: + case OpMemberName: + case 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 { + llvm_unreachable("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 { + + llvm_unreachable("Branch insertion not supported, as MBB info not propagated " + "to OpPhi instructions. Try using -O0 instead."); + + MachineIRBuilder MIRBuilder; + MIRBuilder.setMF(*MBB.getParent()); + MIRBuilder.setMBB(MBB); + + int LocalBytesAdded = 0; + int InstsAdded = 0; + if (Cond.size() > 0) { // Conditional branch (but may only have true MBB) + assert(TBB != nullptr && "Require non-null block for conditional branch"); + assert(Cond.size() == 1 && "Require 1 condition for insertBranch"); + auto falseBlock = FBB; //? FBB : MBB.getFallThrough(); + auto MIB = MIRBuilder.buildInstr(SPIRV::OpBranchConditional) + .addUse(Cond[0].getReg()) + .addMBB(TBB); + if (falseBlock) { + MIB.addMBB(falseBlock); + } + LocalBytesAdded = 16; + InstsAdded = 1; + } else { // Either add unconditional branch, or add to last conditional branch + assert(!FBB && "False block set with no conditions"); + if (TBB) { + if (MBB.empty()) { + MIRBuilder.buildInstr(SPIRV::OpBranch).addMBB(TBB); + LocalBytesAdded = 8; + } else { + auto MI = MBB.getLastNonDebugInstr(); + if (MI.isValid() && !MI->isKnownSentinel() && + MI->getOpcode() == SPIRV::OpBranchConditional) { + if (MI->getNumOperands() == 3) { + MI->getOperand(2).setMBB(TBB); + } else { + MI->addOperand(MachineOperand::CreateMBB(TBB)); + } + } else { + MIRBuilder.buildInstr(SPIRV::OpBranch).addMBB(TBB); + LocalBytesAdded = 8; + } + } + InstsAdded = 1; + } + } + if (LocalBytesAdded) + *BytesAdded = LocalBytesAdded; + return InstsAdded; +} + +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()); +} Index: llvm/lib/Target/SPIRV/SPIRVMCInstLower.h =================================================================== --- /dev/null +++ llvm/lib/Target/SPIRV/SPIRVMCInstLower.h @@ -0,0 +1,26 @@ +//=- 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; + +// SPIRVMCInstLower - This class is used to lower a MachineInstr into an MCInst. +class LLVM_LIBRARY_VISIBILITY SPIRVMCInstLower { +public: + SPIRVMCInstLower() {} + void Lower(const MachineInstr *MI, MCInst &OutMI) const; +}; +} // namespace llvm + +#endif // LLVM_LIB_TARGET_SPIRV_SPIRVMCINSTLOWER_H Index: llvm/lib/Target/SPIRV/SPIRVMCInstLower.cpp =================================================================== --- /dev/null +++ llvm/lib/Target/SPIRV/SPIRVMCInstLower.cpp @@ -0,0 +1,46 @@ +//=- 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); + + // At this stage, SPIR-V should only have Register and Immediate operands + MCOperand MCOp; + switch (MO.getType()) { + default: + MI->print(errs()); + 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); + } +} Index: llvm/lib/Target/SPIRV/SPIRVRegisterBankInfo.h =================================================================== --- /dev/null +++ llvm/lib/Target/SPIRV/SPIRVRegisterBankInfo.h @@ -0,0 +1,40 @@ +//===- 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/GlobalISel/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: + SPIRVRegisterBankInfo() = default; + + const RegisterBank &getRegBankFromRegClass(const TargetRegisterClass &RC, + LLT Ty) const override; +}; +} // namespace llvm +#endif // LLVM_LIB_TARGET_SPIRV_SPIRVREGISTERBANKINFO_H Index: llvm/lib/Target/SPIRV/SPIRVRegisterBankInfo.cpp =================================================================== --- /dev/null +++ llvm/lib/Target/SPIRV/SPIRVRegisterBankInfo.cpp @@ -0,0 +1,48 @@ +//===- 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/GlobalISel/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"); +} Index: llvm/lib/Target/SPIRV/SPIRVRegisterInfo.h =================================================================== --- /dev/null +++ llvm/lib/Target/SPIRV/SPIRVRegisterInfo.h @@ -0,0 +1,41 @@ +//===-- 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 Index: llvm/lib/Target/SPIRV/SPIRVRegisterInfo.cpp =================================================================== --- /dev/null +++ llvm/lib/Target/SPIRV/SPIRVRegisterInfo.cpp @@ -0,0 +1,35 @@ +//===-- 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 { + BitVector Reserved(getNumRegs()); + return Reserved; +} + +// Dummy to not crash RegisterClassInfo. +static const MCPhysReg CalleeSavedReg = SPIRV::NoRegister; + +const MCPhysReg * +SPIRVRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { + return &CalleeSavedReg; +} Index: llvm/lib/Target/SPIRV/SPIRVSubtarget.h =================================================================== --- /dev/null +++ llvm/lib/Target/SPIRV/SPIRVSubtarget.h @@ -0,0 +1,124 @@ +//===-- 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 "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/GlobalISel/RegisterBankInfo.h" +#include "llvm/CodeGen/SelectionDAGTargetInfo.h" +#include "llvm/CodeGen/TargetSubtargetInfo.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/Target/TargetMachine.h" + +#include "SPIRVCallLowering.h" +#include "SPIRVRegisterBankInfo.h" + +#include + +#define GET_SUBTARGETINFO_HEADER +#include "SPIRVGenSubtargetInfo.inc" + +namespace llvm { +class StringRef; + +class SPIRVTargetMachine; + +class SPIRVSubtarget : public SPIRVGenSubtargetInfo { +private: + const unsigned int PointerSize; + + const bool UsesLogicalAddressing; + const bool UsesVulkanEnv; + const bool UsesOpenCLEnv; + + uint32_t TargetSPIRVVersion; + uint32_t TargetOpenCLVersion; + uint32_t TargetVulkanVersion; + bool OpenCLFullProfile; + bool OpenCLImageSupport; + + SPIRVInstrInfo InstrInfo; + SPIRVFrameLowering FrameLowering; + SPIRVTargetLowering TLInfo; + + // TODO Some of these fields might work without unique_ptr. + // But they are shared with other classes, so if the SPIRVSubtarget + // moves, not relying on unique_ptr breaks things. + std::unique_ptr CallLoweringInfo; + std::unique_ptr RegBankInfo; + +private: + // Initialise the available extensions, extended instruction sets and + // capabilities based on the environment settings (i.e. the previous + // properties of SPIRVSubtarget). + // + // These functions must be called in the order they are declared to satisfy + // dependencies during initialisation. + void initAvailableExtensions(const Triple &TT); + void initAvailableExtInstSets(const Triple &TT); + void initAvailableCapabilities(const Triple &TT); + +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 int getPointerSize() const { return PointerSize; } + bool canDirectlyComparePointers() const; + + bool isLogicalAddressing() const; + bool isKernel() const; + bool isShader() const; + + uint32_t getTargetSPIRVVersion() const { return TargetSPIRVVersion; }; + + const CallLowering *getCallLowering() const override { + return CallLoweringInfo.get(); + } + + const RegisterBankInfo *getRegBankInfo() const override { + return RegBankInfo.get(); + } + + bool isLittleEndian() const { return true; } + + 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 Index: llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp =================================================================== --- /dev/null +++ llvm/lib/Target/SPIRV/SPIRVSubtarget.cpp @@ -0,0 +1,89 @@ +//===-- 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 "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 + return Arch == Triple::spirv32 ? 32 : Arch == Triple::spirv64 ? 64 : 8; +} + +// TODO use command line args for this rather than defaulting to 1.1 +static uint32_t computeTargetVulkanVersion(const Triple &TT) { return 0; } + +// TODO use command line args for this rather than defaulting to true +static bool computeOpenCLImageSupport(const Triple &TT) { return true; } + +// TODO use command line args for this rather than defaulting to true +static bool computeOpenCLFullProfile(const Triple &TT) { return true; } + +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)), UsesLogicalAddressing(false), + UsesVulkanEnv(false), UsesOpenCLEnv(false), TargetSPIRVVersion(0), + TargetOpenCLVersion(0), + TargetVulkanVersion(computeTargetVulkanVersion(TT)), + OpenCLFullProfile(computeOpenCLFullProfile(TT)), + OpenCLImageSupport(computeOpenCLImageSupport(TT)), InstrInfo(), + FrameLowering(initSubtargetDependencies(CPU, FS)), TLInfo(TM, *this), + CallLoweringInfo(new SPIRVCallLowering(TLInfo)), + RegBankInfo(new SPIRVRegisterBankInfo()) {} + +SPIRVSubtarget &SPIRVSubtarget::initSubtargetDependencies(StringRef CPU, + StringRef FS) { + ParseSubtargetFeatures(CPU, /* TuneCPU */ CPU, FS); + + if (TargetSPIRVVersion == 0) + TargetSPIRVVersion = 14; + if (TargetOpenCLVersion == 0) + TargetOpenCLVersion = 22; + + return *this; +} + +bool SPIRVSubtarget::isLogicalAddressing() const { + return UsesLogicalAddressing; +} + +bool SPIRVSubtarget::isKernel() const { + return UsesOpenCLEnv || !UsesLogicalAddressing; +} + +bool SPIRVSubtarget::isShader() const { + return UsesVulkanEnv || UsesLogicalAddressing; +} + +// If the SPIR-V version is >= 1.4 we can call OpPtrEqual and OpPtrNotEqual +bool SPIRVSubtarget::canDirectlyComparePointers() const { + bool Res = isAtLeastVer(TargetSPIRVVersion, 14); + return Res; +} Index: llvm/lib/Target/SPIRV/SPIRVTargetMachine.h =================================================================== --- llvm/lib/Target/SPIRV/SPIRVTargetMachine.h +++ 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,12 +27,25 @@ 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) override; + TargetPassConfig *createPassConfig(PassManagerBase &PM) override; + bool usesPhysRegsForValues() const override { return false; } TargetLoweringObjectFile *getObjFileLowering() const override { return TLOF.get(); } + + bool isNoopAddrSpaceCast(unsigned SrcAS, unsigned DestAS) const override { + return true; + } }; } // namespace llvm -#endif +#endif // LLVM_LIB_TARGET_SPIRV_SPIRVTARGETMACHINE_H Index: llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp =================================================================== --- llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp +++ llvm/lib/Target/SPIRV/SPIRVTargetMachine.cpp @@ -11,10 +11,23 @@ //===----------------------------------------------------------------------===// #include "SPIRVTargetMachine.h" +#include "SPIRV.h" +#include "SPIRVSubtarget.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; @@ -42,6 +55,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, @@ -51,8 +67,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 { @@ -65,9 +86,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) { + 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; +} Index: llvm/lib/Target/SPIRV/SPIRVTargetObjectFile.h =================================================================== --- /dev/null +++ llvm/lib/Target/SPIRV/SPIRVTargetObjectFile.h @@ -0,0 +1,47 @@ +//===-- 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() : TargetLoweringObjectFile() {} + + ~SPIRVTargetObjectFile() override; + + void Initialize(MCContext &ctx, const TargetMachine &TM) override { + TargetLoweringObjectFile::Initialize(ctx, TM); + } + + 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 Index: llvm/lib/Target/SPIRV/SPIRVTargetTransformInfo.h =================================================================== --- /dev/null +++ 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