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
30using namespace llvm;
31
32namespace {
33class SPIRVPostLegalizer : public MachineFunctionPass {
34public:
35 static char ID;
36 SPIRVPostLegalizer() : MachineFunctionPass(ID) {
37 initializeSPIRVPostLegalizerPass(*PassRegistry::getPassRegistry());
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,
49 SPIRVGlobalRegistry *GR,
50 MachineIRBuilder &MIB,
51 MachineRegisterInfo &MRI);
52extern void processInstr(MachineInstr &MI, MachineIRBuilder &MIB,
53 MachineRegisterInfo &MRI, SPIRVGlobalRegistry *GR);
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
79static void processNewInstrs(MachineFunction &MF, SPIRVGlobalRegistry *GR,
80 MachineIRBuilder MIB) {
81 MachineRegisterInfo &MRI = MF.getRegInfo();
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(i: ArgI).isReg()
89 ? I.getOperand(i: ArgI).getReg()
90 : Register(0);
91 SPIRVType *DefType =
92 SrcReg.isValid() ? GR->getSPIRVTypeForVReg(VReg: SrcReg) : nullptr;
93 if (!DefType || DefType->getOpcode() != SPIRV::OpTypeVector)
94 report_fatal_error(
95 reason: "cannot select G_UNMERGE_VALUES with a non-vector argument");
96 SPIRVType *ScalarType =
97 GR->getSPIRVTypeForVReg(VReg: DefType->getOperand(i: 1).getReg());
98 for (unsigned i = 0; i < I.getNumDefs(); ++i) {
99 Register ResVReg = I.getOperand(i).getReg();
100 SPIRVType *ResType = GR->getSPIRVTypeForVReg(VReg: 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(VReg: ResVReg,
106 Ty: LLT::scalar(SizeInBits: GR->getScalarOrVectorBitWidth(Type: ResType)));
107 GR->assignSPIRVTypeToVReg(Type: ResType, VReg: ResVReg, MF&: *GR->CurMF);
108 }
109 }
110 } else if (mayBeInserted(Opcode) && I.getNumDefs() == 1 &&
111 I.getNumOperands() > 1 && I.getOperand(i: 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(i: 0).getReg();
116 SPIRVType *ResVType = GR->getSPIRVTypeForVReg(VReg: 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(VReg: I.getOperand(i: 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(VReg: ResVReg,
128 Ty: LLT::scalar(SizeInBits: GR->getScalarOrVectorBitWidth(Type: ResVType)));
129 GR->assignSPIRVTypeToVReg(Type: ResVType, VReg: ResVReg, MF&: *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(Opcode: 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(VReg: ResVReg, Ty: LLT::scalar(SizeInBits: 32));
144 insertAssignInstr(Reg: ResVReg, Ty: nullptr, SpirvTy: ResVType, GR, MIB, MRI);
145 processInstr(MI&: I, MIB, MRI, GR);
146 }
147 }
148 }
149 }
150}
151
152bool SPIRVPostLegalizer::runOnMachineFunction(MachineFunction &MF) {
153 // Initialize the type registry.
154 const SPIRVSubtarget &ST = MF.getSubtarget<SPIRVSubtarget>();
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
169FunctionPass *llvm::createSPIRVPostLegalizerPass() {
170 return new SPIRVPostLegalizer();
171}
172

source code of llvm/lib/Target/SPIRV/SPIRVPostLegalizer.cpp