LLVM 20.0.0git
SPIRVPostLegalizer.cpp
Go to the documentation of this file.
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"
23#include "llvm/IR/Attributes.h"
24#include "llvm/IR/Constants.h"
26#include "llvm/IR/IntrinsicsSPIRV.h"
28#include <stack>
29
30#define DEBUG_TYPE "spirv-postlegalizer"
31
32using namespace llvm;
33
34namespace {
35class SPIRVPostLegalizer : public MachineFunctionPass {
36public:
37 static char ID;
38 SPIRVPostLegalizer() : MachineFunctionPass(ID) {
40 }
41 bool runOnMachineFunction(MachineFunction &MF) override;
42};
43} // namespace
44
45// Defined in SPIRVLegalizerInfo.cpp.
46extern bool isTypeFoldingSupported(unsigned Opcode);
47
48namespace llvm {
49// Defined in SPIRVPreLegalizer.cpp.
50extern Register insertAssignInstr(Register Reg, Type *Ty, SPIRVType *SpirvTy,
56} // namespace llvm
57
58static bool isMetaInstrGET(unsigned Opcode) {
59 return Opcode == SPIRV::GET_ID || Opcode == SPIRV::GET_ID64 ||
60 Opcode == SPIRV::GET_fID || Opcode == SPIRV::GET_fID64 ||
61 Opcode == SPIRV::GET_pID32 || Opcode == SPIRV::GET_pID64 ||
62 Opcode == SPIRV::GET_vID || Opcode == SPIRV::GET_vfID ||
63 Opcode == SPIRV::GET_vpID32 || Opcode == SPIRV::GET_vpID64;
64}
65
66static bool mayBeInserted(unsigned Opcode) {
67 switch (Opcode) {
68 case TargetOpcode::G_SMAX:
69 case TargetOpcode::G_UMAX:
70 case TargetOpcode::G_SMIN:
71 case TargetOpcode::G_UMIN:
72 case TargetOpcode::G_FMINNUM:
73 case TargetOpcode::G_FMINIMUM:
74 case TargetOpcode::G_FMAXNUM:
75 case TargetOpcode::G_FMAXIMUM:
76 return true;
77 default:
78 return isTypeFoldingSupported(Opcode);
79 }
80}
81
83 MachineIRBuilder MIB) {
85
86 for (MachineBasicBlock &MBB : MF) {
87 for (MachineInstr &I : MBB) {
88 const unsigned Opcode = I.getOpcode();
89 if (Opcode == TargetOpcode::G_UNMERGE_VALUES) {
90 unsigned ArgI = I.getNumOperands() - 1;
91 Register SrcReg = I.getOperand(ArgI).isReg()
92 ? I.getOperand(ArgI).getReg()
93 : Register(0);
94 SPIRVType *DefType =
95 SrcReg.isValid() ? GR->getSPIRVTypeForVReg(SrcReg) : nullptr;
96 if (!DefType || DefType->getOpcode() != SPIRV::OpTypeVector)
98 "cannot select G_UNMERGE_VALUES with a non-vector argument");
99 SPIRVType *ScalarType =
100 GR->getSPIRVTypeForVReg(DefType->getOperand(1).getReg());
101 for (unsigned i = 0; i < I.getNumDefs(); ++i) {
102 Register ResVReg = I.getOperand(i).getReg();
103 SPIRVType *ResType = GR->getSPIRVTypeForVReg(ResVReg);
104 if (!ResType) {
105 // There was no "assign type" actions, let's fix this now
106 ResType = ScalarType;
107 MRI.setRegClass(ResVReg, &SPIRV::iIDRegClass);
108 MRI.setType(ResVReg,
110 GR->assignSPIRVTypeToVReg(ResType, ResVReg, *GR->CurMF);
111 }
112 }
113 } else if (mayBeInserted(Opcode) && I.getNumDefs() == 1 &&
114 I.getNumOperands() > 1 && I.getOperand(1).isReg()) {
115 // Legalizer may have added a new instructions and introduced new
116 // registers, we must decorate them as if they were introduced in a
117 // non-automatic way
118 Register ResVReg = I.getOperand(0).getReg();
119 SPIRVType *ResVType = GR->getSPIRVTypeForVReg(ResVReg);
120 // Check if the register defined by the instruction is newly generated
121 // or already processed
122 if (!ResVType) {
123 // Set type of the defined register
124 ResVType = GR->getSPIRVTypeForVReg(I.getOperand(1).getReg());
125 // Check if we have type defined for operands of the new instruction
126 if (!ResVType)
127 continue;
128 // Set type & class
129 MRI.setRegClass(ResVReg, &SPIRV::iIDRegClass);
130 MRI.setType(ResVReg,
132 GR->assignSPIRVTypeToVReg(ResVType, ResVReg, *GR->CurMF);
133 }
134 // If this is a simple operation that is to be reduced by TableGen
135 // definition we must apply some of pre-legalizer rules here
136 if (isTypeFoldingSupported(Opcode)) {
137 // Check if the instruction newly generated or already processed
138 MachineInstr *NextMI = I.getNextNode();
139 if (NextMI && isMetaInstrGET(NextMI->getOpcode()))
140 continue;
141 // Restore usual instructions pattern for the newly inserted
142 // instruction
143 MRI.setRegClass(ResVReg, MRI.getType(ResVReg).isVector()
144 ? &SPIRV::iIDRegClass
145 : &SPIRV::ANYIDRegClass);
146 MRI.setType(ResVReg, LLT::scalar(32));
147 insertAssignInstr(ResVReg, nullptr, ResVType, GR, MIB, MRI);
148 processInstr(I, MIB, MRI, GR);
149 }
150 }
151 }
152 }
153}
154
155// Do a preorder traversal of the CFG starting from the BB |Start|.
156// point. Calls |op| on each basic block encountered during the traversal.
158 std::function<void(MachineBasicBlock *)> op) {
159 std::stack<MachineBasicBlock *> ToVisit;
161
162 ToVisit.push(&Start);
163 Seen.insert(ToVisit.top());
164 while (ToVisit.size() != 0) {
165 MachineBasicBlock *MBB = ToVisit.top();
166 ToVisit.pop();
167
168 op(MBB);
169
170 for (auto Succ : MBB->successors()) {
171 if (Seen.contains(Succ))
172 continue;
173 ToVisit.push(Succ);
174 Seen.insert(Succ);
175 }
176 }
177}
178
179// Do a preorder traversal of the CFG starting from the given function's entry
180// point. Calls |op| on each basic block encountered during the traversal.
181void visit(MachineFunction &MF, std::function<void(MachineBasicBlock *)> op) {
182 visit(MF, *MF.begin(), op);
183}
184
185// Sorts basic blocks by dominance to respect the SPIR-V spec.
187 MachineDominatorTree MDT(MF);
188
189 std::unordered_map<MachineBasicBlock *, size_t> Order;
190 Order.reserve(MF.size());
191
192 size_t Index = 0;
193 visit(MF, [&Order, &Index](MachineBasicBlock *MBB) { Order[MBB] = Index++; });
194
195 auto Comparator = [&Order](MachineBasicBlock &LHS, MachineBasicBlock &RHS) {
196 return Order[&LHS] < Order[&RHS];
197 };
198
199 MF.sort(Comparator);
200}
201
202bool SPIRVPostLegalizer::runOnMachineFunction(MachineFunction &MF) {
203 // Initialize the type registry.
205 SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
206 GR->setCurrentFunc(MF);
207 MachineIRBuilder MIB(MF);
208
209 processNewInstrs(MF, GR, MIB);
210 sortBlocks(MF);
211
212 return true;
213}
214
215INITIALIZE_PASS(SPIRVPostLegalizer, DEBUG_TYPE, "SPIRV post legalizer", false,
216 false)
217
218char SPIRVPostLegalizer::ID = 0;
219
221 return new SPIRVPostLegalizer();
222}
unsigned const MachineRegisterInfo * MRI
MachineBasicBlock & MBB
This file contains the simple types necessary to represent the attributes associated with functions a...
This file contains the declarations for the subclasses of Constant, which represent the different fla...
#define op(i)
IRTranslator LLVM IR MI
#define I(x, y, z)
Definition: MD5.cpp:58
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:38
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
void visit(MachineFunction &MF, MachineBasicBlock &Start, std::function< void(MachineBasicBlock *)> op)
bool isTypeFoldingSupported(unsigned Opcode)
static bool isMetaInstrGET(unsigned Opcode)
#define DEBUG_TYPE
static bool mayBeInserted(unsigned Opcode)
static void processNewInstrs(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
void sortBlocks(MachineFunction &MF)
Value * RHS
Value * LHS
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:310
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
Definition: LowLevelType.h:42
iterator_range< succ_iterator > successors()
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
virtual bool runOnMachineFunction(MachineFunction &MF)=0
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
unsigned size() const
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
void sort(Comp comp)
Helper class to build MachineInstr.
Representation of each machine instruction.
Definition: MachineInstr.h:69
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
Definition: MachineInstr.h:569
const MachineOperand & getOperand(unsigned i) const
Definition: MachineInstr.h:579
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
constexpr bool isValid() const
Definition: Register.h:116
SPIRVType * getSPIRVTypeForVReg(Register VReg, const MachineFunction *MF=nullptr) const
void assignSPIRVTypeToVReg(SPIRVType *Type, Register VReg, MachineFunction &MF)
unsigned getScalarOrVectorBitWidth(const SPIRVType *Type) const
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
Definition: SmallPtrSet.h:367
bool contains(ConstPtrType Ptr) const
Definition: SmallPtrSet.h:441
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
Definition: SmallPtrSet.h:502
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
Register insertAssignInstr(Register Reg, Type *Ty, SPIRVType *SpirvTy, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB, MachineRegisterInfo &MRI)
Helper external function for inserting ASSIGN_TYPE instuction between Reg and its definition,...
FunctionPass * createSPIRVPostLegalizerPass()
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:167
void initializeSPIRVPostLegalizerPass(PassRegistry &)
void processInstr(MachineInstr &MI, MachineIRBuilder &MIB, MachineRegisterInfo &MRI, SPIRVGlobalRegistry *GR)