LLVM 19.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"
22#include "llvm/IR/Attributes.h"
23#include "llvm/IR/Constants.h"
25#include "llvm/IR/IntrinsicsSPIRV.h"
27
28#define DEBUG_TYPE "spirv-postlegalizer"
29
30using namespace llvm;
31
32namespace {
33class SPIRVPostLegalizer : public MachineFunctionPass {
34public:
35 static char ID;
36 SPIRVPostLegalizer() : MachineFunctionPass(ID) {
38 }
39 bool runOnMachineFunction(MachineFunction &MF) override;
40};
41} // namespace
42
43// Defined in SPIRVLegalizerInfo.cpp.
44extern bool isTypeFoldingSupported(unsigned Opcode);
45
46namespace llvm {
47// Defined in SPIRVPreLegalizer.cpp.
48extern Register insertAssignInstr(Register Reg, Type *Ty, SPIRVType *SpirvTy,
54} // namespace llvm
55
56static bool isMetaInstrGET(unsigned Opcode) {
57 return Opcode == SPIRV::GET_ID || Opcode == SPIRV::GET_fID ||
58 Opcode == SPIRV::GET_pID32 || Opcode == SPIRV::GET_pID64 ||
59 Opcode == SPIRV::GET_vID || Opcode == SPIRV::GET_vfID ||
60 Opcode == SPIRV::GET_vpID32 || Opcode == SPIRV::GET_vpID64;
61}
62
63static bool mayBeInserted(unsigned Opcode) {
64 switch (Opcode) {
65 case TargetOpcode::G_SMAX:
66 case TargetOpcode::G_UMAX:
67 case TargetOpcode::G_SMIN:
68 case TargetOpcode::G_UMIN:
69 case TargetOpcode::G_FMINNUM:
70 case TargetOpcode::G_FMINIMUM:
71 case TargetOpcode::G_FMAXNUM:
72 case TargetOpcode::G_FMAXIMUM:
73 return true;
74 default:
75 return isTypeFoldingSupported(Opcode);
76 }
77}
78
80 MachineIRBuilder MIB) {
82
83 for (MachineBasicBlock &MBB : MF) {
84 for (MachineInstr &I : MBB) {
85 const unsigned Opcode = I.getOpcode();
86 if (Opcode == TargetOpcode::G_UNMERGE_VALUES) {
87 unsigned ArgI = I.getNumOperands() - 1;
88 Register SrcReg = I.getOperand(ArgI).isReg()
89 ? I.getOperand(ArgI).getReg()
90 : Register(0);
91 SPIRVType *DefType =
92 SrcReg.isValid() ? GR->getSPIRVTypeForVReg(SrcReg) : nullptr;
93 if (!DefType || DefType->getOpcode() != SPIRV::OpTypeVector)
95 "cannot select G_UNMERGE_VALUES with a non-vector argument");
96 SPIRVType *ScalarType =
97 GR->getSPIRVTypeForVReg(DefType->getOperand(1).getReg());
98 for (unsigned i = 0; i < I.getNumDefs(); ++i) {
99 Register ResVReg = I.getOperand(i).getReg();
100 SPIRVType *ResType = GR->getSPIRVTypeForVReg(ResVReg);
101 if (!ResType) {
102 // There was no "assign type" actions, let's fix this now
103 ResType = ScalarType;
104 MRI.setRegClass(ResVReg, &SPIRV::IDRegClass);
105 MRI.setType(ResVReg,
107 GR->assignSPIRVTypeToVReg(ResType, ResVReg, *GR->CurMF);
108 }
109 }
110 } else if (mayBeInserted(Opcode) && I.getNumDefs() == 1 &&
111 I.getNumOperands() > 1 && I.getOperand(1).isReg()) {
112 // Legalizer may have added a new instructions and introduced new
113 // registers, we must decorate them as if they were introduced in a
114 // non-automatic way
115 Register ResVReg = I.getOperand(0).getReg();
116 SPIRVType *ResVType = GR->getSPIRVTypeForVReg(ResVReg);
117 // Check if the register defined by the instruction is newly generated
118 // or already processed
119 if (!ResVType) {
120 // Set type of the defined register
121 ResVType = GR->getSPIRVTypeForVReg(I.getOperand(1).getReg());
122 // Check if we have type defined for operands of the new instruction
123 if (!ResVType)
124 continue;
125 // Set type & class
126 MRI.setRegClass(ResVReg, &SPIRV::IDRegClass);
127 MRI.setType(ResVReg,
129 GR->assignSPIRVTypeToVReg(ResVType, ResVReg, *GR->CurMF);
130 }
131 // If this is a simple operation that is to be reduced by TableGen
132 // definition we must apply some of pre-legalizer rules here
133 if (isTypeFoldingSupported(Opcode)) {
134 // Check if the instruction newly generated or already processed
135 MachineInstr *NextMI = I.getNextNode();
136 if (NextMI && isMetaInstrGET(NextMI->getOpcode()))
137 continue;
138 // Restore usual instructions pattern for the newly inserted
139 // instruction
140 MRI.setRegClass(ResVReg, MRI.getType(ResVReg).isVector()
141 ? &SPIRV::IDRegClass
142 : &SPIRV::ANYIDRegClass);
143 MRI.setType(ResVReg, LLT::scalar(32));
144 insertAssignInstr(ResVReg, nullptr, ResVType, GR, MIB, MRI);
145 processInstr(I, MIB, MRI, GR);
146 }
147 }
148 }
149 }
150}
151
152bool SPIRVPostLegalizer::runOnMachineFunction(MachineFunction &MF) {
153 // Initialize the type registry.
155 SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
156 GR->setCurrentFunc(MF);
157 MachineIRBuilder MIB(MF);
158
159 processNewInstrs(MF, GR, MIB);
160
161 return true;
162}
163
164INITIALIZE_PASS(SPIRVPostLegalizer, DEBUG_TYPE, "SPIRV post legalizer", false,
165 false)
166
167char SPIRVPostLegalizer::ID = 0;
168
170 return new SPIRVPostLegalizer();
171}
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...
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.
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)
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:311
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
Definition: LowLevelType.h:42
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.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
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:558
const MachineOperand & getOperand(unsigned i) const
Definition: MachineInstr.h:568
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
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:156
void initializeSPIRVPostLegalizerPass(PassRegistry &)
void processInstr(MachineInstr &MI, MachineIRBuilder &MIB, MachineRegisterInfo &MRI, SPIRVGlobalRegistry *GR)