LLVM 22.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"
20#include "llvm/IR/Attributes.h"
21#include <stack>
22
23#define DEBUG_TYPE "spirv-postlegalizer"
24
25using namespace llvm;
26
27namespace {
28class SPIRVPostLegalizer : public MachineFunctionPass {
29public:
30 static char ID;
31 SPIRVPostLegalizer() : MachineFunctionPass(ID) {}
32 bool runOnMachineFunction(MachineFunction &MF) override;
33};
34} // namespace
35
36namespace llvm {
37// Defined in SPIRVPreLegalizer.cpp.
38extern void insertAssignInstr(Register Reg, Type *Ty, SPIRVType *SpirvTy,
43 SPIRVType *KnownResType);
44} // namespace llvm
45
46static bool mayBeInserted(unsigned Opcode) {
47 switch (Opcode) {
48 case TargetOpcode::G_SMAX:
49 case TargetOpcode::G_UMAX:
50 case TargetOpcode::G_SMIN:
51 case TargetOpcode::G_UMIN:
52 case TargetOpcode::G_FMINNUM:
53 case TargetOpcode::G_FMINIMUM:
54 case TargetOpcode::G_FMAXNUM:
55 case TargetOpcode::G_FMAXIMUM:
56 return true;
57 default:
58 return isTypeFoldingSupported(Opcode);
59 }
60}
61
63 MachineIRBuilder MIB) {
65
66 for (MachineBasicBlock &MBB : MF) {
67 for (MachineInstr &I : MBB) {
68 const unsigned Opcode = I.getOpcode();
69 if (Opcode == TargetOpcode::G_UNMERGE_VALUES) {
70 unsigned ArgI = I.getNumOperands() - 1;
71 Register SrcReg = I.getOperand(ArgI).isReg()
72 ? I.getOperand(ArgI).getReg()
73 : Register(0);
74 SPIRVType *DefType =
75 SrcReg.isValid() ? GR->getSPIRVTypeForVReg(SrcReg) : nullptr;
76 if (!DefType || DefType->getOpcode() != SPIRV::OpTypeVector)
78 "cannot select G_UNMERGE_VALUES with a non-vector argument");
79 SPIRVType *ScalarType =
80 GR->getSPIRVTypeForVReg(DefType->getOperand(1).getReg());
81 for (unsigned i = 0; i < I.getNumDefs(); ++i) {
82 Register ResVReg = I.getOperand(i).getReg();
83 SPIRVType *ResType = GR->getSPIRVTypeForVReg(ResVReg);
84 if (!ResType) {
85 // There was no "assign type" actions, let's fix this now
86 ResType = ScalarType;
87 setRegClassType(ResVReg, ResType, GR, &MRI, *GR->CurMF, true);
88 }
89 }
90 } else if (mayBeInserted(Opcode) && I.getNumDefs() == 1 &&
91 I.getNumOperands() > 1 && I.getOperand(1).isReg()) {
92 // Legalizer may have added a new instructions and introduced new
93 // registers, we must decorate them as if they were introduced in a
94 // non-automatic way
95 Register ResVReg = I.getOperand(0).getReg();
96 // Check if the register defined by the instruction is newly generated
97 // or already processed
98 // Check if we have type defined for operands of the new instruction
99 bool IsKnownReg = MRI.getRegClassOrNull(ResVReg);
100 SPIRVType *ResVType = GR->getSPIRVTypeForVReg(
101 IsKnownReg ? ResVReg : I.getOperand(1).getReg());
102 if (!ResVType)
103 continue;
104 // Set type & class
105 if (!IsKnownReg)
106 setRegClassType(ResVReg, ResVType, GR, &MRI, *GR->CurMF, true);
107 // If this is a simple operation that is to be reduced by TableGen
108 // definition we must apply some of pre-legalizer rules here
109 if (isTypeFoldingSupported(Opcode)) {
110 processInstr(I, MIB, MRI, GR, GR->getSPIRVTypeForVReg(ResVReg));
111 if (IsKnownReg && MRI.hasOneUse(ResVReg)) {
112 MachineInstr &UseMI = *MRI.use_instr_begin(ResVReg);
113 if (UseMI.getOpcode() == SPIRV::ASSIGN_TYPE)
114 continue;
115 }
116 insertAssignInstr(ResVReg, nullptr, ResVType, GR, MIB, MRI);
117 }
118 }
119 }
120 }
121}
122
123// Do a preorder traversal of the CFG starting from the BB |Start|.
124// point. Calls |op| on each basic block encountered during the traversal.
126 std::function<void(MachineBasicBlock *)> op) {
127 std::stack<MachineBasicBlock *> ToVisit;
129
130 ToVisit.push(&Start);
131 Seen.insert(ToVisit.top());
132 while (ToVisit.size() != 0) {
133 MachineBasicBlock *MBB = ToVisit.top();
134 ToVisit.pop();
135
136 op(MBB);
137
138 for (auto Succ : MBB->successors()) {
139 if (Seen.contains(Succ))
140 continue;
141 ToVisit.push(Succ);
142 Seen.insert(Succ);
143 }
144 }
145}
146
147// Do a preorder traversal of the CFG starting from the given function's entry
148// point. Calls |op| on each basic block encountered during the traversal.
149void visit(MachineFunction &MF, std::function<void(MachineBasicBlock *)> op) {
150 visit(MF, *MF.begin(), std::move(op));
151}
152
153bool SPIRVPostLegalizer::runOnMachineFunction(MachineFunction &MF) {
154 // Initialize the type registry.
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
165INITIALIZE_PASS(SPIRVPostLegalizer, DEBUG_TYPE, "SPIRV post legalizer", false,
166 false)
167
168char SPIRVPostLegalizer::ID = 0;
169
171 return new SPIRVPostLegalizer();
172}
unsigned const MachineRegisterInfo * MRI
MachineInstrBuilder & UseMI
MachineBasicBlock & MBB
This file contains the simple types necessary to represent the attributes associated with functions a...
#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:56
void visit(MachineFunction &MF, MachineBasicBlock &Start, std::function< void(MachineBasicBlock *)> op)
#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:314
iterator_range< succ_iterator > successors()
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:72
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
Definition: MachineInstr.h:587
const MachineOperand & getOperand(unsigned i) const
Definition: MachineInstr.h:595
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
constexpr bool isValid() const
Definition: Register.h:107
SPIRVType * getSPIRVTypeForVReg(Register VReg, const MachineFunction *MF=nullptr) 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:401
bool contains(ConstPtrType Ptr) const
Definition: SmallPtrSet.h:476
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
Definition: SmallPtrSet.h:541
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
void 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,...
bool isTypeFoldingSupported(unsigned Opcode)
Definition: SPIRVUtils.cpp:958
void processInstr(MachineInstr &MI, MachineIRBuilder &MIB, MachineRegisterInfo &MRI, SPIRVGlobalRegistry *GR, SPIRVType *KnownResType)
FunctionPass * createSPIRVPostLegalizerPass()
void setRegClassType(Register Reg, SPIRVType *SpvType, SPIRVGlobalRegistry *GR, MachineRegisterInfo *MRI, const MachineFunction &MF, bool Force)
Definition: SPIRVUtils.cpp:770
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition: Error.cpp:167