1 //===-- SPIRVPostLegalizer.cpp - ammend info after legalization -*- C++ -*-===//
2 //
3 // which may appear after the legalizer pass
4 //
5 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
6 // See https://llvm.org/LICENSE.txt for license information.
7 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8 //
9 //===----------------------------------------------------------------------===//
10 //
11 // The pass partially apply pre-legalization logic to new instructions inserted
12 // as a result of legalization:
13 // - assigns SPIR-V types to registers for new instructions.
14 //
15 //===----------------------------------------------------------------------===//
16
17 #include "SPIRV.h"
18 #include "SPIRVSubtarget.h"
19 #include "SPIRVUtils.h"
20 #include "llvm/ADT/PostOrderIterator.h"
21 #include "llvm/Analysis/OptimizationRemarkEmitter.h"
22 #include "llvm/IR/Attributes.h"
23 #include "llvm/IR/Constants.h"
24 #include "llvm/IR/DebugInfoMetadata.h"
25 #include "llvm/IR/IntrinsicsSPIRV.h"
26 #include "llvm/Target/TargetIntrinsicInfo.h"
27
28 #define DEBUG_TYPE "spirv-postlegalizer"
29
30 using namespace llvm;
31
32 namespace {
33 class SPIRVPostLegalizer : public MachineFunctionPass {
34 public:
35 static char ID;
SPIRVPostLegalizer()36 SPIRVPostLegalizer() : MachineFunctionPass(ID) {
37 initializeSPIRVPostLegalizerPass(*PassRegistry::getPassRegistry());
38 }
39 bool runOnMachineFunction(MachineFunction &MF) override;
40 };
41 } // namespace
42
43 // Defined in SPIRVLegalizerInfo.cpp.
44 extern bool isTypeFoldingSupported(unsigned Opcode);
45
46 namespace llvm {
47 // Defined in SPIRVPreLegalizer.cpp.
48 extern Register insertAssignInstr(Register Reg, Type *Ty, SPIRVType *SpirvTy,
49 SPIRVGlobalRegistry *GR,
50 MachineIRBuilder &MIB,
51 MachineRegisterInfo &MRI);
52 extern void processInstr(MachineInstr &MI, MachineIRBuilder &MIB,
53 MachineRegisterInfo &MRI, SPIRVGlobalRegistry *GR);
54 } // namespace llvm
55
isMetaInstrGET(unsigned Opcode)56 static bool isMetaInstrGET(unsigned Opcode) {
57 return Opcode == SPIRV::GET_ID || Opcode == SPIRV::GET_ID64 ||
58 Opcode == SPIRV::GET_fID || Opcode == SPIRV::GET_fID64 ||
59 Opcode == SPIRV::GET_pID32 || Opcode == SPIRV::GET_pID64 ||
60 Opcode == SPIRV::GET_vID || Opcode == SPIRV::GET_vfID ||
61 Opcode == SPIRV::GET_vpID32 || Opcode == SPIRV::GET_vpID64;
62 }
63
mayBeInserted(unsigned Opcode)64 static bool mayBeInserted(unsigned Opcode) {
65 switch (Opcode) {
66 case TargetOpcode::G_SMAX:
67 case TargetOpcode::G_UMAX:
68 case TargetOpcode::G_SMIN:
69 case TargetOpcode::G_UMIN:
70 case TargetOpcode::G_FMINNUM:
71 case TargetOpcode::G_FMINIMUM:
72 case TargetOpcode::G_FMAXNUM:
73 case TargetOpcode::G_FMAXIMUM:
74 return true;
75 default:
76 return isTypeFoldingSupported(Opcode);
77 }
78 }
79
processNewInstrs(MachineFunction & MF,SPIRVGlobalRegistry * GR,MachineIRBuilder MIB)80 static void processNewInstrs(MachineFunction &MF, SPIRVGlobalRegistry *GR,
81 MachineIRBuilder MIB) {
82 MachineRegisterInfo &MRI = MF.getRegInfo();
83
84 for (MachineBasicBlock &MBB : MF) {
85 for (MachineInstr &I : MBB) {
86 const unsigned Opcode = I.getOpcode();
87 if (Opcode == TargetOpcode::G_UNMERGE_VALUES) {
88 unsigned ArgI = I.getNumOperands() - 1;
89 Register SrcReg = I.getOperand(ArgI).isReg()
90 ? I.getOperand(ArgI).getReg()
91 : Register(0);
92 SPIRVType *DefType =
93 SrcReg.isValid() ? GR->getSPIRVTypeForVReg(SrcReg) : nullptr;
94 if (!DefType || DefType->getOpcode() != SPIRV::OpTypeVector)
95 report_fatal_error(
96 "cannot select G_UNMERGE_VALUES with a non-vector argument");
97 SPIRVType *ScalarType =
98 GR->getSPIRVTypeForVReg(DefType->getOperand(1).getReg());
99 for (unsigned i = 0; i < I.getNumDefs(); ++i) {
100 Register ResVReg = I.getOperand(i).getReg();
101 SPIRVType *ResType = GR->getSPIRVTypeForVReg(ResVReg);
102 if (!ResType) {
103 // There was no "assign type" actions, let's fix this now
104 ResType = ScalarType;
105 MRI.setRegClass(ResVReg, &SPIRV::IDRegClass);
106 MRI.setType(ResVReg,
107 LLT::scalar(GR->getScalarOrVectorBitWidth(ResType)));
108 GR->assignSPIRVTypeToVReg(ResType, ResVReg, *GR->CurMF);
109 }
110 }
111 } else if (mayBeInserted(Opcode) && I.getNumDefs() == 1 &&
112 I.getNumOperands() > 1 && I.getOperand(1).isReg()) {
113 // Legalizer may have added a new instructions and introduced new
114 // registers, we must decorate them as if they were introduced in a
115 // non-automatic way
116 Register ResVReg = I.getOperand(0).getReg();
117 SPIRVType *ResVType = GR->getSPIRVTypeForVReg(ResVReg);
118 // Check if the register defined by the instruction is newly generated
119 // or already processed
120 if (!ResVType) {
121 // Set type of the defined register
122 ResVType = GR->getSPIRVTypeForVReg(I.getOperand(1).getReg());
123 // Check if we have type defined for operands of the new instruction
124 if (!ResVType)
125 continue;
126 // Set type & class
127 MRI.setRegClass(ResVReg, &SPIRV::IDRegClass);
128 MRI.setType(ResVReg,
129 LLT::scalar(GR->getScalarOrVectorBitWidth(ResVType)));
130 GR->assignSPIRVTypeToVReg(ResVType, ResVReg, *GR->CurMF);
131 }
132 // If this is a simple operation that is to be reduced by TableGen
133 // definition we must apply some of pre-legalizer rules here
134 if (isTypeFoldingSupported(Opcode)) {
135 // Check if the instruction newly generated or already processed
136 MachineInstr *NextMI = I.getNextNode();
137 if (NextMI && isMetaInstrGET(NextMI->getOpcode()))
138 continue;
139 // Restore usual instructions pattern for the newly inserted
140 // instruction
141 MRI.setRegClass(ResVReg, MRI.getType(ResVReg).isVector()
142 ? &SPIRV::IDRegClass
143 : &SPIRV::ANYIDRegClass);
144 MRI.setType(ResVReg, LLT::scalar(32));
145 insertAssignInstr(ResVReg, nullptr, ResVType, GR, MIB, MRI);
146 processInstr(I, MIB, MRI, GR);
147 }
148 }
149 }
150 }
151 }
152
runOnMachineFunction(MachineFunction & MF)153 bool SPIRVPostLegalizer::runOnMachineFunction(MachineFunction &MF) {
154 // Initialize the type registry.
155 const SPIRVSubtarget &ST = MF.getSubtarget<SPIRVSubtarget>();
156 SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
157 GR->setCurrentFunc(MF);
158 MachineIRBuilder MIB(MF);
159
160 processNewInstrs(MF, GR, MIB);
161
162 return true;
163 }
164
165 INITIALIZE_PASS(SPIRVPostLegalizer, DEBUG_TYPE, "SPIRV post legalizer", false,
166 false)
167
168 char SPIRVPostLegalizer::ID = 0;
169
createSPIRVPostLegalizerPass()170 FunctionPass *llvm::createSPIRVPostLegalizerPass() {
171 return new SPIRVPostLegalizer();
172 }
173