1540d2551SVyacheslav Levytskyy //===-- SPIRVPostLegalizer.cpp - ammend info after legalization -*- C++ -*-===// 2540d2551SVyacheslav Levytskyy // 3540d2551SVyacheslav Levytskyy // which may appear after the legalizer pass 4540d2551SVyacheslav Levytskyy // 5540d2551SVyacheslav Levytskyy // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 6540d2551SVyacheslav Levytskyy // See https://llvm.org/LICENSE.txt for license information. 7540d2551SVyacheslav Levytskyy // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 8540d2551SVyacheslav Levytskyy // 9540d2551SVyacheslav Levytskyy //===----------------------------------------------------------------------===// 10540d2551SVyacheslav Levytskyy // 11540d2551SVyacheslav Levytskyy // The pass partially apply pre-legalization logic to new instructions inserted 12540d2551SVyacheslav Levytskyy // as a result of legalization: 13540d2551SVyacheslav Levytskyy // - assigns SPIR-V types to registers for new instructions. 14540d2551SVyacheslav Levytskyy // 15540d2551SVyacheslav Levytskyy //===----------------------------------------------------------------------===// 16540d2551SVyacheslav Levytskyy 17540d2551SVyacheslav Levytskyy #include "SPIRV.h" 18540d2551SVyacheslav Levytskyy #include "SPIRVSubtarget.h" 19540d2551SVyacheslav Levytskyy #include "SPIRVUtils.h" 20540d2551SVyacheslav Levytskyy #include "llvm/ADT/PostOrderIterator.h" 21540d2551SVyacheslav Levytskyy #include "llvm/Analysis/OptimizationRemarkEmitter.h" 220c07e7c2SNathan Gauër #include "llvm/CodeGen/MachinePostDominators.h" 23540d2551SVyacheslav Levytskyy #include "llvm/IR/Attributes.h" 24540d2551SVyacheslav Levytskyy #include "llvm/IR/Constants.h" 25540d2551SVyacheslav Levytskyy #include "llvm/IR/DebugInfoMetadata.h" 26540d2551SVyacheslav Levytskyy #include "llvm/IR/IntrinsicsSPIRV.h" 27540d2551SVyacheslav Levytskyy #include "llvm/Target/TargetIntrinsicInfo.h" 280c07e7c2SNathan Gauër #include <stack> 29540d2551SVyacheslav Levytskyy 30540d2551SVyacheslav Levytskyy #define DEBUG_TYPE "spirv-postlegalizer" 31540d2551SVyacheslav Levytskyy 32540d2551SVyacheslav Levytskyy using namespace llvm; 33540d2551SVyacheslav Levytskyy 34540d2551SVyacheslav Levytskyy namespace { 35540d2551SVyacheslav Levytskyy class SPIRVPostLegalizer : public MachineFunctionPass { 36540d2551SVyacheslav Levytskyy public: 37540d2551SVyacheslav Levytskyy static char ID; 38540d2551SVyacheslav Levytskyy SPIRVPostLegalizer() : MachineFunctionPass(ID) { 39540d2551SVyacheslav Levytskyy initializeSPIRVPostLegalizerPass(*PassRegistry::getPassRegistry()); 40540d2551SVyacheslav Levytskyy } 41540d2551SVyacheslav Levytskyy bool runOnMachineFunction(MachineFunction &MF) override; 42540d2551SVyacheslav Levytskyy }; 43540d2551SVyacheslav Levytskyy } // namespace 44540d2551SVyacheslav Levytskyy 45540d2551SVyacheslav Levytskyy // Defined in SPIRVLegalizerInfo.cpp. 46540d2551SVyacheslav Levytskyy extern bool isTypeFoldingSupported(unsigned Opcode); 47540d2551SVyacheslav Levytskyy 48540d2551SVyacheslav Levytskyy namespace llvm { 49540d2551SVyacheslav Levytskyy // Defined in SPIRVPreLegalizer.cpp. 50540d2551SVyacheslav Levytskyy extern Register insertAssignInstr(Register Reg, Type *Ty, SPIRVType *SpirvTy, 51540d2551SVyacheslav Levytskyy SPIRVGlobalRegistry *GR, 52540d2551SVyacheslav Levytskyy MachineIRBuilder &MIB, 53540d2551SVyacheslav Levytskyy MachineRegisterInfo &MRI); 54540d2551SVyacheslav Levytskyy extern void processInstr(MachineInstr &MI, MachineIRBuilder &MIB, 55540d2551SVyacheslav Levytskyy MachineRegisterInfo &MRI, SPIRVGlobalRegistry *GR); 56540d2551SVyacheslav Levytskyy } // namespace llvm 57540d2551SVyacheslav Levytskyy 58540d2551SVyacheslav Levytskyy static bool mayBeInserted(unsigned Opcode) { 59540d2551SVyacheslav Levytskyy switch (Opcode) { 60540d2551SVyacheslav Levytskyy case TargetOpcode::G_SMAX: 61540d2551SVyacheslav Levytskyy case TargetOpcode::G_UMAX: 62540d2551SVyacheslav Levytskyy case TargetOpcode::G_SMIN: 63540d2551SVyacheslav Levytskyy case TargetOpcode::G_UMIN: 64540d2551SVyacheslav Levytskyy case TargetOpcode::G_FMINNUM: 65540d2551SVyacheslav Levytskyy case TargetOpcode::G_FMINIMUM: 66540d2551SVyacheslav Levytskyy case TargetOpcode::G_FMAXNUM: 67540d2551SVyacheslav Levytskyy case TargetOpcode::G_FMAXIMUM: 68540d2551SVyacheslav Levytskyy return true; 69540d2551SVyacheslav Levytskyy default: 70540d2551SVyacheslav Levytskyy return isTypeFoldingSupported(Opcode); 71540d2551SVyacheslav Levytskyy } 72540d2551SVyacheslav Levytskyy } 73540d2551SVyacheslav Levytskyy 74540d2551SVyacheslav Levytskyy static void processNewInstrs(MachineFunction &MF, SPIRVGlobalRegistry *GR, 75540d2551SVyacheslav Levytskyy MachineIRBuilder MIB) { 76540d2551SVyacheslav Levytskyy MachineRegisterInfo &MRI = MF.getRegInfo(); 77540d2551SVyacheslav Levytskyy 78540d2551SVyacheslav Levytskyy for (MachineBasicBlock &MBB : MF) { 79540d2551SVyacheslav Levytskyy for (MachineInstr &I : MBB) { 80540d2551SVyacheslav Levytskyy const unsigned Opcode = I.getOpcode(); 81540d2551SVyacheslav Levytskyy if (Opcode == TargetOpcode::G_UNMERGE_VALUES) { 82540d2551SVyacheslav Levytskyy unsigned ArgI = I.getNumOperands() - 1; 83540d2551SVyacheslav Levytskyy Register SrcReg = I.getOperand(ArgI).isReg() 84540d2551SVyacheslav Levytskyy ? I.getOperand(ArgI).getReg() 85540d2551SVyacheslav Levytskyy : Register(0); 86540d2551SVyacheslav Levytskyy SPIRVType *DefType = 87540d2551SVyacheslav Levytskyy SrcReg.isValid() ? GR->getSPIRVTypeForVReg(SrcReg) : nullptr; 88540d2551SVyacheslav Levytskyy if (!DefType || DefType->getOpcode() != SPIRV::OpTypeVector) 89540d2551SVyacheslav Levytskyy report_fatal_error( 90540d2551SVyacheslav Levytskyy "cannot select G_UNMERGE_VALUES with a non-vector argument"); 91540d2551SVyacheslav Levytskyy SPIRVType *ScalarType = 92540d2551SVyacheslav Levytskyy GR->getSPIRVTypeForVReg(DefType->getOperand(1).getReg()); 93540d2551SVyacheslav Levytskyy for (unsigned i = 0; i < I.getNumDefs(); ++i) { 94540d2551SVyacheslav Levytskyy Register ResVReg = I.getOperand(i).getReg(); 95540d2551SVyacheslav Levytskyy SPIRVType *ResType = GR->getSPIRVTypeForVReg(ResVReg); 96540d2551SVyacheslav Levytskyy if (!ResType) { 97540d2551SVyacheslav Levytskyy // There was no "assign type" actions, let's fix this now 98540d2551SVyacheslav Levytskyy ResType = ScalarType; 99b5132b7dSVyacheslav Levytskyy setRegClassType(ResVReg, ResType, GR, &MRI, *GR->CurMF, true); 100540d2551SVyacheslav Levytskyy } 101540d2551SVyacheslav Levytskyy } 102540d2551SVyacheslav Levytskyy } else if (mayBeInserted(Opcode) && I.getNumDefs() == 1 && 103540d2551SVyacheslav Levytskyy I.getNumOperands() > 1 && I.getOperand(1).isReg()) { 104540d2551SVyacheslav Levytskyy // Legalizer may have added a new instructions and introduced new 105540d2551SVyacheslav Levytskyy // registers, we must decorate them as if they were introduced in a 106540d2551SVyacheslav Levytskyy // non-automatic way 107540d2551SVyacheslav Levytskyy Register ResVReg = I.getOperand(0).getReg(); 108540d2551SVyacheslav Levytskyy // Check if the register defined by the instruction is newly generated 109540d2551SVyacheslav Levytskyy // or already processed 110*978de2d6SVyacheslav Levytskyy if (MRI.getRegClassOrNull(ResVReg)) 111*978de2d6SVyacheslav Levytskyy continue; 112*978de2d6SVyacheslav Levytskyy assert(GR->getSPIRVTypeForVReg(ResVReg) == nullptr); 113540d2551SVyacheslav Levytskyy // Check if we have type defined for operands of the new instruction 114*978de2d6SVyacheslav Levytskyy SPIRVType *ResVType = GR->getSPIRVTypeForVReg(I.getOperand(1).getReg()); 115540d2551SVyacheslav Levytskyy if (!ResVType) 116540d2551SVyacheslav Levytskyy continue; 117540d2551SVyacheslav Levytskyy // Set type & class 118b5132b7dSVyacheslav Levytskyy setRegClassType(ResVReg, ResVType, GR, &MRI, *GR->CurMF, true); 119540d2551SVyacheslav Levytskyy // If this is a simple operation that is to be reduced by TableGen 120540d2551SVyacheslav Levytskyy // definition we must apply some of pre-legalizer rules here 121540d2551SVyacheslav Levytskyy if (isTypeFoldingSupported(Opcode)) { 122540d2551SVyacheslav Levytskyy insertAssignInstr(ResVReg, nullptr, ResVType, GR, MIB, MRI); 123540d2551SVyacheslav Levytskyy processInstr(I, MIB, MRI, GR); 124540d2551SVyacheslav Levytskyy } 125540d2551SVyacheslav Levytskyy } 126540d2551SVyacheslav Levytskyy } 127540d2551SVyacheslav Levytskyy } 128540d2551SVyacheslav Levytskyy } 129540d2551SVyacheslav Levytskyy 1300c07e7c2SNathan Gauër // Do a preorder traversal of the CFG starting from the BB |Start|. 1310c07e7c2SNathan Gauër // point. Calls |op| on each basic block encountered during the traversal. 1320c07e7c2SNathan Gauër void visit(MachineFunction &MF, MachineBasicBlock &Start, 1330c07e7c2SNathan Gauër std::function<void(MachineBasicBlock *)> op) { 1340c07e7c2SNathan Gauër std::stack<MachineBasicBlock *> ToVisit; 1350c07e7c2SNathan Gauër SmallPtrSet<MachineBasicBlock *, 8> Seen; 1360c07e7c2SNathan Gauër 1370c07e7c2SNathan Gauër ToVisit.push(&Start); 1380c07e7c2SNathan Gauër Seen.insert(ToVisit.top()); 1390c07e7c2SNathan Gauër while (ToVisit.size() != 0) { 1400c07e7c2SNathan Gauër MachineBasicBlock *MBB = ToVisit.top(); 1410c07e7c2SNathan Gauër ToVisit.pop(); 1420c07e7c2SNathan Gauër 1430c07e7c2SNathan Gauër op(MBB); 1440c07e7c2SNathan Gauër 1450c07e7c2SNathan Gauër for (auto Succ : MBB->successors()) { 1460c07e7c2SNathan Gauër if (Seen.contains(Succ)) 1470c07e7c2SNathan Gauër continue; 1480c07e7c2SNathan Gauër ToVisit.push(Succ); 1490c07e7c2SNathan Gauër Seen.insert(Succ); 1500c07e7c2SNathan Gauër } 1510c07e7c2SNathan Gauër } 1520c07e7c2SNathan Gauër } 1530c07e7c2SNathan Gauër 1540c07e7c2SNathan Gauër // Do a preorder traversal of the CFG starting from the given function's entry 1550c07e7c2SNathan Gauër // point. Calls |op| on each basic block encountered during the traversal. 1560c07e7c2SNathan Gauër void visit(MachineFunction &MF, std::function<void(MachineBasicBlock *)> op) { 1570c07e7c2SNathan Gauër visit(MF, *MF.begin(), op); 1580c07e7c2SNathan Gauër } 1590c07e7c2SNathan Gauër 160540d2551SVyacheslav Levytskyy bool SPIRVPostLegalizer::runOnMachineFunction(MachineFunction &MF) { 161540d2551SVyacheslav Levytskyy // Initialize the type registry. 162540d2551SVyacheslav Levytskyy const SPIRVSubtarget &ST = MF.getSubtarget<SPIRVSubtarget>(); 163540d2551SVyacheslav Levytskyy SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry(); 164540d2551SVyacheslav Levytskyy GR->setCurrentFunc(MF); 165540d2551SVyacheslav Levytskyy MachineIRBuilder MIB(MF); 166540d2551SVyacheslav Levytskyy 167540d2551SVyacheslav Levytskyy processNewInstrs(MF, GR, MIB); 168540d2551SVyacheslav Levytskyy 169540d2551SVyacheslav Levytskyy return true; 170540d2551SVyacheslav Levytskyy } 171540d2551SVyacheslav Levytskyy 172540d2551SVyacheslav Levytskyy INITIALIZE_PASS(SPIRVPostLegalizer, DEBUG_TYPE, "SPIRV post legalizer", false, 173540d2551SVyacheslav Levytskyy false) 174540d2551SVyacheslav Levytskyy 175540d2551SVyacheslav Levytskyy char SPIRVPostLegalizer::ID = 0; 176540d2551SVyacheslav Levytskyy 177540d2551SVyacheslav Levytskyy FunctionPass *llvm::createSPIRVPostLegalizerPass() { 178540d2551SVyacheslav Levytskyy return new SPIRVPostLegalizer(); 179540d2551SVyacheslav Levytskyy } 180