Path: blob/main/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp
35269 views
//===-- SPIRVPreLegalizer.cpp - prepare IR for legalization -----*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// The pass prepares IR for legalization: it assigns SPIR-V types to registers9// and removes intrinsics which holded these types during IR translation.10// Also it processes constants and registers them in GR to avoid duplication.11//12//===----------------------------------------------------------------------===//1314#include "SPIRV.h"15#include "SPIRVSubtarget.h"16#include "SPIRVUtils.h"17#include "llvm/ADT/PostOrderIterator.h"18#include "llvm/Analysis/OptimizationRemarkEmitter.h"19#include "llvm/IR/Attributes.h"20#include "llvm/IR/Constants.h"21#include "llvm/IR/DebugInfoMetadata.h"22#include "llvm/IR/IntrinsicsSPIRV.h"23#include "llvm/Target/TargetIntrinsicInfo.h"2425#define DEBUG_TYPE "spirv-prelegalizer"2627using namespace llvm;2829namespace {30class SPIRVPreLegalizer : public MachineFunctionPass {31public:32static char ID;33SPIRVPreLegalizer() : MachineFunctionPass(ID) {34initializeSPIRVPreLegalizerPass(*PassRegistry::getPassRegistry());35}36bool runOnMachineFunction(MachineFunction &MF) override;37};38} // namespace3940static void41addConstantsToTrack(MachineFunction &MF, SPIRVGlobalRegistry *GR,42const SPIRVSubtarget &STI,43DenseMap<MachineInstr *, Type *> &TargetExtConstTypes,44SmallSet<Register, 4> &TrackedConstRegs) {45MachineRegisterInfo &MRI = MF.getRegInfo();46DenseMap<MachineInstr *, Register> RegsAlreadyAddedToDT;47SmallVector<MachineInstr *, 10> ToErase, ToEraseComposites;48for (MachineBasicBlock &MBB : MF) {49for (MachineInstr &MI : MBB) {50if (!isSpvIntrinsic(MI, Intrinsic::spv_track_constant))51continue;52ToErase.push_back(&MI);53Register SrcReg = MI.getOperand(2).getReg();54auto *Const =55cast<Constant>(cast<ConstantAsMetadata>(56MI.getOperand(3).getMetadata()->getOperand(0))57->getValue());58if (auto *GV = dyn_cast<GlobalValue>(Const)) {59Register Reg = GR->find(GV, &MF);60if (!Reg.isValid())61GR->add(GV, &MF, SrcReg);62else63RegsAlreadyAddedToDT[&MI] = Reg;64} else {65Register Reg = GR->find(Const, &MF);66if (!Reg.isValid()) {67if (auto *ConstVec = dyn_cast<ConstantDataVector>(Const)) {68auto *BuildVec = MRI.getVRegDef(SrcReg);69assert(BuildVec &&70BuildVec->getOpcode() == TargetOpcode::G_BUILD_VECTOR);71for (unsigned i = 0; i < ConstVec->getNumElements(); ++i) {72// Ensure that OpConstantComposite reuses a constant when it's73// already created and available in the same machine function.74Constant *ElemConst = ConstVec->getElementAsConstant(i);75Register ElemReg = GR->find(ElemConst, &MF);76if (!ElemReg.isValid())77GR->add(ElemConst, &MF, BuildVec->getOperand(1 + i).getReg());78else79BuildVec->getOperand(1 + i).setReg(ElemReg);80}81}82GR->add(Const, &MF, SrcReg);83TrackedConstRegs.insert(SrcReg);84if (Const->getType()->isTargetExtTy()) {85// remember association so that we can restore it when assign types86MachineInstr *SrcMI = MRI.getVRegDef(SrcReg);87if (SrcMI && (SrcMI->getOpcode() == TargetOpcode::G_CONSTANT ||88SrcMI->getOpcode() == TargetOpcode::G_IMPLICIT_DEF))89TargetExtConstTypes[SrcMI] = Const->getType();90if (Const->isNullValue()) {91MachineIRBuilder MIB(MF);92SPIRVType *ExtType =93GR->getOrCreateSPIRVType(Const->getType(), MIB);94SrcMI->setDesc(STI.getInstrInfo()->get(SPIRV::OpConstantNull));95SrcMI->addOperand(MachineOperand::CreateReg(96GR->getSPIRVTypeID(ExtType), false));97}98}99} else {100RegsAlreadyAddedToDT[&MI] = Reg;101// This MI is unused and will be removed. If the MI uses102// const_composite, it will be unused and should be removed too.103assert(MI.getOperand(2).isReg() && "Reg operand is expected");104MachineInstr *SrcMI = MRI.getVRegDef(MI.getOperand(2).getReg());105if (SrcMI && isSpvIntrinsic(*SrcMI, Intrinsic::spv_const_composite))106ToEraseComposites.push_back(SrcMI);107}108}109}110}111for (MachineInstr *MI : ToErase) {112Register Reg = MI->getOperand(2).getReg();113if (RegsAlreadyAddedToDT.contains(MI))114Reg = RegsAlreadyAddedToDT[MI];115auto *RC = MRI.getRegClassOrNull(MI->getOperand(0).getReg());116if (!MRI.getRegClassOrNull(Reg) && RC)117MRI.setRegClass(Reg, RC);118MRI.replaceRegWith(MI->getOperand(0).getReg(), Reg);119MI->eraseFromParent();120}121for (MachineInstr *MI : ToEraseComposites)122MI->eraseFromParent();123}124125static void126foldConstantsIntoIntrinsics(MachineFunction &MF,127const SmallSet<Register, 4> &TrackedConstRegs) {128SmallVector<MachineInstr *, 10> ToErase;129MachineRegisterInfo &MRI = MF.getRegInfo();130const unsigned AssignNameOperandShift = 2;131for (MachineBasicBlock &MBB : MF) {132for (MachineInstr &MI : MBB) {133if (!isSpvIntrinsic(MI, Intrinsic::spv_assign_name))134continue;135unsigned NumOp = MI.getNumExplicitDefs() + AssignNameOperandShift;136while (MI.getOperand(NumOp).isReg()) {137MachineOperand &MOp = MI.getOperand(NumOp);138MachineInstr *ConstMI = MRI.getVRegDef(MOp.getReg());139assert(ConstMI->getOpcode() == TargetOpcode::G_CONSTANT);140MI.removeOperand(NumOp);141MI.addOperand(MachineOperand::CreateImm(142ConstMI->getOperand(1).getCImm()->getZExtValue()));143Register DefReg = ConstMI->getOperand(0).getReg();144if (MRI.use_empty(DefReg) && !TrackedConstRegs.contains(DefReg))145ToErase.push_back(ConstMI);146}147}148}149for (MachineInstr *MI : ToErase)150MI->eraseFromParent();151}152153static MachineInstr *findAssignTypeInstr(Register Reg,154MachineRegisterInfo *MRI) {155for (MachineRegisterInfo::use_instr_iterator I = MRI->use_instr_begin(Reg),156IE = MRI->use_instr_end();157I != IE; ++I) {158MachineInstr *UseMI = &*I;159if ((isSpvIntrinsic(*UseMI, Intrinsic::spv_assign_ptr_type) ||160isSpvIntrinsic(*UseMI, Intrinsic::spv_assign_type)) &&161UseMI->getOperand(1).getReg() == Reg)162return UseMI;163}164return nullptr;165}166167static void insertBitcasts(MachineFunction &MF, SPIRVGlobalRegistry *GR,168MachineIRBuilder MIB) {169// Get access to information about available extensions170const SPIRVSubtarget *ST =171static_cast<const SPIRVSubtarget *>(&MIB.getMF().getSubtarget());172SmallVector<MachineInstr *, 10> ToErase;173for (MachineBasicBlock &MBB : MF) {174for (MachineInstr &MI : MBB) {175if (!isSpvIntrinsic(MI, Intrinsic::spv_bitcast) &&176!isSpvIntrinsic(MI, Intrinsic::spv_ptrcast))177continue;178assert(MI.getOperand(2).isReg());179MIB.setInsertPt(*MI.getParent(), MI);180ToErase.push_back(&MI);181if (isSpvIntrinsic(MI, Intrinsic::spv_bitcast)) {182MIB.buildBitcast(MI.getOperand(0).getReg(), MI.getOperand(2).getReg());183continue;184}185Register Def = MI.getOperand(0).getReg();186Register Source = MI.getOperand(2).getReg();187Type *ElemTy = getMDOperandAsType(MI.getOperand(3).getMetadata(), 0);188SPIRVType *BaseTy = GR->getOrCreateSPIRVType(ElemTy, MIB);189SPIRVType *AssignedPtrType = GR->getOrCreateSPIRVPointerType(190BaseTy, MI, *MF.getSubtarget<SPIRVSubtarget>().getInstrInfo(),191addressSpaceToStorageClass(MI.getOperand(4).getImm(), *ST));192193// If the ptrcast would be redundant, replace all uses with the source194// register.195if (GR->getSPIRVTypeForVReg(Source) == AssignedPtrType) {196// Erase Def's assign type instruction if we are going to replace Def.197if (MachineInstr *AssignMI = findAssignTypeInstr(Def, MIB.getMRI()))198ToErase.push_back(AssignMI);199MIB.getMRI()->replaceRegWith(Def, Source);200} else {201GR->assignSPIRVTypeToVReg(AssignedPtrType, Def, MF);202MIB.buildBitcast(Def, Source);203}204}205}206for (MachineInstr *MI : ToErase)207MI->eraseFromParent();208}209210// Translating GV, IRTranslator sometimes generates following IR:211// %1 = G_GLOBAL_VALUE212// %2 = COPY %1213// %3 = G_ADDRSPACE_CAST %2214//215// or216//217// %1 = G_ZEXT %2218// G_MEMCPY ... %2 ...219//220// New registers have no SPIRVType and no register class info.221//222// Set SPIRVType for GV, propagate it from GV to other instructions,223// also set register classes.224static SPIRVType *propagateSPIRVType(MachineInstr *MI, SPIRVGlobalRegistry *GR,225MachineRegisterInfo &MRI,226MachineIRBuilder &MIB) {227SPIRVType *SpirvTy = nullptr;228assert(MI && "Machine instr is expected");229if (MI->getOperand(0).isReg()) {230Register Reg = MI->getOperand(0).getReg();231SpirvTy = GR->getSPIRVTypeForVReg(Reg);232if (!SpirvTy) {233switch (MI->getOpcode()) {234case TargetOpcode::G_CONSTANT: {235MIB.setInsertPt(*MI->getParent(), MI);236Type *Ty = MI->getOperand(1).getCImm()->getType();237SpirvTy = GR->getOrCreateSPIRVType(Ty, MIB);238break;239}240case TargetOpcode::G_GLOBAL_VALUE: {241MIB.setInsertPt(*MI->getParent(), MI);242const GlobalValue *Global = MI->getOperand(1).getGlobal();243Type *ElementTy = toTypedPointer(GR->getDeducedGlobalValueType(Global));244auto *Ty = TypedPointerType::get(ElementTy,245Global->getType()->getAddressSpace());246SpirvTy = GR->getOrCreateSPIRVType(Ty, MIB);247break;248}249case TargetOpcode::G_ANYEXT:250case TargetOpcode::G_SEXT:251case TargetOpcode::G_ZEXT: {252if (MI->getOperand(1).isReg()) {253if (MachineInstr *DefInstr =254MRI.getVRegDef(MI->getOperand(1).getReg())) {255if (SPIRVType *Def = propagateSPIRVType(DefInstr, GR, MRI, MIB)) {256unsigned CurrentBW = GR->getScalarOrVectorBitWidth(Def);257unsigned ExpectedBW =258std::max(MRI.getType(Reg).getScalarSizeInBits(), CurrentBW);259unsigned NumElements = GR->getScalarOrVectorComponentCount(Def);260SpirvTy = GR->getOrCreateSPIRVIntegerType(ExpectedBW, MIB);261if (NumElements > 1)262SpirvTy =263GR->getOrCreateSPIRVVectorType(SpirvTy, NumElements, MIB);264}265}266}267break;268}269case TargetOpcode::G_PTRTOINT:270SpirvTy = GR->getOrCreateSPIRVIntegerType(271MRI.getType(Reg).getScalarSizeInBits(), MIB);272break;273case TargetOpcode::G_TRUNC:274case TargetOpcode::G_ADDRSPACE_CAST:275case TargetOpcode::G_PTR_ADD:276case TargetOpcode::COPY: {277MachineOperand &Op = MI->getOperand(1);278MachineInstr *Def = Op.isReg() ? MRI.getVRegDef(Op.getReg()) : nullptr;279if (Def)280SpirvTy = propagateSPIRVType(Def, GR, MRI, MIB);281break;282}283default:284break;285}286if (SpirvTy)287GR->assignSPIRVTypeToVReg(SpirvTy, Reg, MIB.getMF());288if (!MRI.getRegClassOrNull(Reg))289MRI.setRegClass(Reg, &SPIRV::IDRegClass);290}291}292return SpirvTy;293}294295// To support current approach and limitations wrt. bit width here we widen a296// scalar register with a bit width greater than 1 to valid sizes and cap it to297// 64 width.298static void widenScalarLLTNextPow2(Register Reg, MachineRegisterInfo &MRI) {299LLT RegType = MRI.getType(Reg);300if (!RegType.isScalar())301return;302unsigned Sz = RegType.getScalarSizeInBits();303if (Sz == 1)304return;305unsigned NewSz = std::min(std::max(1u << Log2_32_Ceil(Sz), 8u), 64u);306if (NewSz != Sz)307MRI.setType(Reg, LLT::scalar(NewSz));308}309310static std::pair<Register, unsigned>311createNewIdReg(SPIRVType *SpvType, Register SrcReg, MachineRegisterInfo &MRI,312const SPIRVGlobalRegistry &GR) {313if (!SpvType)314SpvType = GR.getSPIRVTypeForVReg(SrcReg);315assert(SpvType && "VReg is expected to have SPIRV type");316LLT SrcLLT = MRI.getType(SrcReg);317LLT NewT = LLT::scalar(32);318bool IsFloat = SpvType->getOpcode() == SPIRV::OpTypeFloat;319bool IsVectorFloat =320SpvType->getOpcode() == SPIRV::OpTypeVector &&321GR.getSPIRVTypeForVReg(SpvType->getOperand(1).getReg())->getOpcode() ==322SPIRV::OpTypeFloat;323IsFloat |= IsVectorFloat;324auto GetIdOp = IsFloat ? SPIRV::GET_fID : SPIRV::GET_ID;325auto DstClass = IsFloat ? &SPIRV::fIDRegClass : &SPIRV::IDRegClass;326if (SrcLLT.isPointer()) {327unsigned PtrSz = GR.getPointerSize();328NewT = LLT::pointer(0, PtrSz);329bool IsVec = SrcLLT.isVector();330if (IsVec)331NewT = LLT::fixed_vector(2, NewT);332if (PtrSz == 64) {333if (IsVec) {334GetIdOp = SPIRV::GET_vpID64;335DstClass = &SPIRV::vpID64RegClass;336} else {337GetIdOp = SPIRV::GET_pID64;338DstClass = &SPIRV::pID64RegClass;339}340} else {341if (IsVec) {342GetIdOp = SPIRV::GET_vpID32;343DstClass = &SPIRV::vpID32RegClass;344} else {345GetIdOp = SPIRV::GET_pID32;346DstClass = &SPIRV::pID32RegClass;347}348}349} else if (SrcLLT.isVector()) {350NewT = LLT::fixed_vector(2, NewT);351if (IsFloat) {352GetIdOp = SPIRV::GET_vfID;353DstClass = &SPIRV::vfIDRegClass;354} else {355GetIdOp = SPIRV::GET_vID;356DstClass = &SPIRV::vIDRegClass;357}358}359Register IdReg = MRI.createGenericVirtualRegister(NewT);360MRI.setRegClass(IdReg, DstClass);361return {IdReg, GetIdOp};362}363364// Insert ASSIGN_TYPE instuction between Reg and its definition, set NewReg as365// a dst of the definition, assign SPIRVType to both registers. If SpirvTy is366// provided, use it as SPIRVType in ASSIGN_TYPE, otherwise create it from Ty.367// It's used also in SPIRVBuiltins.cpp.368// TODO: maybe move to SPIRVUtils.369namespace llvm {370Register insertAssignInstr(Register Reg, Type *Ty, SPIRVType *SpirvTy,371SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB,372MachineRegisterInfo &MRI) {373MachineInstr *Def = MRI.getVRegDef(Reg);374assert((Ty || SpirvTy) && "Either LLVM or SPIRV type is expected.");375MIB.setInsertPt(*Def->getParent(),376(Def->getNextNode() ? Def->getNextNode()->getIterator()377: Def->getParent()->end()));378SpirvTy = SpirvTy ? SpirvTy : GR->getOrCreateSPIRVType(Ty, MIB);379Register NewReg = MRI.createGenericVirtualRegister(MRI.getType(Reg));380if (auto *RC = MRI.getRegClassOrNull(Reg)) {381MRI.setRegClass(NewReg, RC);382} else {383MRI.setRegClass(NewReg, &SPIRV::IDRegClass);384MRI.setRegClass(Reg, &SPIRV::IDRegClass);385}386GR->assignSPIRVTypeToVReg(SpirvTy, Reg, MIB.getMF());387// This is to make it convenient for Legalizer to get the SPIRVType388// when processing the actual MI (i.e. not pseudo one).389GR->assignSPIRVTypeToVReg(SpirvTy, NewReg, MIB.getMF());390// Copy MIFlags from Def to ASSIGN_TYPE instruction. It's required to keep391// the flags after instruction selection.392const uint32_t Flags = Def->getFlags();393MIB.buildInstr(SPIRV::ASSIGN_TYPE)394.addDef(Reg)395.addUse(NewReg)396.addUse(GR->getSPIRVTypeID(SpirvTy))397.setMIFlags(Flags);398Def->getOperand(0).setReg(NewReg);399return NewReg;400}401402void processInstr(MachineInstr &MI, MachineIRBuilder &MIB,403MachineRegisterInfo &MRI, SPIRVGlobalRegistry *GR) {404assert(MI.getNumDefs() > 0 && MRI.hasOneUse(MI.getOperand(0).getReg()));405MachineInstr &AssignTypeInst =406*(MRI.use_instr_begin(MI.getOperand(0).getReg()));407auto NewReg =408createNewIdReg(nullptr, MI.getOperand(0).getReg(), MRI, *GR).first;409AssignTypeInst.getOperand(1).setReg(NewReg);410MI.getOperand(0).setReg(NewReg);411MIB.setInsertPt(*MI.getParent(),412(MI.getNextNode() ? MI.getNextNode()->getIterator()413: MI.getParent()->end()));414for (auto &Op : MI.operands()) {415if (!Op.isReg() || Op.isDef())416continue;417auto IdOpInfo = createNewIdReg(nullptr, Op.getReg(), MRI, *GR);418MIB.buildInstr(IdOpInfo.second).addDef(IdOpInfo.first).addUse(Op.getReg());419Op.setReg(IdOpInfo.first);420}421}422} // namespace llvm423424static void425generateAssignInstrs(MachineFunction &MF, SPIRVGlobalRegistry *GR,426MachineIRBuilder MIB,427DenseMap<MachineInstr *, Type *> &TargetExtConstTypes) {428// Get access to information about available extensions429const SPIRVSubtarget *ST =430static_cast<const SPIRVSubtarget *>(&MIB.getMF().getSubtarget());431432MachineRegisterInfo &MRI = MF.getRegInfo();433SmallVector<MachineInstr *, 10> ToErase;434DenseMap<MachineInstr *, Register> RegsAlreadyAddedToDT;435436for (MachineBasicBlock *MBB : post_order(&MF)) {437if (MBB->empty())438continue;439440bool ReachedBegin = false;441for (auto MII = std::prev(MBB->end()), Begin = MBB->begin();442!ReachedBegin;) {443MachineInstr &MI = *MII;444unsigned MIOp = MI.getOpcode();445446// validate bit width of scalar registers447for (const auto &MOP : MI.operands())448if (MOP.isReg())449widenScalarLLTNextPow2(MOP.getReg(), MRI);450451if (isSpvIntrinsic(MI, Intrinsic::spv_assign_ptr_type)) {452Register Reg = MI.getOperand(1).getReg();453MIB.setInsertPt(*MI.getParent(), MI.getIterator());454Type *ElementTy = getMDOperandAsType(MI.getOperand(2).getMetadata(), 0);455SPIRVType *BaseTy = GR->getOrCreateSPIRVType(ElementTy, MIB);456SPIRVType *AssignedPtrType = GR->getOrCreateSPIRVPointerType(457BaseTy, MI, *MF.getSubtarget<SPIRVSubtarget>().getInstrInfo(),458addressSpaceToStorageClass(MI.getOperand(3).getImm(), *ST));459MachineInstr *Def = MRI.getVRegDef(Reg);460assert(Def && "Expecting an instruction that defines the register");461// G_GLOBAL_VALUE already has type info.462if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE &&463Def->getOpcode() != SPIRV::ASSIGN_TYPE)464insertAssignInstr(Reg, nullptr, AssignedPtrType, GR, MIB,465MF.getRegInfo());466ToErase.push_back(&MI);467} else if (isSpvIntrinsic(MI, Intrinsic::spv_assign_type)) {468Register Reg = MI.getOperand(1).getReg();469Type *Ty = getMDOperandAsType(MI.getOperand(2).getMetadata(), 0);470MachineInstr *Def = MRI.getVRegDef(Reg);471assert(Def && "Expecting an instruction that defines the register");472// G_GLOBAL_VALUE already has type info.473if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE &&474Def->getOpcode() != SPIRV::ASSIGN_TYPE)475insertAssignInstr(Reg, Ty, nullptr, GR, MIB, MF.getRegInfo());476ToErase.push_back(&MI);477} else if (MIOp == TargetOpcode::G_CONSTANT ||478MIOp == TargetOpcode::G_FCONSTANT ||479MIOp == TargetOpcode::G_BUILD_VECTOR) {480// %rc = G_CONSTANT ty Val481// ===>482// %cty = OpType* ty483// %rctmp = G_CONSTANT ty Val484// %rc = ASSIGN_TYPE %rctmp, %cty485Register Reg = MI.getOperand(0).getReg();486bool NeedAssignType = true;487if (MRI.hasOneUse(Reg)) {488MachineInstr &UseMI = *MRI.use_instr_begin(Reg);489if (isSpvIntrinsic(UseMI, Intrinsic::spv_assign_type) ||490isSpvIntrinsic(UseMI, Intrinsic::spv_assign_name))491continue;492}493Type *Ty = nullptr;494if (MIOp == TargetOpcode::G_CONSTANT) {495auto TargetExtIt = TargetExtConstTypes.find(&MI);496Ty = TargetExtIt == TargetExtConstTypes.end()497? MI.getOperand(1).getCImm()->getType()498: TargetExtIt->second;499const ConstantInt *OpCI = MI.getOperand(1).getCImm();500Register PrimaryReg = GR->find(OpCI, &MF);501if (!PrimaryReg.isValid()) {502GR->add(OpCI, &MF, Reg);503} else if (PrimaryReg != Reg &&504MRI.getType(Reg) == MRI.getType(PrimaryReg)) {505auto *RCReg = MRI.getRegClassOrNull(Reg);506auto *RCPrimary = MRI.getRegClassOrNull(PrimaryReg);507if (!RCReg || RCPrimary == RCReg) {508RegsAlreadyAddedToDT[&MI] = PrimaryReg;509ToErase.push_back(&MI);510NeedAssignType = false;511}512}513} else if (MIOp == TargetOpcode::G_FCONSTANT) {514Ty = MI.getOperand(1).getFPImm()->getType();515} else {516assert(MIOp == TargetOpcode::G_BUILD_VECTOR);517Type *ElemTy = nullptr;518MachineInstr *ElemMI = MRI.getVRegDef(MI.getOperand(1).getReg());519assert(ElemMI);520521if (ElemMI->getOpcode() == TargetOpcode::G_CONSTANT)522ElemTy = ElemMI->getOperand(1).getCImm()->getType();523else if (ElemMI->getOpcode() == TargetOpcode::G_FCONSTANT)524ElemTy = ElemMI->getOperand(1).getFPImm()->getType();525else526llvm_unreachable("Unexpected opcode");527unsigned NumElts =528MI.getNumExplicitOperands() - MI.getNumExplicitDefs();529Ty = VectorType::get(ElemTy, NumElts, false);530}531if (NeedAssignType)532insertAssignInstr(Reg, Ty, nullptr, GR, MIB, MRI);533} else if (MIOp == TargetOpcode::G_GLOBAL_VALUE) {534propagateSPIRVType(&MI, GR, MRI, MIB);535}536537if (MII == Begin)538ReachedBegin = true;539else540--MII;541}542}543for (MachineInstr *MI : ToErase) {544auto It = RegsAlreadyAddedToDT.find(MI);545if (RegsAlreadyAddedToDT.contains(MI))546MRI.replaceRegWith(MI->getOperand(0).getReg(), It->second);547MI->eraseFromParent();548}549550// Address the case when IRTranslator introduces instructions with new551// registers without SPIRVType associated.552for (MachineBasicBlock &MBB : MF) {553for (MachineInstr &MI : MBB) {554switch (MI.getOpcode()) {555case TargetOpcode::G_TRUNC:556case TargetOpcode::G_ANYEXT:557case TargetOpcode::G_SEXT:558case TargetOpcode::G_ZEXT:559case TargetOpcode::G_PTRTOINT:560case TargetOpcode::COPY:561case TargetOpcode::G_ADDRSPACE_CAST:562propagateSPIRVType(&MI, GR, MRI, MIB);563break;564}565}566}567}568569// Defined in SPIRVLegalizerInfo.cpp.570extern bool isTypeFoldingSupported(unsigned Opcode);571572static void processInstrsWithTypeFolding(MachineFunction &MF,573SPIRVGlobalRegistry *GR,574MachineIRBuilder MIB) {575MachineRegisterInfo &MRI = MF.getRegInfo();576for (MachineBasicBlock &MBB : MF) {577for (MachineInstr &MI : MBB) {578if (isTypeFoldingSupported(MI.getOpcode()))579processInstr(MI, MIB, MRI, GR);580}581}582583for (MachineBasicBlock &MBB : MF) {584for (MachineInstr &MI : MBB) {585// We need to rewrite dst types for ASSIGN_TYPE instrs to be able586// to perform tblgen'erated selection and we can't do that on Legalizer587// as it operates on gMIR only.588if (MI.getOpcode() != SPIRV::ASSIGN_TYPE)589continue;590Register SrcReg = MI.getOperand(1).getReg();591unsigned Opcode = MRI.getVRegDef(SrcReg)->getOpcode();592if (!isTypeFoldingSupported(Opcode))593continue;594Register DstReg = MI.getOperand(0).getReg();595bool IsDstPtr = MRI.getType(DstReg).isPointer();596bool isDstVec = MRI.getType(DstReg).isVector();597if (IsDstPtr || isDstVec)598MRI.setRegClass(DstReg, &SPIRV::IDRegClass);599// Don't need to reset type of register holding constant and used in600// G_ADDRSPACE_CAST, since it breaks legalizer.601if (Opcode == TargetOpcode::G_CONSTANT && MRI.hasOneUse(DstReg)) {602MachineInstr &UseMI = *MRI.use_instr_begin(DstReg);603if (UseMI.getOpcode() == TargetOpcode::G_ADDRSPACE_CAST)604continue;605}606MRI.setType(DstReg, IsDstPtr ? LLT::pointer(0, GR->getPointerSize())607: LLT::scalar(32));608}609}610}611612static void613insertInlineAsmProcess(MachineFunction &MF, SPIRVGlobalRegistry *GR,614const SPIRVSubtarget &ST, MachineIRBuilder MIRBuilder,615const SmallVector<MachineInstr *> &ToProcess) {616MachineRegisterInfo &MRI = MF.getRegInfo();617Register AsmTargetReg;618for (unsigned i = 0, Sz = ToProcess.size(); i + 1 < Sz; i += 2) {619MachineInstr *I1 = ToProcess[i], *I2 = ToProcess[i + 1];620assert(isSpvIntrinsic(*I1, Intrinsic::spv_inline_asm) && I2->isInlineAsm());621MIRBuilder.setInsertPt(*I1->getParent(), *I1);622623if (!AsmTargetReg.isValid()) {624// define vendor specific assembly target or dialect625AsmTargetReg = MRI.createGenericVirtualRegister(LLT::scalar(32));626MRI.setRegClass(AsmTargetReg, &SPIRV::IDRegClass);627auto AsmTargetMIB =628MIRBuilder.buildInstr(SPIRV::OpAsmTargetINTEL).addDef(AsmTargetReg);629addStringImm(ST.getTargetTripleAsStr(), AsmTargetMIB);630GR->add(AsmTargetMIB.getInstr(), &MF, AsmTargetReg);631}632633// create types634const MDNode *IAMD = I1->getOperand(1).getMetadata();635FunctionType *FTy = cast<FunctionType>(getMDOperandAsType(IAMD, 0));636SmallVector<SPIRVType *, 4> ArgTypes;637for (const auto &ArgTy : FTy->params())638ArgTypes.push_back(GR->getOrCreateSPIRVType(ArgTy, MIRBuilder));639SPIRVType *RetType =640GR->getOrCreateSPIRVType(FTy->getReturnType(), MIRBuilder);641SPIRVType *FuncType = GR->getOrCreateOpTypeFunctionWithArgs(642FTy, RetType, ArgTypes, MIRBuilder);643644// define vendor specific assembly instructions string645Register AsmReg = MRI.createGenericVirtualRegister(LLT::scalar(32));646MRI.setRegClass(AsmReg, &SPIRV::IDRegClass);647auto AsmMIB = MIRBuilder.buildInstr(SPIRV::OpAsmINTEL)648.addDef(AsmReg)649.addUse(GR->getSPIRVTypeID(RetType))650.addUse(GR->getSPIRVTypeID(FuncType))651.addUse(AsmTargetReg);652// inline asm string:653addStringImm(I2->getOperand(InlineAsm::MIOp_AsmString).getSymbolName(),654AsmMIB);655// inline asm constraint string:656addStringImm(cast<MDString>(I1->getOperand(2).getMetadata()->getOperand(0))657->getString(),658AsmMIB);659GR->add(AsmMIB.getInstr(), &MF, AsmReg);660661// calls the inline assembly instruction662unsigned ExtraInfo = I2->getOperand(InlineAsm::MIOp_ExtraInfo).getImm();663if (ExtraInfo & InlineAsm::Extra_HasSideEffects)664MIRBuilder.buildInstr(SPIRV::OpDecorate)665.addUse(AsmReg)666.addImm(static_cast<uint32_t>(SPIRV::Decoration::SideEffectsINTEL));667Register DefReg;668SmallVector<unsigned, 4> Ops;669unsigned StartOp = InlineAsm::MIOp_FirstOperand,670AsmDescOp = InlineAsm::MIOp_FirstOperand;671unsigned I2Sz = I2->getNumOperands();672for (unsigned Idx = StartOp; Idx != I2Sz; ++Idx) {673const MachineOperand &MO = I2->getOperand(Idx);674if (MO.isMetadata())675continue;676if (Idx == AsmDescOp && MO.isImm()) {677// compute the index of the next operand descriptor678const InlineAsm::Flag F(MO.getImm());679AsmDescOp += 1 + F.getNumOperandRegisters();680} else {681if (MO.isReg() && MO.isDef())682DefReg = MO.getReg();683else684Ops.push_back(Idx);685}686}687if (!DefReg.isValid()) {688DefReg = MRI.createGenericVirtualRegister(LLT::scalar(32));689MRI.setRegClass(DefReg, &SPIRV::IDRegClass);690SPIRVType *VoidType = GR->getOrCreateSPIRVType(691Type::getVoidTy(MF.getFunction().getContext()), MIRBuilder);692GR->assignSPIRVTypeToVReg(VoidType, DefReg, MF);693}694auto AsmCall = MIRBuilder.buildInstr(SPIRV::OpAsmCallINTEL)695.addDef(DefReg)696.addUse(GR->getSPIRVTypeID(RetType))697.addUse(AsmReg);698unsigned IntrIdx = 2;699for (unsigned Idx : Ops) {700++IntrIdx;701const MachineOperand &MO = I2->getOperand(Idx);702if (MO.isReg())703AsmCall.addUse(MO.getReg());704else705AsmCall.addUse(I1->getOperand(IntrIdx).getReg());706}707}708for (MachineInstr *MI : ToProcess)709MI->eraseFromParent();710}711712static void insertInlineAsm(MachineFunction &MF, SPIRVGlobalRegistry *GR,713const SPIRVSubtarget &ST,714MachineIRBuilder MIRBuilder) {715SmallVector<MachineInstr *> ToProcess;716for (MachineBasicBlock &MBB : MF) {717for (MachineInstr &MI : MBB) {718if (isSpvIntrinsic(MI, Intrinsic::spv_inline_asm) ||719MI.getOpcode() == TargetOpcode::INLINEASM)720ToProcess.push_back(&MI);721}722}723if (ToProcess.size() == 0)724return;725726if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_inline_assembly))727report_fatal_error("Inline assembly instructions require the "728"following SPIR-V extension: SPV_INTEL_inline_assembly",729false);730731insertInlineAsmProcess(MF, GR, ST, MIRBuilder, ToProcess);732}733734static void insertSpirvDecorations(MachineFunction &MF, MachineIRBuilder MIB) {735SmallVector<MachineInstr *, 10> ToErase;736for (MachineBasicBlock &MBB : MF) {737for (MachineInstr &MI : MBB) {738if (!isSpvIntrinsic(MI, Intrinsic::spv_assign_decoration))739continue;740MIB.setInsertPt(*MI.getParent(), MI);741buildOpSpirvDecorations(MI.getOperand(1).getReg(), MIB,742MI.getOperand(2).getMetadata());743ToErase.push_back(&MI);744}745}746for (MachineInstr *MI : ToErase)747MI->eraseFromParent();748}749750// Find basic blocks of the switch and replace registers in spv_switch() by its751// MBB equivalent.752static void processSwitches(MachineFunction &MF, SPIRVGlobalRegistry *GR,753MachineIRBuilder MIB) {754DenseMap<const BasicBlock *, MachineBasicBlock *> BB2MBB;755SmallVector<std::pair<MachineInstr *, SmallVector<MachineInstr *, 8>>>756Switches;757for (MachineBasicBlock &MBB : MF) {758MachineRegisterInfo &MRI = MF.getRegInfo();759BB2MBB[MBB.getBasicBlock()] = &MBB;760for (MachineInstr &MI : MBB) {761if (!isSpvIntrinsic(MI, Intrinsic::spv_switch))762continue;763// Calls to spv_switch intrinsics representing IR switches.764SmallVector<MachineInstr *, 8> NewOps;765for (unsigned i = 2; i < MI.getNumOperands(); ++i) {766Register Reg = MI.getOperand(i).getReg();767if (i % 2 == 1) {768MachineInstr *ConstInstr = getDefInstrMaybeConstant(Reg, &MRI);769NewOps.push_back(ConstInstr);770} else {771MachineInstr *BuildMBB = MRI.getVRegDef(Reg);772assert(BuildMBB &&773BuildMBB->getOpcode() == TargetOpcode::G_BLOCK_ADDR &&774BuildMBB->getOperand(1).isBlockAddress() &&775BuildMBB->getOperand(1).getBlockAddress());776NewOps.push_back(BuildMBB);777}778}779Switches.push_back(std::make_pair(&MI, NewOps));780}781}782783SmallPtrSet<MachineInstr *, 8> ToEraseMI;784for (auto &SwIt : Switches) {785MachineInstr &MI = *SwIt.first;786SmallVector<MachineInstr *, 8> &Ins = SwIt.second;787SmallVector<MachineOperand, 8> NewOps;788for (unsigned i = 0; i < Ins.size(); ++i) {789if (Ins[i]->getOpcode() == TargetOpcode::G_BLOCK_ADDR) {790BasicBlock *CaseBB =791Ins[i]->getOperand(1).getBlockAddress()->getBasicBlock();792auto It = BB2MBB.find(CaseBB);793if (It == BB2MBB.end())794report_fatal_error("cannot find a machine basic block by a basic "795"block in a switch statement");796NewOps.push_back(MachineOperand::CreateMBB(It->second));797MI.getParent()->addSuccessor(It->second);798ToEraseMI.insert(Ins[i]);799} else {800NewOps.push_back(801MachineOperand::CreateCImm(Ins[i]->getOperand(1).getCImm()));802}803}804for (unsigned i = MI.getNumOperands() - 1; i > 1; --i)805MI.removeOperand(i);806for (auto &MO : NewOps)807MI.addOperand(MO);808if (MachineInstr *Next = MI.getNextNode()) {809if (isSpvIntrinsic(*Next, Intrinsic::spv_track_constant)) {810ToEraseMI.insert(Next);811Next = MI.getNextNode();812}813if (Next && Next->getOpcode() == TargetOpcode::G_BRINDIRECT)814ToEraseMI.insert(Next);815}816}817818// If we just delete G_BLOCK_ADDR instructions with BlockAddress operands,819// this leaves their BasicBlock counterparts in a "address taken" status. This820// would make AsmPrinter to generate a series of unneeded labels of a "Address821// of block that was removed by CodeGen" kind. Let's first ensure that we822// don't have a dangling BlockAddress constants by zapping the BlockAddress823// nodes, and only after that proceed with erasing G_BLOCK_ADDR instructions.824Constant *Replacement =825ConstantInt::get(Type::getInt32Ty(MF.getFunction().getContext()), 1);826for (MachineInstr *BlockAddrI : ToEraseMI) {827if (BlockAddrI->getOpcode() == TargetOpcode::G_BLOCK_ADDR) {828BlockAddress *BA = const_cast<BlockAddress *>(829BlockAddrI->getOperand(1).getBlockAddress());830BA->replaceAllUsesWith(831ConstantExpr::getIntToPtr(Replacement, BA->getType()));832BA->destroyConstant();833}834BlockAddrI->eraseFromParent();835}836}837838static bool isImplicitFallthrough(MachineBasicBlock &MBB) {839if (MBB.empty())840return true;841842// Branching SPIR-V intrinsics are not detected by this generic method.843// Thus, we can only trust negative result.844if (!MBB.canFallThrough())845return false;846847// Otherwise, we must manually check if we have a SPIR-V intrinsic which848// prevent an implicit fallthrough.849for (MachineBasicBlock::reverse_iterator It = MBB.rbegin(), E = MBB.rend();850It != E; ++It) {851if (isSpvIntrinsic(*It, Intrinsic::spv_switch))852return false;853}854return true;855}856857static void removeImplicitFallthroughs(MachineFunction &MF,858MachineIRBuilder MIB) {859// It is valid for MachineBasicBlocks to not finish with a branch instruction.860// In such cases, they will simply fallthrough their immediate successor.861for (MachineBasicBlock &MBB : MF) {862if (!isImplicitFallthrough(MBB))863continue;864865assert(std::distance(MBB.successors().begin(), MBB.successors().end()) ==8661);867MIB.setInsertPt(MBB, MBB.end());868MIB.buildBr(**MBB.successors().begin());869}870}871872bool SPIRVPreLegalizer::runOnMachineFunction(MachineFunction &MF) {873// Initialize the type registry.874const SPIRVSubtarget &ST = MF.getSubtarget<SPIRVSubtarget>();875SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();876GR->setCurrentFunc(MF);877MachineIRBuilder MIB(MF);878// a registry of target extension constants879DenseMap<MachineInstr *, Type *> TargetExtConstTypes;880// to keep record of tracked constants881SmallSet<Register, 4> TrackedConstRegs;882addConstantsToTrack(MF, GR, ST, TargetExtConstTypes, TrackedConstRegs);883foldConstantsIntoIntrinsics(MF, TrackedConstRegs);884insertBitcasts(MF, GR, MIB);885generateAssignInstrs(MF, GR, MIB, TargetExtConstTypes);886processSwitches(MF, GR, MIB);887processInstrsWithTypeFolding(MF, GR, MIB);888removeImplicitFallthroughs(MF, MIB);889insertSpirvDecorations(MF, MIB);890insertInlineAsm(MF, GR, ST, MIB);891892return true;893}894895INITIALIZE_PASS(SPIRVPreLegalizer, DEBUG_TYPE, "SPIRV pre legalizer", false,896false)897898char SPIRVPreLegalizer::ID = 0;899900FunctionPass *llvm::createSPIRVPreLegalizerPass() {901return new SPIRVPreLegalizer();902}903904905