LLVM 24.0.0git
SPIRVPreLegalizer.cpp
Go to the documentation of this file.
1//===-- SPIRVPreLegalizer.cpp - prepare IR for legalization -----*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// The pass prepares IR for legalization: it assigns SPIR-V types to registers
10// and removes intrinsics which holded these types during IR translation.
11// Also it processes constants and registers them in GR to avoid duplication.
12//
13//===----------------------------------------------------------------------===//
14
15#include "SPIRV.h"
16#include "SPIRVSubtarget.h"
17#include "SPIRVUtils.h"
23#include "llvm/IR/Analysis.h"
24#include "llvm/IR/Attributes.h"
25#include "llvm/IR/Constants.h"
26#include "llvm/IR/InstrTypes.h"
27#include "llvm/IR/IntrinsicsSPIRV.h"
29
30#define DEBUG_TYPE "spirv-prelegalizer"
31
32using namespace llvm;
33
34namespace {
35class SPIRVPreLegalizerLegacy : public MachineFunctionPass {
36public:
37 static char ID;
38 SPIRVPreLegalizerLegacy() : MachineFunctionPass(ID) {}
39 bool runOnMachineFunction(MachineFunction &MF) override;
40 void getAnalysisUsage(AnalysisUsage &AU) const override;
41};
42} // namespace
43
44void SPIRVPreLegalizerLegacy::getAnalysisUsage(AnalysisUsage &AU) const {
45 AU.addPreserved<GISelValueTrackingAnalysisLegacy>();
47}
48
52 MI->eraseFromParent();
53}
54
55static void
57 const SPIRVSubtarget &STI,
58 DenseMap<MachineInstr *, Type *> &TargetExtConstTypes) {
60 DenseMap<MachineInstr *, Register> RegsAlreadyAddedToDT;
61 SmallVector<MachineInstr *, 10> ToErase, ToEraseComposites;
62 for (MachineBasicBlock &MBB : MF) {
63 for (MachineInstr &MI : MBB) {
64 if (!isSpvIntrinsic(MI, Intrinsic::spv_track_constant))
65 continue;
66 ToErase.push_back(&MI);
67 Register SrcReg = MI.getOperand(2).getReg();
68 auto *Const =
70 MI.getOperand(3).getMetadata()->getOperand(0))
71 ->getValue());
72 if (auto *GV = dyn_cast<GlobalValue>(Const)) {
73 Register Reg = GR->find(GV, &MF);
74 if (!Reg.isValid()) {
75 GR->add(GV, MRI.getVRegDef(SrcReg));
76 GR->addGlobalObject(GV, &MF, SrcReg);
77 } else
78 RegsAlreadyAddedToDT[&MI] = Reg;
79 } else {
80 Register Reg = GR->find(Const, &MF);
81 if (!Reg.isValid()) {
82 if (auto *ConstVec = dyn_cast<ConstantDataVector>(Const)) {
83 auto *BuildVec = MRI.getVRegDef(SrcReg);
84 assert(BuildVec &&
85 BuildVec->getOpcode() == TargetOpcode::G_BUILD_VECTOR);
86 GR->add(Const, BuildVec);
87 for (unsigned i = 0; i < ConstVec->getNumElements(); ++i) {
88 // Ensure that OpConstantComposite reuses a constant when it's
89 // already created and available in the same machine function.
90 Constant *ElemConst = ConstVec->getElementAsConstant(i);
91 Register ElemReg = GR->find(ElemConst, &MF);
92 if (!ElemReg.isValid())
93 GR->add(ElemConst,
94 MRI.getVRegDef(BuildVec->getOperand(1 + i).getReg()));
95 else
96 BuildVec->getOperand(1 + i).setReg(ElemReg);
97 }
98 }
99 if (Const->getType()->isTargetExtTy()) {
100 // remember association so that we can restore it when assign types
101 MachineInstr *SrcMI = MRI.getVRegDef(SrcReg);
102 if (SrcMI)
103 GR->add(Const, SrcMI);
104 if (SrcMI && (SrcMI->getOpcode() == TargetOpcode::G_CONSTANT ||
105 SrcMI->getOpcode() == TargetOpcode::G_IMPLICIT_DEF))
106 TargetExtConstTypes[SrcMI] = Const->getType();
107 if (Const->isNullValue()) {
108 MachineBasicBlock &DepMBB = MF.front();
109 MachineIRBuilder MIB(DepMBB, DepMBB.getFirstNonPHI());
111 Const->getType(), MIB, SPIRV::AccessQualifier::ReadWrite,
112 true);
113 assert(SrcMI && "Expected source instruction to be valid");
114 SrcMI->setDesc(STI.getInstrInfo()->get(SPIRV::OpConstantNull));
116 GR->getSPIRVTypeID(ExtType), false));
117 }
118 }
119 } else {
120 RegsAlreadyAddedToDT[&MI] = Reg;
121 // This MI is unused and will be removed. If the MI uses
122 // const_composite, it will be unused and should be removed too.
123 assert(MI.getOperand(2).isReg() && "Reg operand is expected");
124 MachineInstr *SrcMI = MRI.getVRegDef(MI.getOperand(2).getReg());
125 if (SrcMI && isSpvIntrinsic(*SrcMI, Intrinsic::spv_const_composite))
126 ToEraseComposites.push_back(SrcMI);
127 }
128 }
129 }
130 }
131 for (MachineInstr *MI : ToErase) {
132 Register Reg = MI->getOperand(2).getReg();
133 auto It = RegsAlreadyAddedToDT.find(MI);
134 if (It != RegsAlreadyAddedToDT.end())
135 Reg = It->second;
136 auto *RC = MRI.getRegClassOrNull(MI->getOperand(0).getReg());
137 if (!MRI.getRegClassOrNull(Reg) && RC)
138 MRI.setRegClass(Reg, RC);
139 MRI.replaceRegWith(MI->getOperand(0).getReg(), Reg);
141 }
142 for (MachineInstr *MI : ToEraseComposites)
144}
145
148 MachineIRBuilder MIB) {
150 for (MachineBasicBlock &MBB : MF) {
151 for (MachineInstr &MI : MBB) {
152 if (!isSpvIntrinsic(MI, Intrinsic::spv_assign_name))
153 continue;
154 const MDNode *MD = MI.getOperand(2).getMetadata();
155 StringRef ValueName = cast<MDString>(MD->getOperand(0))->getString();
156 if (ValueName.size() > 0) {
157 MIB.setInsertPt(*MI.getParent(), MI);
158 buildOpName(MI.getOperand(1).getReg(), ValueName, MIB);
159 }
160 ToErase.push_back(&MI);
161 }
162 for (MachineInstr *MI : ToErase)
164 ToErase.clear();
165 }
166}
167
169 MachineRegisterInfo *MRI) {
171 IE = MRI->use_instr_end();
172 I != IE; ++I) {
173 MachineInstr *UseMI = &*I;
174 if ((isSpvIntrinsic(*UseMI, Intrinsic::spv_assign_ptr_type) ||
175 isSpvIntrinsic(*UseMI, Intrinsic::spv_assign_type)) &&
176 UseMI->getOperand(1).getReg() == Reg)
177 return UseMI;
178 }
179 return nullptr;
180}
181
183 Register ResVReg, Register OpReg) {
184 SPIRVTypeInst ResType = GR->getSPIRVTypeForVReg(ResVReg);
185 SPIRVTypeInst OpType = GR->getSPIRVTypeForVReg(OpReg);
186 assert(ResType && OpType && "Operand types are expected");
187 if (!GR->isBitcastCompatible(ResType, OpType))
188 report_fatal_error("incompatible result and operand types in a bitcast");
189 MachineRegisterInfo *MRI = MIB.getMRI();
190 if (!MRI->getRegClassOrNull(ResVReg))
191 MRI->setRegClass(ResVReg, GR->getRegClass(ResType));
192 if (ResType == OpType)
193 MIB.buildInstr(TargetOpcode::COPY).addDef(ResVReg).addUse(OpReg);
194 else
195 MIB.buildInstr(SPIRV::OpBitcast)
196 .addDef(ResVReg)
197 .addUse(GR->getSPIRVTypeID(ResType))
198 .addUse(OpReg);
199}
200
201// We lower G_BITCAST to OpBitcast here to avoid a MachineVerifier error.
202// The verifier checks if the source and destination LLTs of a G_BITCAST are
203// different, but this check is too strict for SPIR-V's typed pointers, which
204// may have the same LLT but different SPIRV type (e.g. pointers to different
205// pointee types). By lowering to OpBitcast here, we bypass the verifier's
206// check. See discussion in https://github.com/llvm/llvm-project/pull/110270
207// for more context.
208//
209// We also handle the llvm.spv.bitcast intrinsic here. If the source and
210// destination SPIR-V types are the same, we lower it to a COPY to enable
211// further optimizations like copy propagation.
213 MachineIRBuilder MIB) {
215 for (MachineBasicBlock &MBB : MF) {
216 for (MachineInstr &MI : MBB) {
217 if (isSpvIntrinsic(MI, Intrinsic::spv_bitcast)) {
218 Register DstReg = MI.getOperand(0).getReg();
219 Register SrcReg = MI.getOperand(2).getReg();
220 SPIRVTypeInst DstType = GR->getSPIRVTypeForVReg(DstReg);
221 assert(
222 DstType &&
223 "Expected destination SPIR-V type to have been assigned already.");
224 SPIRVTypeInst SrcType = GR->getSPIRVTypeForVReg(SrcReg);
225 assert(SrcType &&
226 "Expected source SPIR-V type to have been assigned already.");
227 if (DstType == SrcType) {
228 MIB.setInsertPt(*MI.getParent(), MI);
229 MIB.buildCopy(DstReg, SrcReg);
230 ToErase.push_back(&MI);
231 continue;
232 }
233 }
234
235 if (MI.getOpcode() != TargetOpcode::G_BITCAST)
236 continue;
237
238 MIB.setInsertPt(*MI.getParent(), MI);
239 buildOpBitcast(GR, MIB, MI.getOperand(0).getReg(),
240 MI.getOperand(1).getReg());
241 ToErase.push_back(&MI);
242 }
243 }
244 for (MachineInstr *MI : ToErase)
246}
247
249 MachineIRBuilder MIB) {
250 // Get access to information about available extensions
251 const SPIRVSubtarget *ST =
252 static_cast<const SPIRVSubtarget *>(&MIB.getMF().getSubtarget());
254 for (MachineBasicBlock &MBB : MF) {
255 for (MachineInstr &MI : MBB) {
256 if (!isSpvIntrinsic(MI, Intrinsic::spv_ptrcast))
257 continue;
258 assert(MI.getOperand(2).isReg());
259 MIB.setInsertPt(*MI.getParent(), MI);
260 ToErase.push_back(&MI);
261 Register Def = MI.getOperand(0).getReg();
262 Register Source = MI.getOperand(2).getReg();
263 Type *ElemTy = getMDOperandAsType(MI.getOperand(3).getMetadata(), 0);
264 auto SC =
265 isa<FunctionType>(ElemTy) &&
266 ST->canUseExtension(
267 SPIRV::Extension::SPV_INTEL_function_pointers)
268 ? SPIRV::StorageClass::CodeSectionINTEL
269 : addressSpaceToStorageClass(MI.getOperand(4).getImm(), *ST);
270 SPIRVTypeInst AssignedPtrType =
271 GR->getOrCreateSPIRVPointerType(ElemTy, MI, SC);
272
273 // If the ptrcast would be redundant, replace all uses with the source
274 // register.
275 MachineRegisterInfo *MRI = MIB.getMRI();
276 // For untyped pointers the SPIR-V pointer type does not encode the
277 // pointee, so two pointers with different element types share the same
278 // pointer type. The element type still matters because it selects the
279 // Base Type operand of OpUntyped*AccessChainKHR. Treat the cast as
280 // redundant only when the source already carries the same element type.
281 // Otherwise keep a distinct register so the element type is preserved.
282 bool Redundant =
283 AssignedPtrType->getOpcode() == SPIRV::OpTypeUntypedPointerKHR
284 ? GR->getUntypedPtrElementType(Source) ==
285 GR->getOrCreateSPIRVType(ElemTy, MIB,
286 SPIRV::AccessQualifier::ReadWrite,
287 /*EmitIR=*/true)
288 : GR->getSPIRVTypeForVReg(Source) == AssignedPtrType;
289 if (Redundant) {
290 // Erase Def's assign type instruction if we are going to replace Def.
291 if (MachineInstr *AssignMI = findAssignTypeInstr(Def, MRI))
292 ToErase.push_back(AssignMI);
293 MRI->replaceRegWith(Def, Source);
294 } else {
295 if (!GR->getSPIRVTypeForVReg(Def, &MF))
296 GR->assignSPIRVTypeToVReg(AssignedPtrType, Def, MF);
297 MIB.buildBitcast(Def, Source);
298 }
299 }
300 }
301 for (MachineInstr *MI : ToErase)
303}
304
305// Translating GV, IRTranslator sometimes generates following IR:
306// %1 = G_GLOBAL_VALUE
307// %2 = COPY %1
308// %3 = G_ADDRSPACE_CAST %2
309//
310// or
311//
312// %1 = G_ZEXT %2
313// G_MEMCPY ... %2 ...
314//
315// New registers have no SPIRV type and no register class info.
316//
317// Set SPIRV type for GV, propagate it from GV to other instructions,
318// also set register classes.
322 MachineIRBuilder &MIB) {
323 SPIRVTypeInst SpvType = nullptr;
324 assert(MI && "Machine instr is expected");
325 if (MI->getOperand(0).isReg()) {
326 Register Reg = MI->getOperand(0).getReg();
327 SpvType = GR->getSPIRVTypeForVReg(Reg);
328 if (!SpvType) {
329 switch (MI->getOpcode()) {
330 case TargetOpcode::G_FCONSTANT:
331 case TargetOpcode::G_CONSTANT: {
332 MIB.setInsertPt(*MI->getParent(), MI);
333 Type *Ty = MI->getOperand(1).getCImm()->getType();
334 SpvType = GR->getOrCreateSPIRVType(
335 Ty, MIB, SPIRV::AccessQualifier::ReadWrite, true);
336 break;
337 }
338 case TargetOpcode::G_GLOBAL_VALUE: {
339 MIB.setInsertPt(*MI->getParent(), MI);
340 const GlobalValue *Global = MI->getOperand(1).getGlobal();
342 unsigned AddrSpace = Global->getType()->getAddressSpace();
343 // Function pointers use CodeSectionINTEL storage class in SPIR-V when
344 // the SPV_INTEL_function_pointers extension is enabled.
345 const SPIRVSubtarget &ST = MIB.getMF().getSubtarget<SPIRVSubtarget>();
346 if (isa<Function>(Global) &&
347 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers))
348 AddrSpace =
349 storageClassToAddressSpace(SPIRV::StorageClass::CodeSectionINTEL);
350 auto *Ty = TypedPointerType::get(ElementTy, AddrSpace);
351 SpvType = GR->getOrCreateSPIRVType(
352 Ty, MIB, SPIRV::AccessQualifier::ReadWrite, true);
353 break;
354 }
355 case TargetOpcode::G_ANYEXT:
356 case TargetOpcode::G_SEXT:
357 case TargetOpcode::G_ZEXT: {
358 if (MI->getOperand(1).isReg()) {
359 if (MachineInstr *DefInstr =
360 MRI.getVRegDef(MI->getOperand(1).getReg())) {
361 if (SPIRVTypeInst Def =
362 propagateSPIRVType(DefInstr, GR, MRI, MIB)) {
363 unsigned CurrentBW = GR->getScalarOrVectorBitWidth(Def);
364 unsigned ExpectedBW =
365 std::max(MRI.getType(Reg).getScalarSizeInBits(), CurrentBW);
366 unsigned NumElements = GR->getScalarOrVectorComponentCount(Def);
367 SpvType = GR->getOrCreateSPIRVIntegerType(ExpectedBW, MIB);
368 if (NumElements > 1)
369 SpvType = GR->getOrCreateSPIRVVectorType(SpvType, NumElements,
370 MIB, true);
371 }
372 }
373 }
374 break;
375 }
376 case TargetOpcode::G_PTRTOINT:
377 SpvType = GR->getOrCreateSPIRVIntegerType(
378 MRI.getType(Reg).getScalarSizeInBits(), MIB);
379 break;
380 case TargetOpcode::G_TRUNC:
381 case TargetOpcode::G_ADDRSPACE_CAST:
382 case TargetOpcode::G_PTR_ADD:
383 case TargetOpcode::COPY: {
384 MachineOperand &Op = MI->getOperand(1);
385 MachineInstr *Def = Op.isReg() ? MRI.getVRegDef(Op.getReg()) : nullptr;
386 if (Def)
387 SpvType = propagateSPIRVType(Def, GR, MRI, MIB);
388 break;
389 }
390 default:
391 break;
392 }
393 if (SpvType) {
394 // check if the address space needs correction
395 LLT RegType = MRI.getType(Reg);
396 if (SpvType.isPointer() && RegType.isPointer() &&
398 RegType.getAddressSpace()) {
399 // Don't correct CodeSectionINTEL back to Function for function
400 // pointer G_GLOBAL_VALUE - the LLVM register has address space 0
401 // but the SPIR-V type was intentionally set to CodeSectionINTEL.
402 bool SkipCorrection =
403 MI->getOpcode() == TargetOpcode::G_GLOBAL_VALUE &&
404 GR->getPointerStorageClass(SpvType) ==
405 SPIRV::StorageClass::CodeSectionINTEL;
406 if (!SkipCorrection) {
407 const SPIRVSubtarget &ST =
408 MI->getParent()->getParent()->getSubtarget<SPIRVSubtarget>();
409 auto TSC =
410 addressSpaceToStorageClass(RegType.getAddressSpace(), ST);
411 SpvType = GR->changePointerStorageClass(SpvType, TSC, *MI);
412 }
413 }
414 GR->assignSPIRVTypeToVReg(SpvType, Reg, MIB.getMF());
415 }
416 if (!MRI.getRegClassOrNull(Reg))
417 MRI.setRegClass(Reg, SpvType ? GR->getRegClass(SpvType)
418 : &SPIRV::iIDRegClass);
419 }
420 }
421 return SpvType;
422}
423
424// To support current approach and limitations wrt. bit width here we widen a
425// scalar register with a bit width greater than 1 to valid sizes and cap it to
426// 128 width.
427static unsigned widenBitWidthToNextPow2(unsigned BitWidth) {
428 if (BitWidth == 1)
429 return 1; // No need to widen 1-bit values
430 return std::min(std::max<unsigned>(PowerOf2Ceil(BitWidth), 8u), 128u);
431}
432
434 LLT RegType = MRI.getType(Reg);
435 if (!RegType.isScalar())
436 return;
437 unsigned CurrentWidth = RegType.getScalarSizeInBits();
438 unsigned NewWidth = widenBitWidthToNextPow2(CurrentWidth);
439 if (NewWidth != CurrentWidth)
440 MRI.setType(Reg, LLT::scalar(NewWidth));
441}
442
443static void widenCImmType(MachineOperand &MOP) {
444 const ConstantInt *CImmVal = MOP.getCImm();
445 unsigned CurrentWidth = CImmVal->getBitWidth();
446 unsigned NewWidth = widenBitWidthToNextPow2(CurrentWidth);
447 if (NewWidth != CurrentWidth) {
448 // Replace the immediate value with the widened version
449 MOP.setCImm(ConstantInt::get(CImmVal->getType()->getContext(),
450 CImmVal->getValue().zextOrTrunc(NewWidth)));
451 }
452}
453
455 MachineBasicBlock &MBB = *Def->getParent();
457 Def->getNextNode() ? Def->getNextNode()->getIterator() : MBB.end();
458 // Skip all the PHI and debug instructions.
459 while (DefIt != MBB.end() &&
460 (DefIt->isPHI() || DefIt->isDebugOrPseudoInstr()))
461 DefIt = std::next(DefIt);
462 MIB.setInsertPt(MBB, DefIt);
463}
464
465namespace llvm {
468 MachineRegisterInfo &MRI) {
469 assert((Ty || SpvType) && "Either LLVM or SPIRV type is expected.");
470 MachineInstr *Def = MRI.getVRegDef(Reg);
471 setInsertPtAfterDef(MIB, Def);
472 if (!SpvType)
473 SpvType = GR->getOrCreateSPIRVType(Ty, MIB,
474 SPIRV::AccessQualifier::ReadWrite, true);
475 if (!MRI.getRegClassOrNull(Reg))
476 MRI.setRegClass(Reg, GR->getRegClass(SpvType));
477 if (!MRI.getType(Reg).isValid())
478 MRI.setType(Reg, GR->getRegType(SpvType));
479 GR->assignSPIRVTypeToVReg(SpvType, Reg, MIB.getMF());
480}
481
484 SPIRVTypeInst KnownResType) {
485 MIB.setInsertPt(*MI.getParent(), MI.getIterator());
486 for (auto &Op : MI.operands()) {
487 if (!Op.isReg() || Op.isDef())
488 continue;
489 Register OpReg = Op.getReg();
490 SPIRVTypeInst SpvType = GR->getSPIRVTypeForVReg(OpReg);
491 if (!SpvType && KnownResType) {
492 SpvType = KnownResType;
493 GR->assignSPIRVTypeToVReg(KnownResType, OpReg, *MI.getMF());
494 }
495 assert(SpvType);
496 if (!MRI.getRegClassOrNull(OpReg))
497 MRI.setRegClass(OpReg, GR->getRegClass(SpvType));
498 if (!MRI.getType(OpReg).isValid())
499 MRI.setType(OpReg, GR->getRegType(SpvType));
500 }
501}
502} // namespace llvm
503
504// Sign-sensitive integer ops: their result depends on the value of the input
505// sign bit at position (width-1). On sub-pow2 widths the general widening
506// loop is a pure LLT relabel, which leaves the sign bit at the *original*
507// position instead of the widened MSB. These ops therefore need an explicit
508// G_SEXT_INREG on each value operand to move the sign bit up.
509//
510// Signed-vs-unsigned G_ICMP is distinguished by its predicate operand.
511//
512// TODO: follow-up PRs will add the remaining sign-sensitive opcodes
513// (e.g. G_SMIN/G_SMAX, G_SADDSAT/G_SSUBSAT, signed overflow ops).
514static bool isSignSensitiveOp(const MachineInstr &MI) {
515 switch (MI.getOpcode()) {
516 case TargetOpcode::G_ASHR:
517 case TargetOpcode::G_SDIV:
518 case TargetOpcode::G_SREM:
519 return true;
520 case TargetOpcode::G_ICMP:
521 return CmpInst::isSigned(
522 static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate()));
523 default:
524 return false;
525 }
526}
527
529 // Width before widening of each value-operand vreg (one entry per vreg).
531 // Ops whose value operand(s) need replacing, ordered for reproducible vreg
532 // numbering.
534};
535
536// Collect sign-sensitive ops with narrow scalar value operands and their
537// pre-widening widths, before later passes retype those vregs to pow2 LLTs
538// and the original width is no longer recoverable.
541 MachineRegisterInfo &MRI) {
543 auto RecordIfNarrow = [&](Register Reg) {
544 LLT Ty = MRI.getType(Reg);
545 if (!Ty.isScalar())
546 return false;
547 unsigned W = Ty.getScalarSizeInBits();
548 if (widenBitWidthToNextPow2(W) == W)
549 return false;
550 Info.OrigWidth.try_emplace(Reg, W);
551 return true;
552 };
553 for (MachineBasicBlock &MBB : MF) {
554 for (MachineInstr &MI : MBB) {
555 if (!isSignSensitiveOp(MI))
556 continue;
557 // Value operands are the trailing two, past any def or predicate.
558 unsigned N = MI.getNumOperands();
559 const MachineOperand &LHS = MI.getOperand(N - 2);
560 const MachineOperand &RHS = MI.getOperand(N - 1);
561 // Sign-sensitive opcodes carry register operands only.
562 assert(LHS.isReg() && RHS.isReg());
563 bool NeedsRewrite = RecordIfNarrow(LHS.getReg());
564 NeedsRewrite = RecordIfNarrow(RHS.getReg()) || NeedsRewrite;
565 if (NeedsRewrite)
566 Info.Worklist.push_back(&MI);
567 }
568 }
569 return Info;
570}
571
572// For every recorded sign-sensitive op, insert G_SEXT_INREG on each value
573// operand whose original width was narrower than the widened pow2 width and
574// retype the operand's vreg LLT in place to the widened width.
575//
576// Info must have been populated by recordSignSensitiveOperandWidths before
577// other passes retyped the vregs; otherwise the narrow widths needed here
578// are lost.
579//
580// TODO: handle vector operands.
582 MachineIRBuilder &MIB,
584 const SignSensitiveWideningInfo &Info) {
585 // Emit G_SEXT_INREG from Reg's recorded narrow width; retypes Reg to the
586 // widened width and returns the sign-extended vreg.
587 auto SignExtendReg = [&](Register Reg, unsigned OldW,
589 unsigned NewW = widenBitWidthToNextPow2(OldW);
590 LLT NewLLT = LLT::scalar(NewW);
591 MIB.setInsertPt(*MI.getParent(), MI.getIterator());
592 SPIRVTypeInst SpvTy = GR->getOrCreateSPIRVIntegerType(NewW, MIB);
593 Register SExted = MRI.createGenericVirtualRegister(NewLLT);
594 GR->assignSPIRVTypeToVReg(SpvTy, SExted, MF);
595 MRI.setRegClass(SExted, GR->getRegClass(SpvTy));
596 MRI.setType(Reg, NewLLT);
597 MIB.buildSExtInReg(SExted, Reg, OldW);
598 return SExted;
599 };
600
601 // TODO: when the same narrow vreg feeds multiple sign-sensitive ops (e.g.
602 // sdiv %x, %y and srem %x, %y), emit one shared G_SEXT_INREG instead of one
603 // per use.
604 for (MachineInstr *MI : Info.Worklist) {
605 unsigned N = MI->getNumOperands();
606 MachineOperand &LHS = MI->getOperand(N - 2);
607 MachineOperand &RHS = MI->getOperand(N - 1);
608 Register LHSReg = LHS.getReg();
609 Register RHSReg = RHS.getReg();
610 if (auto It = Info.OrigWidth.find(LHSReg); It != Info.OrigWidth.end())
611 LHS.setReg(SignExtendReg(LHSReg, It->second, *MI));
612 // Same vreg on both sides (e.g. G_ICMP slt %x, %x): reuse the sext just
613 // emitted for LHS instead of emitting a second one.
614 if (RHSReg == LHSReg) {
615 RHS.setReg(LHS.getReg());
616 continue;
617 }
618 if (auto It = Info.OrigWidth.find(RHSReg); It != Info.OrigWidth.end())
619 RHS.setReg(SignExtendReg(RHSReg, It->second, *MI));
620 }
621}
622
623static void
626 DenseMap<MachineInstr *, Type *> &TargetExtConstTypes) {
627 // Get access to information about available extensions
628 const SPIRVSubtarget *ST =
629 static_cast<const SPIRVSubtarget *>(&MIB.getMF().getSubtarget());
630
633 DenseMap<MachineInstr *, Register> RegsAlreadyAddedToDT;
634
635 bool IsExtendedInts =
636 ST->canUseExtension(
637 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_integers) ||
638 ST->canUseExtension(SPIRV::Extension::SPV_KHR_bit_instructions) ||
639 ST->canUseExtension(SPIRV::Extension::SPV_INTEL_int4);
640
641 if (!IsExtendedInts) {
642 // Without arbitrary precision integer extensions, SPIR-V only supports
643 // integer widths of 8, 16, 32, 64. Non-standard widths (e.g., i24, i40)
644 // must be widened to the next power of two.
645 //
646 // Record the original widths of sign-sensitive operands before either
647 // the G_TRUNC handling or the general widening loop retypes vregs, then
648 // rewrite those ops after G_TRUNC processing using the recorded widths.
649 SignSensitiveWideningInfo SignSensitiveInfo =
651
652 // G_TRUNC requires special handling because its semantics depend on the
653 // original destination width. For example:
654 // %dst:s24 = G_TRUNC %src:s64
655 // After widening s24 to s32, we cannot simply do:
656 // %dst:s32 = G_TRUNC %src:s64
657 // because this would keep 32 bits instead of 24. Instead, we insert a
658 // G_AND to mask the value to the original width:
659 // %mask:s64 = G_CONSTANT 0xFFFFFF ; 24-bit mask
660 // %masked:s64 = G_AND %src:s64, %mask
661 // %dst:s32 = G_TRUNC %masked:s64
662 // If src and dst widen to the same size, G_TRUNC is replaced entirely:
663 // %mask:s64 = G_CONSTANT 0xFFFFFFFFFF ; 40-bit mask
664 // %dst:s64 = G_AND %src:s64, %mask
665 SmallVector<MachineInstr *, 8> TruncToRemove;
666 for (MachineBasicBlock &MBB : MF) {
667 for (MachineInstr &MI : MBB) {
668 unsigned MIOp = MI.getOpcode();
669 if (MIOp != TargetOpcode::G_TRUNC)
670 continue;
671 assert(MI.getNumOperands() == 2);
672 assert(MI.getOperand(0).isReg());
673 assert(MI.getOperand(1).isReg());
674
675 Register DstReg = MI.getOperand(0).getReg();
676 Register SrcReg = MI.getOperand(1).getReg();
677
678 LLT DstTy = MRI.getType(DstReg);
679 LLT SrcTy = MRI.getType(SrcReg);
680 assert((DstTy.isScalar() || DstTy.isVector()) &&
681 (SrcTy.isScalar() || SrcTy.isVector()) &&
682 "Expected scalar or vector G_TRUNC types");
683 assert(DstTy.isVector() == SrcTy.isVector() &&
684 "Expected matching scalar/vector G_TRUNC types");
685 assert((!DstTy.isVector() ||
686 DstTy.getElementCount() == SrcTy.getElementCount()) &&
687 "Expected equal vector element counts");
688
689 unsigned OriginalDstWidth = DstTy.getScalarSizeInBits();
690 unsigned OriginalSrcWidth = SrcTy.getScalarSizeInBits();
691
692 unsigned NewDstWidth = widenBitWidthToNextPow2(OriginalDstWidth);
693 unsigned NewSrcWidth = widenBitWidthToNextPow2(OriginalSrcWidth);
694 LLT NewDstTy = DstTy.changeElementSize(NewDstWidth);
695 LLT NewSrcTy = SrcTy.changeElementSize(NewSrcWidth);
696
697 // No Dst width change means no truncation semantics change, but the
698 // source still needs a legal type.
699 if (OriginalDstWidth == NewDstWidth) {
700 MRI.setType(SrcReg, NewSrcTy);
701 continue;
702 }
703
704 MRI.setType(SrcReg, NewSrcTy);
705 MRI.setType(DstReg, NewDstTy);
706
707 MIB.setInsertPt(MBB, MI.getIterator());
708 APInt Mask = APInt::getLowBitsSet(NewSrcWidth, OriginalDstWidth);
709 MachineInstrBuilder MaskReg =
710 DstTy.isVector()
712 NewSrcTy,
714 : MIB.buildConstant(NewSrcTy, Mask);
715 Register MaskedReg = MRI.createGenericVirtualRegister(NewSrcTy);
716 MIB.buildAnd(MaskedReg, SrcReg, MaskReg);
717
718 if (NewSrcWidth == NewDstWidth) {
719 // Rekey OrigWidth from DstReg to MaskedReg so widenSignSensitiveOps
720 // still sees the narrow original width after replaceRegWith.
721 if (auto It = SignSensitiveInfo.OrigWidth.find(DstReg);
722 It != SignSensitiveInfo.OrigWidth.end()) {
723 unsigned W = It->second;
724 SignSensitiveInfo.OrigWidth.erase(It);
725 SignSensitiveInfo.OrigWidth.try_emplace(MaskedReg, W);
726 }
727 MRI.replaceRegWith(DstReg, MaskedReg);
728 TruncToRemove.push_back(&MI);
729 } else {
730 MI.getOperand(1).setReg(MaskedReg);
731 }
732 }
733 }
734 for (MachineInstr *MI : TruncToRemove)
735 MI->eraseFromParent();
736
737 widenSignSensitiveOps(MF, GR, MIB, MRI, SignSensitiveInfo);
738 }
739
740 for (MachineBasicBlock *MBB : post_order(&MF)) {
741 if (MBB->empty())
742 continue;
743
744 bool ReachedBegin = false;
745 for (auto MII = std::prev(MBB->end()), Begin = MBB->begin();
746 !ReachedBegin;) {
747 MachineInstr &MI = *MII;
748 unsigned MIOp = MI.getOpcode();
749
750 if (!IsExtendedInts) {
751 // validate bit width of scalar registers and constant immediates
752 for (auto &MOP : MI.operands()) {
753 if (MOP.isReg())
754 widenScalarType(MOP.getReg(), MRI);
755 else if (MOP.isCImm())
756 widenCImmType(MOP);
757 }
758 }
759
760 if (isSpvIntrinsic(MI, Intrinsic::spv_assign_ptr_type)) {
761 Register Reg = MI.getOperand(1).getReg();
762 MIB.setInsertPt(*MI.getParent(), MI.getIterator());
763 Type *ElementTy = getMDOperandAsType(MI.getOperand(2).getMetadata(), 0);
764 auto SC = addressSpaceToStorageClass(MI.getOperand(3).getImm(), *ST);
765 if (SC == SPIRV::StorageClass::Function &&
766 isa<FunctionType>(ElementTy) &&
767 ST->canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers))
768 SC = SPIRV::StorageClass::CodeSectionINTEL;
769 SPIRVTypeInst AssignedPtrType =
770 GR->getOrCreateSPIRVPointerType(ElementTy, MI, SC);
771
772 // For untyped pointers, store the element type for later use.
773 if (ST->canUseExtension(SPIRV::Extension::SPV_KHR_untyped_pointers) &&
774 !ST->isShader()) {
775 SPIRVTypeInst ElemSpvType = GR->getOrCreateSPIRVType(
776 ElementTy, MIB, SPIRV::AccessQualifier::ReadWrite,
777 /*EmitIR=*/true);
778 GR->setUntypedPtrElementType(Reg, ElemSpvType);
779 }
780
781 // The intrinsic also carries vector-of-pointer values produced by
782 // scalarized vector GEPs; wrap the pointer in OpTypeVector to match
783 // the vreg's LLT.
784 LLT RegTy = MRI.getType(Reg);
785 if (RegTy.isValid() && RegTy.isVector())
786 AssignedPtrType = GR->getOrCreateSPIRVVectorType(
787 AssignedPtrType, RegTy.getNumElements(), MIB,
788 /*EmitIR=*/true);
789 MachineInstr *Def = MRI.getVRegDef(Reg);
790 assert(Def && "Expecting an instruction that defines the register");
791 // G_GLOBAL_VALUE already has type info.
792 if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE)
793 updateRegType(Reg, nullptr, AssignedPtrType, GR, MIB,
794 MF.getRegInfo());
795 ToErase.push_back(&MI);
796 } else if (isSpvIntrinsic(MI, Intrinsic::spv_assign_type)) {
797 Register Reg = MI.getOperand(1).getReg();
798 Type *Ty = getMDOperandAsType(MI.getOperand(2).getMetadata(), 0);
799 MachineInstr *Def = MRI.getVRegDef(Reg);
800 assert(Def && "Expecting an instruction that defines the register");
801 // G_GLOBAL_VALUE already has type info.
802 if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE)
803 updateRegType(Reg, Ty, nullptr, GR, MIB, MF.getRegInfo());
804 if (Def->getOpcode() == TargetOpcode::COPY && isVector1(Ty))
806 Ty, nullptr, GR, MIB, MF.getRegInfo());
807 ToErase.push_back(&MI);
808 } else if (MIOp == TargetOpcode::FAKE_USE && MI.getNumOperands() > 0) {
809 MachineInstr *MdMI = MI.getPrevNode();
810 if (MdMI && isSpvIntrinsic(*MdMI, Intrinsic::spv_value_md)) {
811 // It's an internal service info from before IRTranslator passes.
812 MachineInstr *Def = getVRegDef(MRI, MI.getOperand(0).getReg());
813 for (unsigned I = 1, E = MI.getNumOperands(); I != E && Def; ++I)
814 if (getVRegDef(MRI, MI.getOperand(I).getReg()) != Def)
815 Def = nullptr;
816 if (Def) {
817 const MDNode *MD = MdMI->getOperand(1).getMetadata();
819 cast<MDString>(MD->getOperand(1))->getString();
820 const MDNode *TypeMD = cast<MDNode>(MD->getOperand(0));
821 Type *ValueTy = getMDOperandAsType(TypeMD, 0);
822 GR->addValueAttrs(Def, std::make_pair(ValueTy, ValueName.str()));
823 }
824 ToErase.push_back(MdMI);
825 }
826 ToErase.push_back(&MI);
827 } else if (MIOp == TargetOpcode::G_CONSTANT ||
828 MIOp == TargetOpcode::G_FCONSTANT ||
829 MIOp == TargetOpcode::G_BUILD_VECTOR) {
830 // %rc = G_CONSTANT ty Val
831 // Ensure %rc has a valid SPIR-V type assigned in the Global Registry.
832 Register Reg = MI.getOperand(0).getReg();
833 bool NeedAssignType = !GR->getSPIRVTypeForVReg(Reg);
834 Type *Ty = nullptr;
835 if (MIOp == TargetOpcode::G_CONSTANT) {
836 auto TargetExtIt = TargetExtConstTypes.find(&MI);
837 Ty = TargetExtIt == TargetExtConstTypes.end()
838 ? MI.getOperand(1).getCImm()->getType()
839 : TargetExtIt->second;
840 const ConstantInt *OpCI = MI.getOperand(1).getCImm();
841 // TODO: we may wish to analyze here if OpCI is zero and LLT RegType =
842 // MRI.getType(Reg); RegType.isPointer() is true, so that we observe
843 // at this point not i64/i32 constant but null pointer in the
844 // corresponding address space of RegType.getAddressSpace(). This may
845 // help to successfully validate the case when a OpConstantComposite's
846 // constituent has type that does not match Result Type of
847 // OpConstantComposite (see, for example,
848 // pointers/PtrCast-null-in-OpSpecConstantOp.ll).
849 Register PrimaryReg = GR->find(OpCI, &MF);
850 if (!PrimaryReg.isValid()) {
851 GR->add(OpCI, &MI);
852 } else if (PrimaryReg != Reg &&
853 MRI.getType(Reg) == MRI.getType(PrimaryReg)) {
854 auto *RCReg = MRI.getRegClassOrNull(Reg);
855 auto *RCPrimary = MRI.getRegClassOrNull(PrimaryReg);
856 if (!RCReg || RCPrimary == RCReg) {
857 RegsAlreadyAddedToDT[&MI] = PrimaryReg;
858 ToErase.push_back(&MI);
859 NeedAssignType = false;
860 }
861 }
862 } else if (MIOp == TargetOpcode::G_FCONSTANT) {
863 Ty = MI.getOperand(1).getFPImm()->getType();
864 } else {
865 assert(MIOp == TargetOpcode::G_BUILD_VECTOR);
866 Type *ElemTy = nullptr;
867 MachineInstr *ElemMI = MRI.getVRegDef(MI.getOperand(1).getReg());
868 assert(ElemMI);
869
870 if (ElemMI->getOpcode() == TargetOpcode::G_CONSTANT) {
871 ElemTy = ElemMI->getOperand(1).getCImm()->getType();
872 } else if (ElemMI->getOpcode() == TargetOpcode::G_FCONSTANT) {
873 ElemTy = ElemMI->getOperand(1).getFPImm()->getType();
874 } else {
875 if (SPIRVTypeInst ElemSpvType =
876 GR->getSPIRVTypeForVReg(MI.getOperand(1).getReg(), &MF))
877 ElemTy = const_cast<Type *>(GR->getTypeForSPIRVType(ElemSpvType));
878 }
879 if (ElemTy)
880 Ty = VectorType::get(
881 ElemTy, MI.getNumExplicitOperands() - MI.getNumExplicitDefs(),
882 false);
883 else
884 NeedAssignType = false;
885 }
886 if (NeedAssignType)
887 updateRegType(Reg, Ty, nullptr, GR, MIB, MRI);
888 } else if (MIOp == TargetOpcode::G_GLOBAL_VALUE) {
889 propagateSPIRVType(&MI, GR, MRI, MIB);
890 }
891
892 if (MII == Begin)
893 ReachedBegin = true;
894 else
895 --MII;
896 }
897 }
898 for (MachineInstr *MI : ToErase) {
899 auto It = RegsAlreadyAddedToDT.find(MI);
900 if (It != RegsAlreadyAddedToDT.end())
901 MRI.replaceRegWith(MI->getOperand(0).getReg(), It->second);
903 }
904
905 // Address the case when IRTranslator introduces instructions with new
906 // registers without associated SPIRV type.
907 for (MachineBasicBlock &MBB : MF) {
908 for (MachineInstr &MI : MBB) {
909 switch (MI.getOpcode()) {
910 case TargetOpcode::G_TRUNC:
911 case TargetOpcode::G_ANYEXT:
912 case TargetOpcode::G_SEXT:
913 case TargetOpcode::G_ZEXT:
914 case TargetOpcode::G_PTRTOINT:
915 case TargetOpcode::COPY:
916 case TargetOpcode::G_ADDRSPACE_CAST:
917 propagateSPIRVType(&MI, GR, MRI, MIB);
918 break;
919 }
920 }
921 }
922}
923
926 MachineIRBuilder MIB) {
928 for (MachineBasicBlock &MBB : MF)
929 for (MachineInstr &MI : MBB)
930 if (isTypeFoldingSupported(MI.getOpcode()))
931 processInstr(MI, MIB, MRI, GR, nullptr);
932}
933
934static Register
936 SmallVector<unsigned, 4> *Ops = nullptr) {
937 Register DefReg;
938 unsigned StartOp = InlineAsm::MIOp_FirstOperand,
940 for (unsigned Idx = StartOp, MISz = MI->getNumOperands(); Idx != MISz;
941 ++Idx) {
942 const MachineOperand &MO = MI->getOperand(Idx);
943 if (MO.isMetadata())
944 continue;
945 if (Idx == AsmDescOp && MO.isImm()) {
946 // compute the index of the next operand descriptor
947 const InlineAsm::Flag F(MO.getImm());
948 AsmDescOp += 1 + F.getNumOperandRegisters();
949 continue;
950 }
951 if (MO.isReg() && MO.isDef()) {
952 if (!Ops)
953 return MO.getReg();
954 DefReg = MO.getReg();
955 } else if (Ops) {
956 Ops->push_back(Idx);
957 }
958 }
959 return DefReg;
960}
961
962static void
964 const SPIRVSubtarget &ST, MachineIRBuilder MIRBuilder,
965 const SmallVector<MachineInstr *> &ToProcess) {
967 Register AsmTargetReg;
968 for (unsigned i = 0, Sz = ToProcess.size(); i + 1 < Sz; i += 2) {
969 MachineInstr *I1 = ToProcess[i], *I2 = ToProcess[i + 1];
970 assert(isSpvIntrinsic(*I1, Intrinsic::spv_inline_asm) && I2->isInlineAsm());
971 MIRBuilder.setInsertPt(*I2->getParent(), *I2);
972
973 if (!AsmTargetReg.isValid()) {
974 // define vendor specific assembly target or dialect
975 AsmTargetReg = MRI.createGenericVirtualRegister(LLT::scalar(32));
976 MRI.setRegClass(AsmTargetReg, &SPIRV::iIDRegClass);
977 auto AsmTargetMIB =
978 MIRBuilder.buildInstr(SPIRV::OpAsmTargetINTEL).addDef(AsmTargetReg);
979 addStringImm(ST.getTargetTripleAsStr(), AsmTargetMIB);
980 GR->add(AsmTargetMIB.getInstr(), AsmTargetMIB);
981 }
982
983 // create types
984 const MDNode *IAMD = I1->getOperand(1).getMetadata();
987 for (const auto &ArgTy : FTy->params())
988 ArgTypes.push_back(GR->getOrCreateSPIRVType(
989 ArgTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite, true));
990 SPIRVTypeInst RetType =
991 GR->getOrCreateSPIRVType(FTy->getReturnType(), MIRBuilder,
992 SPIRV::AccessQualifier::ReadWrite, true);
994 FTy, RetType, ArgTypes, MIRBuilder);
995
996 // define vendor specific assembly instructions string
998 MRI.setRegClass(AsmReg, &SPIRV::iIDRegClass);
999 auto AsmMIB = MIRBuilder.buildInstr(SPIRV::OpAsmINTEL)
1000 .addDef(AsmReg)
1001 .addUse(GR->getSPIRVTypeID(RetType))
1002 .addUse(GR->getSPIRVTypeID(FuncType))
1003 .addUse(AsmTargetReg);
1004 // inline asm string:
1005 addStringImm(I2->getOperand(InlineAsm::MIOp_AsmString).getSymbolName(),
1006 AsmMIB);
1007 // inline asm constraint string:
1008 addStringImm(cast<MDString>(I1->getOperand(2).getMetadata()->getOperand(0))
1009 ->getString(),
1010 AsmMIB);
1011 GR->add(AsmMIB.getInstr(), AsmMIB);
1012
1013 // calls the inline assembly instruction
1014 unsigned ExtraInfo = I2->getOperand(InlineAsm::MIOp_ExtraInfo).getImm();
1015 if (ExtraInfo & InlineAsm::Extra_HasSideEffects)
1016 MIRBuilder.buildInstr(SPIRV::OpDecorate)
1017 .addUse(AsmReg)
1018 .addImm(static_cast<uint32_t>(SPIRV::Decoration::SideEffectsINTEL));
1019
1021 if (!DefReg.isValid()) {
1022 DefReg = MRI.createGenericVirtualRegister(LLT::scalar(32));
1023 MRI.setRegClass(DefReg, &SPIRV::iIDRegClass);
1024 SPIRVTypeInst VoidType = GR->getOrCreateSPIRVType(
1025 Type::getVoidTy(MF.getFunction().getContext()), MIRBuilder,
1026 SPIRV::AccessQualifier::ReadWrite, true);
1027 GR->assignSPIRVTypeToVReg(VoidType, DefReg, MF);
1028 }
1029
1030 auto AsmCall = MIRBuilder.buildInstr(SPIRV::OpAsmCallINTEL)
1031 .addDef(DefReg)
1032 .addUse(GR->getSPIRVTypeID(RetType))
1033 .addUse(AsmReg);
1034 for (unsigned IntrIdx = 3; IntrIdx < I1->getNumOperands(); ++IntrIdx)
1035 AsmCall.addUse(I1->getOperand(IntrIdx).getReg());
1036
1037 // IRTranslator gets a bit confused when lowering inline ASM with outputs
1038 // and inserts a spurious COPY & TRUNC as registers are assumed to be i64;
1039 // we have to clean that up here to prevent erroneous trunc casts either on
1040 // a struct (for multiple outputs) or same width integers to get lowered
1041 // into SPIR-V
1042 if (MRI.hasOneUse(DefReg)) {
1043 MachineInstr &CopyMI = *MRI.use_instr_begin(DefReg);
1044 if (CopyMI.getOpcode() == TargetOpcode::COPY) {
1045 Register CopyDst = CopyMI.getOperand(0).getReg();
1046 if (MRI.hasOneUse(CopyDst)) {
1047 MachineInstr &TruncMI = *MRI.use_instr_begin(CopyDst);
1048 if (TruncMI.getOpcode() == TargetOpcode::G_TRUNC) {
1049 MRI.setType(DefReg, GR->getRegType(RetType));
1050 Register TruncReg = TruncMI.defs().begin()->getReg();
1051 MRI.replaceRegWith(TruncReg, DefReg);
1052 invalidateAndEraseMI(GR, &TruncMI);
1053 invalidateAndEraseMI(GR, &CopyMI);
1054 }
1055 }
1056 }
1057 }
1058 }
1059 for (MachineInstr *MI : ToProcess)
1061}
1062
1064 const SPIRVSubtarget &ST,
1065 MachineIRBuilder MIRBuilder) {
1067 for (MachineBasicBlock &MBB : MF) {
1068 for (MachineInstr &MI : MBB) {
1069 if (isSpvIntrinsic(MI, Intrinsic::spv_inline_asm) ||
1070 MI.getOpcode() == TargetOpcode::INLINEASM)
1071 ToProcess.push_back(&MI);
1072 }
1073 }
1074 if (ToProcess.size() == 0)
1075 return;
1076
1077 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_inline_assembly))
1078 report_fatal_error("Inline assembly instructions require the "
1079 "following SPIR-V extension: SPV_INTEL_inline_assembly",
1080 false);
1081
1082 insertInlineAsmProcess(MF, GR, ST, MIRBuilder, ToProcess);
1083}
1084
1086 MachineIRBuilder MIB) {
1089 for (MachineBasicBlock &MBB : MF) {
1090 for (MachineInstr &MI : MBB) {
1091 if (!isSpvIntrinsic(MI, Intrinsic::spv_assign_decoration) &&
1092 !isSpvIntrinsic(MI, Intrinsic::spv_assign_aliasing_decoration) &&
1093 !isSpvIntrinsic(MI, Intrinsic::spv_assign_fpmaxerror_decoration))
1094 continue;
1095 MIB.setInsertPt(*MI.getParent(), MI.getNextNode());
1096 if (isSpvIntrinsic(MI, Intrinsic::spv_assign_decoration)) {
1097 buildOpSpirvDecorations(MI.getOperand(1).getReg(), MIB,
1098 MI.getOperand(2).getMetadata(), ST);
1099 } else if (isSpvIntrinsic(MI,
1100 Intrinsic::spv_assign_fpmaxerror_decoration)) {
1102 MI.getOperand(2).getMetadata()->getOperand(0));
1103 uint32_t OpValue = OpV->getValueAPF().bitcastToAPInt().getZExtValue();
1104
1105 buildOpDecorate(MI.getOperand(1).getReg(), MIB,
1106 SPIRV::Decoration::FPMaxErrorDecorationINTEL,
1107 {OpValue});
1108 } else {
1109 GR->buildMemAliasingOpDecorate(MI.getOperand(1).getReg(), MIB,
1110 MI.getOperand(2).getImm(),
1111 MI.getOperand(3).getMetadata());
1112 }
1113
1114 ToErase.push_back(&MI);
1115 }
1116 }
1117 for (MachineInstr *MI : ToErase)
1119}
1120
1121// LLVM allows the switches to use registers as cases, while SPIR-V required
1122// those to be immediate values. This function replaces such operands with the
1123// equivalent immediate constant.
1126 MachineIRBuilder MIB) {
1127 MachineRegisterInfo &MRI = MF.getRegInfo();
1128 for (MachineBasicBlock &MBB : MF) {
1129 for (MachineInstr &MI : MBB) {
1130 if (!isSpvIntrinsic(MI, Intrinsic::spv_switch))
1131 continue;
1132
1134 NewOperands.push_back(MI.getOperand(0)); // Opcode
1135 NewOperands.push_back(MI.getOperand(1)); // Condition
1136 NewOperands.push_back(MI.getOperand(2)); // Default
1137 for (unsigned i = 3; i < MI.getNumOperands(); i += 2) {
1138 Register Reg = MI.getOperand(i).getReg();
1139 MachineInstr *ConstInstr = getDefInstrMaybeConstant(Reg, &MRI);
1140 NewOperands.push_back(
1142
1143 NewOperands.push_back(MI.getOperand(i + 1));
1144 }
1145
1146 assert(MI.getNumOperands() == NewOperands.size());
1147 while (MI.getNumOperands() > 0)
1148 MI.removeOperand(0);
1149 for (auto &MO : NewOperands)
1150 MI.addOperand(MO);
1151 }
1152 }
1153}
1154
1155// Some instructions are used during CodeGen but should never be emitted.
1156// Cleaning up those.
1158 SPIRVGlobalRegistry *GR) {
1160 for (MachineBasicBlock &MBB : MF) {
1161 for (MachineInstr &MI : MBB) {
1162 if (isSpvIntrinsic(MI, Intrinsic::spv_track_constant) ||
1163 MI.getOpcode() == TargetOpcode::G_BRINDIRECT)
1164 ToEraseMI.push_back(&MI);
1165 }
1166 }
1167
1168 for (MachineInstr *MI : ToEraseMI)
1170}
1171
1172// Find all usages of G_BLOCK_ADDR in our intrinsics and replace those
1173// operands/registers by the actual MBB it references.
1175 MachineIRBuilder MIB) {
1176 // Gather the reverse-mapping BB -> MBB.
1178 for (MachineBasicBlock &MBB : MF)
1179 BB2MBB[MBB.getBasicBlock()] = &MBB;
1180
1181 // Gather instructions requiring patching. For now, only those can use
1182 // G_BLOCK_ADDR.
1183 SmallVector<MachineInstr *, 8> InstructionsToPatch;
1184 for (MachineBasicBlock &MBB : MF) {
1185 for (MachineInstr &MI : MBB) {
1186 if (isSpvIntrinsic(MI, Intrinsic::spv_switch) ||
1187 isSpvIntrinsic(MI, Intrinsic::spv_loop_merge) ||
1188 isSpvIntrinsic(MI, Intrinsic::spv_selection_merge))
1189 InstructionsToPatch.push_back(&MI);
1190 }
1191 }
1192
1193 // For each instruction to fix, we replace all the G_BLOCK_ADDR operands by
1194 // the actual MBB it references. Once those references have been updated, we
1195 // can cleanup remaining G_BLOCK_ADDR references.
1196 SmallPtrSet<MachineBasicBlock *, 8> ClearAddressTaken;
1198 MachineRegisterInfo &MRI = MF.getRegInfo();
1199 for (MachineInstr *MI : InstructionsToPatch) {
1201 for (unsigned i = 0; i < MI->getNumOperands(); ++i) {
1202 // The operand is not a register, keep as-is.
1203 if (!MI->getOperand(i).isReg()) {
1204 NewOps.push_back(MI->getOperand(i));
1205 continue;
1206 }
1207
1208 Register Reg = MI->getOperand(i).getReg();
1209 MachineInstr *BuildMBB = MRI.getVRegDef(Reg);
1210 // The register is not the result of G_BLOCK_ADDR, keep as-is.
1211 if (!BuildMBB || BuildMBB->getOpcode() != TargetOpcode::G_BLOCK_ADDR) {
1212 NewOps.push_back(MI->getOperand(i));
1213 continue;
1214 }
1215
1216 assert(BuildMBB && BuildMBB->getOpcode() == TargetOpcode::G_BLOCK_ADDR &&
1217 BuildMBB->getOperand(1).isBlockAddress() &&
1218 BuildMBB->getOperand(1).getBlockAddress());
1219 BasicBlock *BB =
1220 BuildMBB->getOperand(1).getBlockAddress()->getBasicBlock();
1221 auto It = BB2MBB.find(BB);
1222 if (It == BB2MBB.end())
1223 report_fatal_error("cannot find a machine basic block by a basic block "
1224 "in a switch statement");
1225 MachineBasicBlock *ReferencedBlock = It->second;
1226 NewOps.push_back(MachineOperand::CreateMBB(ReferencedBlock));
1227
1228 ClearAddressTaken.insert(ReferencedBlock);
1229 ToEraseMI.insert(BuildMBB);
1230 }
1231
1232 // Replace the operands.
1233 assert(MI->getNumOperands() == NewOps.size());
1234 while (MI->getNumOperands() > 0)
1235 MI->removeOperand(0);
1236 for (auto &MO : NewOps)
1237 MI->addOperand(MO);
1238
1239 if (MachineInstr *Next = MI->getNextNode()) {
1240 if (isSpvIntrinsic(*Next, Intrinsic::spv_track_constant)) {
1241 ToEraseMI.insert(Next);
1242 Next = MI->getNextNode();
1243 }
1244 if (Next && Next->getOpcode() == TargetOpcode::G_BRINDIRECT)
1245 ToEraseMI.insert(Next);
1246 }
1247 }
1248
1249 // BlockAddress operands were used to keep information between passes,
1250 // let's undo the "address taken" status to reflect that Succ doesn't
1251 // actually correspond to an IR-level basic block.
1252 for (MachineBasicBlock *Succ : ClearAddressTaken)
1253 Succ->setAddressTakenIRBlock(nullptr);
1254
1255 // If we just delete G_BLOCK_ADDR instructions with BlockAddress operands,
1256 // this leaves their BasicBlock counterparts in a "address taken" status. This
1257 // would make AsmPrinter to generate a series of unneeded labels of a "Address
1258 // of block that was removed by CodeGen" kind. Let's first ensure that we
1259 // don't have a dangling BlockAddress constants by zapping the BlockAddress
1260 // nodes, and only after that proceed with erasing G_BLOCK_ADDR instructions.
1261 Constant *Replacement =
1262 ConstantInt::get(Type::getInt32Ty(MF.getFunction().getContext()), 1);
1263 for (MachineInstr *BlockAddrI : ToEraseMI) {
1264 if (BlockAddrI->getOpcode() == TargetOpcode::G_BLOCK_ADDR) {
1265 BlockAddress *BA = const_cast<BlockAddress *>(
1266 BlockAddrI->getOperand(1).getBlockAddress());
1268 ConstantExpr::getIntToPtr(Replacement, BA->getType()));
1269 BA->destroyConstant();
1270 }
1271 invalidateAndEraseMI(GR, BlockAddrI);
1272 }
1273}
1274
1276 if (MBB.empty())
1277 return MBB.getNextNode() != nullptr;
1278
1279 // Branching SPIR-V intrinsics are not detected by this generic method.
1280 // Thus, we can only trust negative result.
1281 if (!MBB.canFallThrough())
1282 return false;
1283
1284 // Otherwise, we must manually check if we have a SPIR-V intrinsic which
1285 // prevent an implicit fallthrough.
1286 for (MachineBasicBlock::reverse_iterator It = MBB.rbegin(), E = MBB.rend();
1287 It != E; ++It) {
1288 if (isSpvIntrinsic(*It, Intrinsic::spv_switch))
1289 return false;
1290 }
1291 return true;
1292}
1293
1295 MachineIRBuilder MIB) {
1296 // It is valid for MachineBasicBlocks to not finish with a branch instruction.
1297 // In such cases, they will simply fallthrough their immediate successor.
1298 for (MachineBasicBlock &MBB : MF) {
1300 continue;
1301
1302 assert(MBB.succ_size() == 1);
1303 MIB.setInsertPt(MBB, MBB.end());
1304 MIB.buildBr(**MBB.successors().begin());
1305 }
1306}
1307
1309 // Initialize the type registry.
1310 const SPIRVSubtarget &ST = MF.getSubtarget<SPIRVSubtarget>();
1311 SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
1312 GR->setCurrentFunc(MF);
1313 MachineIRBuilder MIB(MF);
1314 // a registry of target extension constants
1315 DenseMap<MachineInstr *, Type *> TargetExtConstTypes;
1316 // to keep record of tracked constants
1317 addConstantsToTrack(MF, GR, ST, TargetExtConstTypes);
1318 foldConstantsIntoIntrinsics(MF, GR, MIB);
1319 insertBitcasts(MF, GR, MIB);
1320 generateAssignInstrs(MF, GR, MIB, TargetExtConstTypes);
1321
1322 processSwitchesConstants(MF, GR, MIB);
1323 processBlockAddr(MF, GR, MIB);
1325
1326 processInstrsWithTypeFolding(MF, GR, MIB);
1328 insertSpirvDecorations(MF, GR, MIB);
1329 insertInlineAsm(MF, GR, ST, MIB);
1330 lowerBitcasts(MF, GR, MIB);
1331
1332 return true;
1333}
1334
1335INITIALIZE_PASS(SPIRVPreLegalizerLegacy, DEBUG_TYPE, "SPIRV pre legalizer",
1336 false, false)
1337
1338char SPIRVPreLegalizerLegacy::ID = 0;
1339
1340FunctionPass *llvm::createSPIRVPreLegalizerLegacyPass() {
1341 return new SPIRVPreLegalizerLegacy();
1342}
1343
1344bool SPIRVPreLegalizerLegacy::runOnMachineFunction(MachineFunction &MF) {
1345 return runPreLegalizer(MF);
1346}
1347
1348PreservedAnalyses
MachineInstrBuilder & UseMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock & MBB
This file contains the simple types necessary to represent the attributes associated with functions a...
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
Provides analysis for continuously CSEing during GISel passes.
This file contains the declarations for the subclasses of Constant, which represent the different fla...
Provides analysis for querying information about KnownBits during GISel passes.
#define DEBUG_TYPE
IRTranslator LLVM IR MI
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Register Reg
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
static Register collectInlineAsmInstrOperands(MachineInstr *MI, SmallVector< unsigned, 4 > *Ops=nullptr)
static void insertInlineAsm(MachineFunction &MF, SPIRVGlobalRegistry *GR, const SPIRVSubtarget &ST, MachineIRBuilder MIRBuilder)
static void cleanupHelperInstructions(MachineFunction &MF, SPIRVGlobalRegistry *GR)
static void insertInlineAsmProcess(MachineFunction &MF, SPIRVGlobalRegistry *GR, const SPIRVSubtarget &ST, MachineIRBuilder MIRBuilder, const SmallVector< MachineInstr * > &ToProcess)
static bool runPreLegalizer(MachineFunction &MF)
static void removeImplicitFallthroughs(MachineFunction &MF, MachineIRBuilder MIB)
static unsigned widenBitWidthToNextPow2(unsigned BitWidth)
static void setInsertPtAfterDef(MachineIRBuilder &MIB, MachineInstr *Def)
static bool isImplicitFallthrough(MachineBasicBlock &MBB)
static void insertSpirvDecorations(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
static void insertBitcasts(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
static void processInstrsWithTypeFolding(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
static void processSwitchesConstants(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
static void lowerBitcasts(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
static MachineInstr * findAssignTypeInstr(Register Reg, MachineRegisterInfo *MRI)
static void widenCImmType(MachineOperand &MOP)
static void buildOpBitcast(SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB, Register ResVReg, Register OpReg)
static SignSensitiveWideningInfo recordSignSensitiveOperandWidths(MachineFunction &MF, MachineRegisterInfo &MRI)
static void processBlockAddr(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
static void widenScalarType(Register Reg, MachineRegisterInfo &MRI)
static void foldConstantsIntoIntrinsics(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
static void addConstantsToTrack(MachineFunction &MF, SPIRVGlobalRegistry *GR, const SPIRVSubtarget &STI, DenseMap< MachineInstr *, Type * > &TargetExtConstTypes)
static SPIRVTypeInst propagateSPIRVType(MachineInstr *MI, SPIRVGlobalRegistry *GR, MachineRegisterInfo &MRI, MachineIRBuilder &MIB)
static bool isSignSensitiveOp(const MachineInstr &MI)
static void invalidateAndEraseMI(SPIRVGlobalRegistry *GR, MachineInstr *MI)
static void generateAssignInstrs(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB, DenseMap< MachineInstr *, Type * > &TargetExtConstTypes)
static void widenSignSensitiveOps(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB, MachineRegisterInfo &MRI, const SignSensitiveWideningInfo &Info)
Value * RHS
Value * LHS
APInt bitcastToAPInt() const
Definition APFloat.h:1467
Class for arbitrary precision integers.
Definition APInt.h:78
uint64_t getZExtValue() const
Get zero extended value.
Definition APInt.h:1561
LLVM_ABI APInt zextOrTrunc(unsigned width) const
Zero extend or truncate to width.
Definition APInt.cpp:1077
static APInt getLowBitsSet(unsigned numBits, unsigned loBitsSet)
Constructs an APInt value that has the bottom loBitsSet bits set.
Definition APInt.h:303
Represent the analysis usage information of a pass.
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
LLVM Basic Block Representation.
Definition BasicBlock.h:62
The address of a basic block.
Definition Constants.h:1088
BasicBlock * getBasicBlock() const
Definition Constants.h:1125
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
Definition InstrTypes.h:740
bool isSigned() const
Definition InstrTypes.h:993
static LLVM_ABI Constant * getIntToPtr(Constant *C, Type *Ty, bool OnlyIfReduced=false)
ConstantFP - Floating Point Values [float, double].
Definition Constants.h:420
const APFloat & getValueAPF() const
Definition Constants.h:463
This is the shared class of boolean and integer constants.
Definition Constants.h:87
unsigned getBitWidth() const
getBitWidth - Return the scalar bitwidth of this constant.
Definition Constants.h:162
const APInt & getValue() const
Return the constant as an APInt value reference.
Definition Constants.h:159
This is an important base class in LLVM.
Definition Constant.h:43
LLVM_ABI void destroyConstant()
Called if some element of this constant is no longer valid.
iterator find(const_arg_type_t< KeyT > Val)
Definition DenseMap.h:223
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
Definition DenseMap.h:299
bool erase(const KeyT &Val)
Definition DenseMap.h:377
iterator end()
Definition DenseMap.h:141
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:353
constexpr unsigned getScalarSizeInBits() const
constexpr bool isScalar() const
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr bool isValid() const
constexpr uint16_t getNumElements() const
Returns the number of elements in a vector LLT.
constexpr bool isVector() const
constexpr ElementCount getElementCount() const
LLT changeElementSize(unsigned NewEltSize) const
If this type is a vector, return a vector with the same number of elements but the new element size.
Metadata node.
Definition Metadata.h:1069
const MDOperand & getOperand(unsigned I) const
Definition Metadata.h:1426
LLVM_ABI iterator getFirstNonPHI()
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
MachineInstrBundleIterator< MachineInstr, true > reverse_iterator
MachineInstrBundleIterator< MachineInstr > iterator
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
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.
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineBasicBlock & front() const
Helper class to build MachineInstr.
MachineInstrBuilder buildBr(MachineBasicBlock &Dest)
Build and insert G_BR Dest.
void setInsertPt(MachineBasicBlock &MBB, MachineBasicBlock::iterator II)
Set the insertion point before the specified position.
MachineInstrBuilder buildAnd(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1)
Build and insert Res = G_AND Op0, Op1.
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineInstrBuilder buildBuildVectorConstant(const DstOp &Res, ArrayRef< APInt > Ops)
Build and insert Res = G_BUILD_VECTOR Op0, ... where each OpN is built with G_CONSTANT.
MachineFunction & getMF()
Getter for the function we currently build.
MachineInstrBuilder buildBitcast(const DstOp &Dst, const SrcOp &Src)
Build and insert Dst = G_BITCAST Src.
MachineRegisterInfo * getMRI()
Getter for MRI.
MachineInstrBuilder buildCopy(const DstOp &Res, const SrcOp &Op)
Build and insert Res = COPY Op.
virtual MachineInstrBuilder buildConstant(const DstOp &Res, const ConstantInt &Val)
Build and insert Res = G_CONSTANT Val.
MachineInstrBuilder buildSExtInReg(const DstOp &Res, const SrcOp &Op, int64_t ImmOp)
Build and insert Res = G_SEXT_INREG Op, ImmOp.
const MachineInstrBuilder & addUse(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addDef(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register definition operand.
Representation of each machine instruction.
mop_range defs()
Returns all explicit operands that are register definitions.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
LLVM_ABI void addOperand(MachineFunction &MF, const MachineOperand &Op)
Add the specified operand to the instruction.
LLVM_ABI void setDesc(const MCInstrDesc &TID)
Replace the instruction descriptor (thus opcode) of the current instruction with a new one.
const MachineOperand & getOperand(unsigned i) const
MachineOperand class - Representation of each machine instruction operand.
const ConstantInt * getCImm() const
int64_t getImm() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
const MDNode * getMetadata() const
static MachineOperand CreateCImm(const ConstantInt *CI)
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
bool isMetadata() const
isMetadata - Tests if this is a MO_Metadata operand.
const BlockAddress * getBlockAddress() const
void setCImm(const ConstantInt *CI)
bool isBlockAddress() const
isBlockAddress - Tests if this is a MO_BlockAddress operand.
Register getReg() const
getReg - Returns the register number.
const ConstantFP * getFPImm() const
static MachineOperand CreateReg(Register Reg, bool isDef, bool isImp=false, bool isKill=false, bool isDead=false, bool isUndef=false, bool isEarlyClobber=false, unsigned SubReg=0, bool isDebug=false, bool isInternalRead=false, bool isRenamable=false)
static MachineOperand CreateMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0)
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
defusechain_instr_iterator< true, false, false, true > use_instr_iterator
use_instr_iterator/use_instr_begin/use_instr_end - Walk all uses of the specified register,...
LLVM_ABI LLVM_READONLY MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
use_instr_iterator use_instr_begin(Register RegNo) const
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
bool hasOneUse(Register RegNo) const
hasOneUse - Return true if there is exactly one instruction using the specified register.
static use_instr_iterator use_instr_end()
LLVM_ABI void setType(Register VReg, LLT Ty)
Set the low-level type of VReg to Ty.
LLVM_ABI void setRegClass(Register Reg, const TargetRegisterClass *RC)
setRegClass - Set the register class of the specified virtual register.
LLVM_ABI Register createGenericVirtualRegister(LLT Ty, StringRef Name="")
Create and return a new generic virtual register with low-level type Ty.
const TargetRegisterClass * getRegClassOrNull(Register Reg) const
Return the register class of Reg, or null if Reg has not been assigned a register class yet.
LLVM_ABI void replaceRegWith(Register FromReg, Register ToReg)
replaceRegWith - Replace all instances of FromReg with ToReg in the machine function.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
PreservedAnalyses & preserve()
Mark an analysis as preserved.
Definition Analysis.h:132
Wrapper class representing virtual and physical registers.
Definition Register.h:20
constexpr bool isValid() const
Definition Register.h:112
void assignSPIRVTypeToVReg(SPIRVTypeInst Type, Register VReg, const MachineFunction &MF)
SPIRVTypeInst getOrCreateOpTypeFunctionWithArgs(const Type *Ty, SPIRVTypeInst RetType, const SmallVectorImpl< SPIRVTypeInst > &ArgTypes, MachineIRBuilder &MIRBuilder)
SPIRVTypeInst getOrCreateSPIRVPointerType(const Type *BaseType, MachineIRBuilder &MIRBuilder, SPIRV::StorageClass::StorageClass SC, bool ForceTyped=false)
const TargetRegisterClass * getRegClass(SPIRVTypeInst SpvType) const
unsigned getScalarOrVectorBitWidth(SPIRVTypeInst Type) const
void setUntypedPtrElementType(Register Reg, SPIRVTypeInst ElemType)
SPIRVTypeInst getOrCreateSPIRVIntegerType(unsigned BitWidth, MachineIRBuilder &MIRBuilder)
SPIRVTypeInst getOrCreateSPIRVVectorType(SPIRVTypeInst BaseType, unsigned NumElements, MachineIRBuilder &MIRBuilder, bool EmitIR)
unsigned getScalarOrVectorComponentCount(Register VReg) const
const Type * getTypeForSPIRVType(SPIRVTypeInst Ty) const
bool isBitcastCompatible(SPIRVTypeInst Type1, SPIRVTypeInst Type2) const
LLT getRegType(SPIRVTypeInst SpvType) const
void invalidateMachineInstr(MachineInstr *MI)
Register getSPIRVTypeID(SPIRVTypeInst SpirvType) const
SPIRVTypeInst changePointerStorageClass(SPIRVTypeInst PtrType, SPIRV::StorageClass::StorageClass SC, MachineInstr &I)
void addGlobalObject(const Value *V, const MachineFunction *MF, Register R)
SPIRVTypeInst getOrCreateSPIRVType(const Type *Type, MachineInstr &I, SPIRV::AccessQualifier::AccessQualifier AQ, bool EmitIR)
SPIRVTypeInst getSPIRVTypeForVReg(Register VReg, const MachineFunction *MF=nullptr) const
Type * getDeducedGlobalValueType(const GlobalValue *Global)
void addValueAttrs(MachineInstr *Key, std::pair< Type *, std::string > Val)
void buildMemAliasingOpDecorate(Register Reg, MachineIRBuilder &MIRBuilder, uint32_t Dec, const MDNode *GVarMD)
SPIRV::StorageClass::StorageClass getPointerStorageClass(Register VReg) const
SPIRVTypeInst getUntypedPtrElementType(Register Reg) const
bool add(SPIRV::IRHandle Handle, const MachineInstr *MI)
Register find(SPIRV::IRHandle Handle, const MachineFunction *MF)
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
const SPIRVInstrInfo * getInstrInfo() const override
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
Definition Type.cpp:309
static LLVM_ABI Type * getVoidTy(LLVMContext &C)
Definition Type.cpp:282
LLVMContext & getContext() const
Return the LLVMContext in which this type was uniqued.
Definition Type.h:130
static LLVM_ABI TypedPointerType * get(Type *ElementType, unsigned AddressSpace)
This constructs a pointer to an object of the specified type in a numbered address space.
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:255
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition Value.cpp:553
static LLVM_ABI VectorType * get(Type *ElementType, ElementCount EC)
This static method is the primary way to construct an VectorType.
IteratorT begin() const
Changed
Pass manager infrastructure for declaring and invalidating analyses.
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > dyn_extract(Y &&MD)
Extract a Value from Metadata, if any.
Definition Metadata.h:696
This is an optimization pass for GlobalISel generic memory operations.
StringMapEntry< Value * > ValueName
Definition Value.h:56
void addStringImm(StringRef Str, MCInst &Inst)
bool isTypeFoldingSupported(unsigned Opcode)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
void updateRegType(Register Reg, Type *Ty, SPIRVTypeInst SpirvTy, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB, MachineRegisterInfo &MRI)
Helper external function for assigning a SPIRV type to a register, ensuring the register class and ty...
void buildOpDecorate(Register Reg, MachineIRBuilder &MIRBuilder, SPIRV::Decoration::Decoration Dec, ArrayRef< uint32_t > DecArgs, StringRef StrImm)
constexpr unsigned storageClassToAddressSpace(SPIRV::StorageClass::StorageClass SC)
Definition SPIRVUtils.h:245
uint64_t PowerOf2Ceil(uint64_t A)
Returns the power of two which is greater than or equal to the given value.
Definition MathExtras.h:380
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
void buildOpName(Register Target, StringRef Name, MachineIRBuilder &MIRBuilder)
Type * toTypedPointer(Type *Ty)
Definition SPIRVUtils.h:479
bool isVector1(Type *Ty)
Definition SPIRVUtils.h:512
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
auto post_order(const T &G)
Post-order traversal of a graph.
MachineInstr * passCopy(MachineInstr *Def, const MachineRegisterInfo *MRI)
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
@ Global
Append to llvm.global_dtors.
SPIRV::StorageClass::StorageClass addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI)
void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder, const MDNode *GVarMD, const SPIRVSubtarget &ST)
void processInstr(MachineInstr &MI, MachineIRBuilder &MIB, MachineRegisterInfo &MRI, SPIRVGlobalRegistry *GR, SPIRVTypeInst KnownResType)
DWARFExpression::Operation Op
MachineInstr * getDefInstrMaybeConstant(Register &ConstReg, const MachineRegisterInfo *MRI)
constexpr unsigned BitWidth
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
Type * getMDOperandAsType(const MDNode *N, unsigned I)
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Next
Definition InstrProf.h:147
FunctionPass * createSPIRVPreLegalizerLegacyPass()
bool isSpvIntrinsic(const MachineInstr &MI, Intrinsic::ID IntrinsicID)
MachineInstr * getVRegDef(MachineRegisterInfo &MRI, Register Reg)
#define N
SmallVector< MachineInstr * > Worklist
DenseMap< Register, unsigned > OrigWidth