xref: /freebsd/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVPostLegalizer.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 
25 using namespace llvm;
26 
27 namespace {
28 class SPIRVPostLegalizer : public MachineFunctionPass {
29 public:
30   static char ID;
SPIRVPostLegalizer()31   SPIRVPostLegalizer() : MachineFunctionPass(ID) {}
32   bool runOnMachineFunction(MachineFunction &MF) override;
33 };
34 } // namespace
35 
36 namespace llvm {
37 //  Defined in SPIRVPreLegalizer.cpp.
38 extern void insertAssignInstr(Register Reg, Type *Ty, SPIRVType *SpirvTy,
39                               SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB,
40                               MachineRegisterInfo &MRI);
41 extern void processInstr(MachineInstr &MI, MachineIRBuilder &MIB,
42                          MachineRegisterInfo &MRI, SPIRVGlobalRegistry *GR,
43                          SPIRVType *KnownResType);
44 } // namespace llvm
45 
mayBeInserted(unsigned Opcode)46 static 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 
processNewInstrs(MachineFunction & MF,SPIRVGlobalRegistry * GR,MachineIRBuilder MIB)62 static void processNewInstrs(MachineFunction &MF, SPIRVGlobalRegistry *GR,
63                              MachineIRBuilder MIB) {
64   MachineRegisterInfo &MRI = MF.getRegInfo();
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)
77           report_fatal_error(
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.
visit(MachineFunction & MF,MachineBasicBlock & Start,std::function<void (MachineBasicBlock *)> op)125 void visit(MachineFunction &MF, MachineBasicBlock &Start,
126            std::function<void(MachineBasicBlock *)> op) {
127   std::stack<MachineBasicBlock *> ToVisit;
128   SmallPtrSet<MachineBasicBlock *, 8> Seen;
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.
visit(MachineFunction & MF,std::function<void (MachineBasicBlock *)> op)149 void visit(MachineFunction &MF, std::function<void(MachineBasicBlock *)> op) {
150   visit(MF, *MF.begin(), op);
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