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"
24#include "llvm/IR/Analysis.h"
25#include "llvm/IR/Attributes.h"
26#include "llvm/IR/Constants.h"
27#include "llvm/IR/InstrTypes.h"
28#include "llvm/IR/IntrinsicsSPIRV.h"
30
31#define DEBUG_TYPE "spirv-prelegalizer"
32
33using namespace llvm;
34using namespace llvm::MIPatternMatch;
35
36namespace {
37class SPIRVPreLegalizerLegacy : public MachineFunctionPass {
38public:
39 static char ID;
40 SPIRVPreLegalizerLegacy() : MachineFunctionPass(ID) {}
41 bool runOnMachineFunction(MachineFunction &MF) override;
42 void getAnalysisUsage(AnalysisUsage &AU) const override;
43};
44} // namespace
45
46void SPIRVPreLegalizerLegacy::getAnalysisUsage(AnalysisUsage &AU) const {
47 AU.addPreserved<GISelValueTrackingAnalysisLegacy>();
49}
50
54 MI->eraseFromParent();
55}
56
57static void
59 const SPIRVSubtarget &STI,
60 DenseMap<MachineInstr *, Type *> &TargetExtConstTypes) {
62 DenseMap<MachineInstr *, Register> RegsAlreadyAddedToDT;
63 SmallVector<MachineInstr *, 10> ToErase, ToEraseComposites;
64 for (MachineBasicBlock &MBB : MF) {
65 for (MachineInstr &MI : MBB) {
66 if (!isSpvIntrinsic(MI, Intrinsic::spv_track_constant))
67 continue;
68 ToErase.push_back(&MI);
69 Register SrcReg = MI.getOperand(2).getReg();
70 auto *Const =
72 MI.getOperand(3).getMetadata()->getOperand(0))
73 ->getValue());
74 if (auto *GV = dyn_cast<GlobalValue>(Const)) {
75 Register Reg = GR->find(GV, &MF);
76 if (!Reg.isValid()) {
77 GR->add(GV, MRI.getVRegDef(SrcReg));
78 GR->addGlobalObject(GV, &MF, SrcReg);
79 } else
80 RegsAlreadyAddedToDT[&MI] = Reg;
81 } else {
82 Register Reg = GR->find(Const, &MF);
83 if (!Reg.isValid()) {
84 if (auto *ConstVec = dyn_cast<ConstantDataVector>(Const)) {
85 auto *BuildVec = MRI.getVRegDef(SrcReg);
86 assert(BuildVec &&
87 BuildVec->getOpcode() == TargetOpcode::G_BUILD_VECTOR);
88 GR->add(Const, BuildVec);
89 for (unsigned i = 0; i < ConstVec->getNumElements(); ++i) {
90 // Ensure that OpConstantComposite reuses a constant when it's
91 // already created and available in the same machine function.
92 Constant *ElemConst = ConstVec->getElementAsConstant(i);
93 Register ElemReg = GR->find(ElemConst, &MF);
94 if (!ElemReg.isValid())
95 GR->add(ElemConst,
96 MRI.getVRegDef(BuildVec->getOperand(1 + i).getReg()));
97 else
98 BuildVec->getOperand(1 + i).setReg(ElemReg);
99 }
100 }
101 if (Const->getType()->isTargetExtTy()) {
102 // remember association so that we can restore it when assign types
103 MachineInstr *SrcMI = MRI.getVRegDef(SrcReg);
104 if (SrcMI)
105 GR->add(Const, SrcMI);
106 if (SrcMI && (SrcMI->getOpcode() == TargetOpcode::G_CONSTANT ||
107 SrcMI->getOpcode() == TargetOpcode::G_IMPLICIT_DEF))
108 TargetExtConstTypes[SrcMI] = Const->getType();
109 if (Const->isNullValue()) {
110 MachineBasicBlock &DepMBB = MF.front();
111 MachineIRBuilder MIB(DepMBB, DepMBB.getFirstNonPHI());
113 Const->getType(), MIB, SPIRV::AccessQualifier::ReadWrite,
114 true);
115 assert(SrcMI && "Expected source instruction to be valid");
116 SrcMI->setDesc(STI.getInstrInfo()->get(SPIRV::OpConstantNull));
118 GR->getSPIRVTypeID(ExtType), false));
119 }
120 }
121 } else {
122 RegsAlreadyAddedToDT[&MI] = Reg;
123 // This MI is unused and will be removed. If the MI uses
124 // const_composite, it will be unused and should be removed too.
125 assert(MI.getOperand(2).isReg() && "Reg operand is expected");
126 MachineInstr *SrcMI = MRI.getVRegDef(MI.getOperand(2).getReg());
127 if (SrcMI && isSpvIntrinsic(*SrcMI, Intrinsic::spv_const_composite))
128 ToEraseComposites.push_back(SrcMI);
129 }
130 }
131 }
132 }
133 for (MachineInstr *MI : ToErase) {
134 Register Reg = MI->getOperand(2).getReg();
135 auto It = RegsAlreadyAddedToDT.find(MI);
136 if (It != RegsAlreadyAddedToDT.end())
137 Reg = It->second;
138 auto *RC = MRI.getRegClassOrNull(MI->getOperand(0).getReg());
139 if (!MRI.getRegClassOrNull(Reg) && RC)
140 MRI.setRegClass(Reg, RC);
141 MRI.replaceRegWith(MI->getOperand(0).getReg(), Reg);
143 }
144 for (MachineInstr *MI : ToEraseComposites)
146}
147
150 MachineIRBuilder MIB) {
152 for (MachineBasicBlock &MBB : MF) {
153 for (MachineInstr &MI : MBB) {
154 if (!isSpvIntrinsic(MI, Intrinsic::spv_assign_name))
155 continue;
156 const MDNode *MD = MI.getOperand(2).getMetadata();
157 StringRef ValueName = cast<MDString>(MD->getOperand(0))->getString();
158 if (ValueName.size() > 0) {
159 MIB.setInsertPt(*MI.getParent(), MI);
160 buildOpName(MI.getOperand(1).getReg(), ValueName, MIB);
161 }
162 ToErase.push_back(&MI);
163 }
164 for (MachineInstr *MI : ToErase)
166 ToErase.clear();
167 }
168}
169
171 MachineRegisterInfo *MRI) {
173 IE = MRI->use_instr_end();
174 I != IE; ++I) {
175 MachineInstr *UseMI = &*I;
176 if ((isSpvIntrinsic(*UseMI, Intrinsic::spv_assign_ptr_type) ||
177 isSpvIntrinsic(*UseMI, Intrinsic::spv_assign_type)) &&
178 UseMI->getOperand(1).getReg() == Reg)
179 return UseMI;
180 }
181 return nullptr;
182}
183
185 Register ResVReg, Register OpReg) {
186 SPIRVTypeInst ResType = GR->getSPIRVTypeForVReg(ResVReg);
187 SPIRVTypeInst OpType = GR->getSPIRVTypeForVReg(OpReg);
188 assert(ResType && OpType && "Operand types are expected");
189 if (!GR->isBitcastCompatible(ResType, OpType))
190 report_fatal_error("incompatible result and operand types in a bitcast");
191 MachineRegisterInfo *MRI = MIB.getMRI();
192 if (!MRI->getRegClassOrNull(ResVReg))
193 MRI->setRegClass(ResVReg, GR->getRegClass(ResType));
194 if (ResType == OpType)
195 MIB.buildInstr(TargetOpcode::COPY).addDef(ResVReg).addUse(OpReg);
196 else
197 MIB.buildInstr(SPIRV::OpBitcast)
198 .addDef(ResVReg)
199 .addUse(GR->getSPIRVTypeID(ResType))
200 .addUse(OpReg);
201}
202
203// We lower G_BITCAST to OpBitcast here to avoid a MachineVerifier error.
204// The verifier checks if the source and destination LLTs of a G_BITCAST are
205// different, but this check is too strict for SPIR-V's typed pointers, which
206// may have the same LLT but different SPIRV type (e.g. pointers to different
207// pointee types). By lowering to OpBitcast here, we bypass the verifier's
208// check. See discussion in https://github.com/llvm/llvm-project/pull/110270
209// for more context.
210//
211// We also handle the llvm.spv.bitcast intrinsic here. If the source and
212// destination SPIR-V types are the same, we lower it to a COPY to enable
213// further optimizations like copy propagation.
215 MachineIRBuilder MIB) {
217 for (MachineBasicBlock &MBB : MF) {
218 for (MachineInstr &MI : MBB) {
219 if (isSpvIntrinsic(MI, Intrinsic::spv_bitcast)) {
220 Register DstReg = MI.getOperand(0).getReg();
221 Register SrcReg = MI.getOperand(2).getReg();
222 SPIRVTypeInst DstType = GR->getSPIRVTypeForVReg(DstReg);
223 assert(
224 DstType &&
225 "Expected destination SPIR-V type to have been assigned already.");
226 SPIRVTypeInst SrcType = GR->getSPIRVTypeForVReg(SrcReg);
227 assert(SrcType &&
228 "Expected source SPIR-V type to have been assigned already.");
229 if (DstType == SrcType) {
230 MIB.setInsertPt(*MI.getParent(), MI);
231 MIB.buildCopy(DstReg, SrcReg);
232 ToErase.push_back(&MI);
233 continue;
234 }
235 }
236
237 if (MI.getOpcode() != TargetOpcode::G_BITCAST)
238 continue;
239
240 MIB.setInsertPt(*MI.getParent(), MI);
241 buildOpBitcast(GR, MIB, MI.getOperand(0).getReg(),
242 MI.getOperand(1).getReg());
243 ToErase.push_back(&MI);
244 }
245 }
246 for (MachineInstr *MI : ToErase)
248}
249
251 MachineIRBuilder MIB) {
252 // Get access to information about available extensions
253 const SPIRVSubtarget *ST =
254 static_cast<const SPIRVSubtarget *>(&MIB.getMF().getSubtarget());
256 for (MachineBasicBlock &MBB : MF) {
257 for (MachineInstr &MI : MBB) {
258 if (!isSpvIntrinsic(MI, Intrinsic::spv_ptrcast))
259 continue;
260 assert(MI.getOperand(2).isReg());
261 MIB.setInsertPt(*MI.getParent(), MI);
262 ToErase.push_back(&MI);
263 Register Def = MI.getOperand(0).getReg();
264 Register Source = MI.getOperand(2).getReg();
265 Type *ElemTy = getMDOperandAsType(MI.getOperand(3).getMetadata(), 0);
266 auto SC =
268 ST->canUseExtension(
269 SPIRV::Extension::SPV_INTEL_function_pointers)
270 ? SPIRV::StorageClass::CodeSectionINTEL
271 : addressSpaceToStorageClass(MI.getOperand(4).getImm(), *ST);
272 SPIRVTypeInst AssignedPtrType =
274
275 // If the ptrcast would be redundant, replace all uses with the source
276 // register.
277 MachineRegisterInfo *MRI = MIB.getMRI();
278 // For untyped pointers the SPIR-V pointer type does not encode the
279 // pointee, so two pointers with different element types share the same
280 // pointer type. The element type still matters because it selects the
281 // Base Type operand of OpUntyped*AccessChainKHR. Treat the cast as
282 // redundant only when the source already carries the same element type.
283 // Otherwise keep a distinct register so the element type is preserved.
284 bool Redundant =
285 AssignedPtrType->getOpcode() == SPIRV::OpTypeUntypedPointerKHR
286 ? GR->getUntypedPtrElementType(Source) ==
288 SPIRV::AccessQualifier::ReadWrite,
289 /*EmitIR=*/true)
290 : GR->getSPIRVTypeForVReg(Source) == AssignedPtrType;
291 if (Redundant) {
292 // Erase Def's assign type instruction if we are going to replace Def.
293 if (MachineInstr *AssignMI = findAssignTypeInstr(Def, MRI))
294 ToErase.push_back(AssignMI);
295 MRI->replaceRegWith(Def, Source);
296 } else {
297 if (!GR->getSPIRVTypeForVReg(Def, &MF))
298 GR->assignSPIRVTypeToVReg(AssignedPtrType, Def, MF);
299 MIB.buildBitcast(Def, Source);
300 }
301 }
302 }
303 for (MachineInstr *MI : ToErase)
305}
306
307// Translating GV, IRTranslator sometimes generates following IR:
308// %1 = G_GLOBAL_VALUE
309// %2 = COPY %1
310// %3 = G_ADDRSPACE_CAST %2
311//
312// or
313//
314// %1 = G_ZEXT %2
315// G_MEMCPY ... %2 ...
316//
317// New registers have no SPIRV type and no register class info.
318//
319// Set SPIRV type for GV, propagate it from GV to other instructions,
320// also set register classes.
324 MachineIRBuilder &MIB) {
325 SPIRVTypeInst SpvType = nullptr;
326 assert(MI && "Machine instr is expected");
327 if (MI->getOperand(0).isReg()) {
328 Register Reg = MI->getOperand(0).getReg();
329 SpvType = GR->getSPIRVTypeForVReg(Reg);
330 if (!SpvType) {
331 switch (MI->getOpcode()) {
332 case TargetOpcode::G_FCONSTANT:
333 case TargetOpcode::G_CONSTANT: {
334 MIB.setInsertPt(*MI->getParent(), MI);
335 Type *Ty = MI->getOperand(1).getCImm()->getType();
336 SpvType = GR->getOrCreateSPIRVType(
337 Ty, MIB, SPIRV::AccessQualifier::ReadWrite, true);
338 break;
339 }
340 case TargetOpcode::G_GLOBAL_VALUE: {
341 MIB.setInsertPt(*MI->getParent(), MI);
342 const GlobalValue *Global = MI->getOperand(1).getGlobal();
344 unsigned AddrSpace = Global->getType()->getAddressSpace();
345 // Function pointers use CodeSectionINTEL storage class in SPIR-V when
346 // the SPV_INTEL_function_pointers extension is enabled.
347 const SPIRVSubtarget &ST = MIB.getMF().getSubtarget<SPIRVSubtarget>();
348 if (isa<Function>(Global) &&
349 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers))
350 AddrSpace =
351 storageClassToAddressSpace(SPIRV::StorageClass::CodeSectionINTEL);
352 auto *Ty = TypedPointerType::get(ElementTy, AddrSpace);
353 SpvType = GR->getOrCreateSPIRVType(
354 Ty, MIB, SPIRV::AccessQualifier::ReadWrite, true);
355 break;
356 }
357 case TargetOpcode::G_ANYEXT:
358 case TargetOpcode::G_SEXT:
359 case TargetOpcode::G_ZEXT: {
360 if (MI->getOperand(1).isReg()) {
361 if (MachineInstr *DefInstr =
362 MRI.getVRegDef(MI->getOperand(1).getReg())) {
363 if (SPIRVTypeInst Def =
364 propagateSPIRVType(DefInstr, GR, MRI, MIB)) {
365 unsigned CurrentBW = GR->getScalarOrVectorBitWidth(Def);
366 unsigned ExpectedBW =
367 std::max(MRI.getType(Reg).getScalarSizeInBits(), CurrentBW);
368 unsigned NumElements = GR->getScalarOrVectorComponentCount(Def);
369 SpvType = GR->getOrCreateSPIRVIntegerType(ExpectedBW, MIB);
370 if (NumElements > 1)
371 SpvType = GR->getOrCreateSPIRVVectorType(SpvType, NumElements,
372 MIB, true);
373 }
374 }
375 }
376 break;
377 }
378 case TargetOpcode::G_PTRTOINT:
379 SpvType = GR->getOrCreateSPIRVIntegerType(
380 MRI.getType(Reg).getScalarSizeInBits(), MIB);
381 break;
382 case TargetOpcode::G_TRUNC:
383 case TargetOpcode::G_ADDRSPACE_CAST:
384 case TargetOpcode::G_PTR_ADD:
385 case TargetOpcode::COPY: {
386 MachineOperand &Op = MI->getOperand(1);
387 MachineInstr *Def = Op.isReg() ? MRI.getVRegDef(Op.getReg()) : nullptr;
388 if (Def)
389 SpvType = propagateSPIRVType(Def, GR, MRI, MIB);
390 break;
391 }
392 default:
393 break;
394 }
395 if (SpvType) {
396 // check if the address space needs correction
397 LLT RegType = MRI.getType(Reg);
398 if (SpvType.isPointer() && RegType.isPointer() &&
400 RegType.getAddressSpace()) {
401 // Don't correct CodeSectionINTEL back to Function for function
402 // pointer G_GLOBAL_VALUE - the LLVM register has address space 0
403 // but the SPIR-V type was intentionally set to CodeSectionINTEL.
404 bool SkipCorrection =
405 MI->getOpcode() == TargetOpcode::G_GLOBAL_VALUE &&
406 GR->getPointerStorageClass(SpvType) ==
407 SPIRV::StorageClass::CodeSectionINTEL;
408 if (!SkipCorrection) {
409 const SPIRVSubtarget &ST =
410 MI->getParent()->getParent()->getSubtarget<SPIRVSubtarget>();
411 auto TSC =
412 addressSpaceToStorageClass(RegType.getAddressSpace(), ST);
413 SpvType = GR->changePointerStorageClass(SpvType, TSC, *MI);
414 }
415 }
416 GR->assignSPIRVTypeToVReg(SpvType, Reg, MIB.getMF());
417 }
418 if (!MRI.getRegClassOrNull(Reg))
419 MRI.setRegClass(Reg, SpvType ? GR->getRegClass(SpvType)
420 : &SPIRV::iIDRegClass);
421 }
422 }
423 return SpvType;
424}
425
426// To support current approach and limitations wrt. bit width here we widen a
427// scalar register with a bit width greater than 1 to valid sizes and cap it to
428// 128 width.
429static unsigned widenBitWidthToNextPow2(unsigned BitWidth) {
430 if (BitWidth == 1)
431 return 1; // No need to widen 1-bit values
432 return std::min(std::max<unsigned>(PowerOf2Ceil(BitWidth), 8u), 128u);
433}
434
435static std::optional<unsigned>
437 LLT Ty = MRI.getType(Reg);
438 if (!Ty.isScalar())
439 return std::nullopt;
440 unsigned W = Ty.getScalarSizeInBits();
441 // <= and not == because widenBitWidthToNextPow2 caps at 128.
442 if (widenBitWidthToNextPow2(W) <= W)
443 return std::nullopt;
444 return W;
445}
446
448 LLT RegType = MRI.getType(Reg);
449 if (!RegType.isScalar())
450 return;
451 unsigned CurrentWidth = RegType.getScalarSizeInBits();
452 unsigned NewWidth = widenBitWidthToNextPow2(CurrentWidth);
453 if (NewWidth != CurrentWidth)
454 MRI.setType(Reg, LLT::scalar(NewWidth));
455}
456
457static void widenCImmType(MachineOperand &MOP) {
458 const ConstantInt *CImmVal = MOP.getCImm();
459 unsigned CurrentWidth = CImmVal->getBitWidth();
460 unsigned NewWidth = widenBitWidthToNextPow2(CurrentWidth);
461 if (NewWidth != CurrentWidth) {
462 // Replace the immediate value with the widened version
463 MOP.setCImm(ConstantInt::get(CImmVal->getType()->getContext(),
464 CImmVal->getValue().zextOrTrunc(NewWidth)));
465 }
466}
467
469 MachineBasicBlock &MBB = *Def->getParent();
471 Def->getNextNode() ? Def->getNextNode()->getIterator() : MBB.end();
472 // Skip all the PHI and debug instructions.
473 while (DefIt != MBB.end() &&
474 (DefIt->isPHI() || DefIt->isDebugOrPseudoInstr()))
475 DefIt = std::next(DefIt);
476 MIB.setInsertPt(MBB, DefIt);
477}
478
479namespace llvm {
482 MachineRegisterInfo &MRI) {
483 assert((Ty || SpvType) && "Either LLVM or SPIRV type is expected.");
484 MachineInstr *Def = MRI.getVRegDef(Reg);
485 setInsertPtAfterDef(MIB, Def);
486 if (!SpvType)
487 SpvType = GR->getOrCreateSPIRVType(Ty, MIB,
488 SPIRV::AccessQualifier::ReadWrite, true);
489 if (!MRI.getRegClassOrNull(Reg))
490 MRI.setRegClass(Reg, GR->getRegClass(SpvType));
491 if (!MRI.getType(Reg).isValid())
492 MRI.setType(Reg, GR->getRegType(SpvType));
493 GR->assignSPIRVTypeToVReg(SpvType, Reg, MIB.getMF());
494}
495
498 SPIRVTypeInst KnownResType) {
499 MIB.setInsertPt(*MI.getParent(), MI.getIterator());
500 for (auto &Op : MI.operands()) {
501 if (!Op.isReg() || Op.isDef())
502 continue;
503 Register OpReg = Op.getReg();
504 SPIRVTypeInst SpvType = GR->getSPIRVTypeForVReg(OpReg);
505 if (!SpvType && KnownResType) {
506 SpvType = KnownResType;
507 GR->assignSPIRVTypeToVReg(KnownResType, OpReg, *MI.getMF());
508 }
509 assert(SpvType);
510 if (!MRI.getRegClassOrNull(OpReg))
511 MRI.setRegClass(OpReg, GR->getRegClass(SpvType));
512 if (!MRI.getType(OpReg).isValid())
513 MRI.setType(OpReg, GR->getRegType(SpvType));
514 }
515}
516} // namespace llvm
517
518// Sign-sensitive integer ops: their result depends on the value of the input
519// sign bit at position (width-1). On sub-pow2 widths the general widening
520// loop is a pure LLT relabel, which leaves the sign bit at the *original*
521// position instead of the widened MSB. These ops therefore need an explicit
522// G_SEXT_INREG on each value operand to move the sign bit up.
523//
524// Signed-vs-unsigned G_ICMP is distinguished by its predicate operand.
525//
526// TODO: follow-up PRs will add the remaining sign-sensitive opcodes
527// (e.g. G_SADDSAT/G_SSUBSAT, signed overflow ops).
528static bool isSignSensitiveOp(const MachineInstr &MI) {
529 switch (MI.getOpcode()) {
530 case TargetOpcode::G_ASHR:
531 case TargetOpcode::G_SDIV:
532 case TargetOpcode::G_SREM:
533 case TargetOpcode::G_SITOFP:
534 case TargetOpcode::G_SMIN:
535 case TargetOpcode::G_SMAX:
536 return true;
537 case TargetOpcode::G_ICMP:
538 return CmpInst::isSigned(
539 static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate()));
540 default:
541 return false;
542 }
543}
544
546 // Width before widening of each sign-sensitive value-operand vreg (one entry
547 // per vreg).
549 // Sign-sensitive ops whose value operand(s) need replacing, ordered for
550 // reproducible vreg numbering.
552 // Keyed by instruction, not vreg: G_TRUNC handling can replace the source.
554};
555
556// G_CTTZ_ZERO_POISON is absent because its low bits are known non-zero, G_CTLS
557// because the backend does not select it.
558static bool isWidthSensitiveBitCountOp(unsigned Opcode) {
559 switch (Opcode) {
560 case TargetOpcode::G_CTLZ:
561 case TargetOpcode::G_CTLZ_ZERO_POISON:
562 case TargetOpcode::G_CTTZ:
563 case TargetOpcode::G_CTPOP:
564 return true;
565 default:
566 return false;
567 }
568}
569
570// Collect ops whose semantics depend on the operand width along with their
571// pre-widening widths, before later passes retype those vregs to pow2 LLTs
572// and the original width is no longer recoverable.
573static NarrowWideningInfo
576 auto RecordIfNarrow = [&](Register Reg) {
577 std::optional<unsigned> W = getNarrowScalarWidth(Reg, MRI);
578 if (!W)
579 return false;
580 Info.OrigWidth.try_emplace(Reg, *W);
581 return true;
582 };
583 for (MachineBasicBlock &MBB : MF) {
584 for (MachineInstr &MI : MBB) {
585 if (isWidthSensitiveBitCountOp(MI.getOpcode())) {
586 if (std::optional<unsigned> W =
587 getNarrowScalarWidth(MI.getOperand(1).getReg(), MRI))
588 Info.BitCountWorklist.emplace_back(&MI, *W);
589 continue;
590 }
591 if (!isSignSensitiveOp(MI))
592 continue;
593 bool NeedsRewrite = false;
594 for (const MachineOperand &MO : MI.all_uses())
595 NeedsRewrite = RecordIfNarrow(MO.getReg()) || NeedsRewrite;
596 if (NeedsRewrite) {
597 Info.SignSensitiveWorklist.push_back(&MI);
598 // Record the result too so it gets masked.
599 RecordIfNarrow(MI.getOperand(0).getReg());
600 }
601 }
602 }
603 return Info;
604}
605
606// For every recorded sign-sensitive op, insert G_SEXT_INREG on each value
607// operand whose original width was narrower than the widened pow2 width and
608// retype the operand's vreg LLT in place to the widened width.
609//
610// Info must have been populated by recordNarrowOperandWidths before
611// other passes retyped the vregs; otherwise the narrow widths needed here
612// are lost.
613//
614// TODO: handle vector operands.
616 MachineIRBuilder &MIB,
618 const NarrowWideningInfo &Info) {
619 // Emit G_SEXT_INREG from Reg's recorded narrow width; retypes Reg to the
620 // widened width and returns the sign-extended vreg.
621 auto SignExtendReg = [&](Register Reg, unsigned OldW,
623 unsigned NewW = widenBitWidthToNextPow2(OldW);
624 LLT NewLLT = LLT::scalar(NewW);
625 MIB.setInsertPt(*MI.getParent(), MI.getIterator());
626 SPIRVTypeInst SpvTy = GR->getOrCreateSPIRVIntegerType(NewW, MIB);
627 Register SExted = MRI.createGenericVirtualRegister(NewLLT);
628 GR->assignSPIRVTypeToVReg(SpvTy, SExted, MF);
629 MRI.setRegClass(SExted, GR->getRegClass(SpvTy));
630 MRI.setType(Reg, NewLLT);
631 MIB.buildSExtInReg(SExted, Reg, OldW);
632 return SExted;
633 };
634
635 // The wide op yields a sign-extended value, mask it back to OldW bits because
636 // later users assume the upper bits are zero.
637 auto MaskResult = [&](MachineInstr &MI, unsigned OldW) {
638 Register DstReg = MI.getOperand(0).getReg();
639 widenScalarType(DstReg, MRI);
641 SPIRVTypeInst SpvTy =
643 Register Result = createVirtualRegister(SpvTy, GR, MIB);
644 MI.getOperand(0).setReg(Result);
645 setInsertPtAfterDef(MIB, &MI);
646 MIB.buildZExtInReg(DstReg, Result, OldW);
647 };
648
649 // TODO: when the same narrow vreg feeds multiple sign-sensitive ops (e.g.
650 // sdiv %x, %y and srem %x, %y), emit one shared G_SEXT_INREG instead of one
651 // per use.
653 for (MachineInstr *MI : Info.SignSensitiveWorklist) {
654 for (const MachineOperand &MO : MI->all_uses()) {
655 Register Reg = MO.getReg();
656 auto It = Info.OrigWidth.find(Reg);
657 if (It == Info.OrigWidth.end())
658 continue;
659 // substituteRegister fills every slot holding Reg at once: SignExtendReg
660 // retypes Reg in place, so a second sext would read the widened width.
661 MI->substituteRegister(Reg, SignExtendReg(Reg, It->second, *MI),
662 /*SubIdx=*/0, TRI);
663 }
664 Register Dst = MI->getOperand(0).getReg();
665 if (auto It = Info.OrigWidth.find(Dst); It != Info.OrigWidth.end())
666 MaskResult(*MI, It->second);
667 }
668}
669
670// LegalizerHelper::widenScalar has the same cases but cannot be reached: the
671// relabel retypes every narrow scalar to a pow2 LLT, so no illegal narrow type
672// ever reaches the legalizer.
673//
674// TODO: handle vector operands.
677 const NarrowWideningInfo &Info) {
678 for (auto [MI, OldWidth] : Info.BitCountWorklist) {
679 Register SrcReg = MI->getOperand(1).getReg();
680 unsigned NewWidth = widenBitWidthToNextPow2(OldWidth);
681 LLT NewTy = LLT::scalar(NewWidth);
682 widenScalarType(SrcReg, MRI);
684 SPIRVTypeInst SpvTy = GR->getOrCreateSPIRVIntegerType(NewWidth, MIB);
685
686 // The G_TRUNC lowering masks its result to the narrow width, so a source
687 // coming from it needs no second mask.
688 APInt Cst;
689 bool HighBitsAlreadyZero =
690 mi_match(SrcReg, MRI, m_GAnd(m_Reg(), m_ICst(Cst))) &&
691 Cst.isSubsetOf(APInt::getLowBitsSet(Cst.getBitWidth(), OldWidth));
692 auto ClearHighBits = [&](unsigned Width) -> Register {
693 if (HighBitsAlreadyZero)
694 return SrcReg;
695 Register Masked = createVirtualRegister(SpvTy, GR, MIB);
696 MIB.buildZExtInReg(Masked, SrcReg, Width);
697 return Masked;
698 };
699
701 switch (MI->getOpcode()) {
702 case TargetOpcode::G_CTLZ_ZERO_POISON: {
703 // Shifting up to the widened MSB moves the poison out too, so no
704 // adjustment.
705 Input = createVirtualRegister(SpvTy, GR, MIB);
706 auto Diff = MIB.buildConstant(NewTy, NewWidth - OldWidth);
707 MIB.buildShl(Input, SrcReg, Diff);
708 break;
709 }
710 case TargetOpcode::G_CTTZ: {
711 // Keeps an all-zero narrow value counting exactly OldWidth zeros.
712 Input = createVirtualRegister(SpvTy, GR, MIB);
713 auto TopBit =
714 MIB.buildConstant(NewTy, APInt::getOneBitSet(NewWidth, OldWidth));
715 MIB.buildOr(Input, SrcReg, TopBit);
716 break;
717 }
718 case TargetOpcode::G_CTPOP:
719 Input = ClearHighBits(OldWidth);
720 break;
721 case TargetOpcode::G_CTLZ: {
722 // Clearing the extra bits adds leading zeros the count has to drop.
723 Input = ClearHighBits(OldWidth);
724 Register DstReg = MI->getOperand(0).getReg();
725 widenScalarType(DstReg, MRI);
726 Register Count = createVirtualRegister(SpvTy, GR, MIB);
727 MI->getOperand(0).setReg(Count);
729 auto Diff = MIB.buildConstant(NewTy, NewWidth - OldWidth);
730 MIB.buildSub(DstReg, Count, Diff);
731 break;
732 }
733 default:
734 llvm_unreachable("unexpected width-sensitive bit-count opcode");
735 }
736 MI->getOperand(1).setReg(Input);
737 }
738}
739
740static void
743 DenseMap<MachineInstr *, Type *> &TargetExtConstTypes) {
744 // Get access to information about available extensions
745 const SPIRVSubtarget *ST =
746 static_cast<const SPIRVSubtarget *>(&MIB.getMF().getSubtarget());
747
750 DenseMap<MachineInstr *, Register> RegsAlreadyAddedToDT;
751
752 bool IsExtendedInts =
753 ST->canUseExtension(
754 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_integers) ||
755 ST->canUseExtension(SPIRV::Extension::SPV_KHR_bit_instructions) ||
756 ST->canUseExtension(SPIRV::Extension::SPV_INTEL_int4);
757
758 if (!IsExtendedInts) {
759 // Without arbitrary precision integer extensions, SPIR-V only supports
760 // integer widths of 8, 16, 32, 64. Non-standard widths (e.g., i24, i40)
761 // must be widened to the next power of two.
762 //
763 // Record the original widths of width-sensitive operands before either
764 // the G_TRUNC handling or the general widening loop retypes vregs, then
765 // rewrite those ops after G_TRUNC processing using the recorded widths.
766 NarrowWideningInfo WideningInfo = recordNarrowOperandWidths(MF, MRI);
767
768 // G_TRUNC requires special handling because its semantics depend on the
769 // original destination width. For example:
770 // %dst:s24 = G_TRUNC %src:s64
771 // After widening s24 to s32, we cannot simply do:
772 // %dst:s32 = G_TRUNC %src:s64
773 // because this would keep 32 bits instead of 24. Instead, we insert a
774 // G_AND to mask the value to the original width:
775 // %mask:s64 = G_CONSTANT 0xFFFFFF ; 24-bit mask
776 // %masked:s64 = G_AND %src:s64, %mask
777 // %dst:s32 = G_TRUNC %masked:s64
778 // If src and dst widen to the same size, G_TRUNC is replaced entirely:
779 // %mask:s64 = G_CONSTANT 0xFFFFFFFFFF ; 40-bit mask
780 // %dst:s64 = G_AND %src:s64, %mask
781 SmallVector<MachineInstr *, 8> TruncToRemove;
782 for (MachineBasicBlock &MBB : MF) {
783 for (MachineInstr &MI : MBB) {
784 unsigned MIOp = MI.getOpcode();
785 if (MIOp != TargetOpcode::G_TRUNC)
786 continue;
787 assert(MI.getNumOperands() == 2);
788 assert(MI.getOperand(0).isReg());
789 assert(MI.getOperand(1).isReg());
790
791 Register DstReg = MI.getOperand(0).getReg();
792 Register SrcReg = MI.getOperand(1).getReg();
793
794 LLT DstTy = MRI.getType(DstReg);
795 LLT SrcTy = MRI.getType(SrcReg);
796 assert((DstTy.isScalar() || DstTy.isVector()) &&
797 (SrcTy.isScalar() || SrcTy.isVector()) &&
798 "Expected scalar or vector G_TRUNC types");
799 assert(DstTy.isVector() == SrcTy.isVector() &&
800 "Expected matching scalar/vector G_TRUNC types");
801 assert((!DstTy.isVector() ||
802 DstTy.getElementCount() == SrcTy.getElementCount()) &&
803 "Expected equal vector element counts");
804
805 unsigned OriginalDstWidth = DstTy.getScalarSizeInBits();
806 unsigned OriginalSrcWidth = SrcTy.getScalarSizeInBits();
807
808 unsigned NewDstWidth = widenBitWidthToNextPow2(OriginalDstWidth);
809 unsigned NewSrcWidth = widenBitWidthToNextPow2(OriginalSrcWidth);
810 LLT NewDstTy = DstTy.changeElementSize(NewDstWidth);
811 LLT NewSrcTy = SrcTy.changeElementSize(NewSrcWidth);
812
813 // No Dst width change means no truncation semantics change, but the
814 // source still needs a legal type.
815 if (OriginalDstWidth == NewDstWidth) {
816 MRI.setType(SrcReg, NewSrcTy);
817 continue;
818 }
819
820 MRI.setType(SrcReg, NewSrcTy);
821 MRI.setType(DstReg, NewDstTy);
822
823 MIB.setInsertPt(MBB, MI.getIterator());
824 APInt Mask = APInt::getLowBitsSet(NewSrcWidth, OriginalDstWidth);
825 MachineInstrBuilder MaskReg =
826 DstTy.isVector()
828 NewSrcTy,
830 : MIB.buildConstant(NewSrcTy, Mask);
831 Register MaskedReg = MRI.createGenericVirtualRegister(NewSrcTy);
832 MIB.buildAnd(MaskedReg, SrcReg, MaskReg);
833
834 if (NewSrcWidth == NewDstWidth) {
835 // Rekey OrigWidth from DstReg to MaskedReg so widenSignSensitiveOps
836 // still sees the narrow original width after replaceRegWith.
837 if (auto It = WideningInfo.OrigWidth.find(DstReg);
838 It != WideningInfo.OrigWidth.end()) {
839 unsigned W = It->second;
840 WideningInfo.OrigWidth.erase(It);
841 WideningInfo.OrigWidth.try_emplace(MaskedReg, W);
842 }
843 MRI.replaceRegWith(DstReg, MaskedReg);
844 TruncToRemove.push_back(&MI);
845 } else {
846 MI.getOperand(1).setReg(MaskedReg);
847 }
848 }
849 }
850 for (MachineInstr *MI : TruncToRemove)
851 MI->eraseFromParent();
852
853 widenSignSensitiveOps(MF, GR, MIB, MRI, WideningInfo);
854 widenBitCountOps(GR, MIB, MRI, WideningInfo);
855 }
856
857 for (MachineBasicBlock *MBB : post_order(&MF)) {
858 if (MBB->empty())
859 continue;
860
861 bool ReachedBegin = false;
862 for (auto MII = std::prev(MBB->end()), Begin = MBB->begin();
863 !ReachedBegin;) {
864 MachineInstr &MI = *MII;
865 unsigned MIOp = MI.getOpcode();
866
867 if (!IsExtendedInts) {
868 // validate bit width of scalar registers and constant immediates
869 for (auto &MOP : MI.operands()) {
870 if (MOP.isReg())
871 widenScalarType(MOP.getReg(), MRI);
872 else if (MOP.isCImm())
873 widenCImmType(MOP);
874 }
875 }
876
877 if (isSpvIntrinsic(MI, Intrinsic::spv_assign_ptr_type)) {
878 Register Reg = MI.getOperand(1).getReg();
879 MIB.setInsertPt(*MI.getParent(), MI.getIterator());
880 Type *ElementTy = getMDOperandAsType(MI.getOperand(2).getMetadata(), 0);
881 auto SC = addressSpaceToStorageClass(MI.getOperand(3).getImm(), *ST);
882 if (SC == SPIRV::StorageClass::Function &&
883 isa<FunctionType>(ElementTy) &&
884 ST->canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers))
885 SC = SPIRV::StorageClass::CodeSectionINTEL;
886 SPIRVTypeInst AssignedPtrType =
887 GR->getOrCreateSPIRVPointerType(ElementTy, MI, SC);
888
889 // For untyped pointers, store the element type for later use.
890 if (ST->canUseExtension(SPIRV::Extension::SPV_KHR_untyped_pointers) &&
891 !ST->isShader()) {
892 SPIRVTypeInst ElemSpvType = GR->getOrCreateSPIRVType(
893 ElementTy, MIB, SPIRV::AccessQualifier::ReadWrite,
894 /*EmitIR=*/true);
895 GR->setUntypedPtrElementType(Reg, ElemSpvType);
896 }
897
898 // The intrinsic also carries vector-of-pointer values produced by
899 // scalarized vector GEPs; wrap the pointer in OpTypeVector to match
900 // the vreg's LLT.
901 LLT RegTy = MRI.getType(Reg);
902 if (RegTy.isValid() && RegTy.isVector())
903 AssignedPtrType = GR->getOrCreateSPIRVVectorType(
904 AssignedPtrType, RegTy.getNumElements(), MIB,
905 /*EmitIR=*/true);
906 MachineInstr *Def = MRI.getVRegDef(Reg);
907 assert(Def && "Expecting an instruction that defines the register");
908 // G_GLOBAL_VALUE already has type info.
909 if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE)
910 updateRegType(Reg, nullptr, AssignedPtrType, GR, MIB,
911 MF.getRegInfo());
912 ToErase.push_back(&MI);
913 } else if (isSpvIntrinsic(MI, Intrinsic::spv_assign_type)) {
914 Register Reg = MI.getOperand(1).getReg();
915 Type *Ty = getMDOperandAsType(MI.getOperand(2).getMetadata(), 0);
916 MachineInstr *Def = MRI.getVRegDef(Reg);
917 assert(Def && "Expecting an instruction that defines the register");
918 // G_GLOBAL_VALUE already has type info.
919 if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE)
920 updateRegType(Reg, Ty, nullptr, GR, MIB, MF.getRegInfo());
921 if (Def->getOpcode() == TargetOpcode::COPY && isVector1(Ty))
923 Ty, nullptr, GR, MIB, MF.getRegInfo());
924 ToErase.push_back(&MI);
925 } else if (MIOp == TargetOpcode::FAKE_USE && MI.getNumOperands() > 0) {
926 MachineInstr *MdMI = MI.getPrevNode();
927 if (MdMI && isSpvIntrinsic(*MdMI, Intrinsic::spv_value_md)) {
928 // It's an internal service info from before IRTranslator passes.
929 MachineInstr *Def = getVRegDef(MRI, MI.getOperand(0).getReg());
930 for (unsigned I = 1, E = MI.getNumOperands(); I != E && Def; ++I)
931 if (getVRegDef(MRI, MI.getOperand(I).getReg()) != Def)
932 Def = nullptr;
933 if (Def) {
934 const MDNode *MD = MdMI->getOperand(1).getMetadata();
936 cast<MDString>(MD->getOperand(1))->getString();
937 const MDNode *TypeMD = cast<MDNode>(MD->getOperand(0));
938 Type *ValueTy = getMDOperandAsType(TypeMD, 0);
939 GR->addValueAttrs(Def, std::make_pair(ValueTy, ValueName.str()));
940 }
941 ToErase.push_back(MdMI);
942 }
943 ToErase.push_back(&MI);
944 } else if (MIOp == TargetOpcode::G_CONSTANT ||
945 MIOp == TargetOpcode::G_FCONSTANT ||
946 MIOp == TargetOpcode::G_BUILD_VECTOR) {
947 // %rc = G_CONSTANT ty Val
948 // Ensure %rc has a valid SPIR-V type assigned in the Global Registry.
949 Register Reg = MI.getOperand(0).getReg();
950 bool NeedAssignType = !GR->getSPIRVTypeForVReg(Reg);
951 Type *Ty = nullptr;
952 if (MIOp == TargetOpcode::G_CONSTANT) {
953 auto TargetExtIt = TargetExtConstTypes.find(&MI);
954 Ty = TargetExtIt == TargetExtConstTypes.end()
955 ? MI.getOperand(1).getCImm()->getType()
956 : TargetExtIt->second;
957 const ConstantInt *OpCI = MI.getOperand(1).getCImm();
958 // TODO: we may wish to analyze here if OpCI is zero and LLT RegType =
959 // MRI.getType(Reg); RegType.isPointer() is true, so that we observe
960 // at this point not i64/i32 constant but null pointer in the
961 // corresponding address space of RegType.getAddressSpace(). This may
962 // help to successfully validate the case when a OpConstantComposite's
963 // constituent has type that does not match Result Type of
964 // OpConstantComposite (see, for example,
965 // pointers/PtrCast-null-in-OpSpecConstantOp.ll).
966 Register PrimaryReg = GR->find(OpCI, &MF);
967 if (!PrimaryReg.isValid()) {
968 GR->add(OpCI, &MI);
969 } else if (PrimaryReg != Reg &&
970 MRI.getType(Reg) == MRI.getType(PrimaryReg)) {
971 auto *RCReg = MRI.getRegClassOrNull(Reg);
972 auto *RCPrimary = MRI.getRegClassOrNull(PrimaryReg);
973 if (!RCReg || RCPrimary == RCReg) {
974 RegsAlreadyAddedToDT[&MI] = PrimaryReg;
975 ToErase.push_back(&MI);
976 NeedAssignType = false;
977 }
978 }
979 } else if (MIOp == TargetOpcode::G_FCONSTANT) {
980 Ty = MI.getOperand(1).getFPImm()->getType();
981 } else {
982 assert(MIOp == TargetOpcode::G_BUILD_VECTOR);
983 Type *ElemTy = nullptr;
984 MachineInstr *ElemMI = MRI.getVRegDef(MI.getOperand(1).getReg());
985 assert(ElemMI);
986
987 if (ElemMI->getOpcode() == TargetOpcode::G_CONSTANT) {
988 ElemTy = ElemMI->getOperand(1).getCImm()->getType();
989 } else if (ElemMI->getOpcode() == TargetOpcode::G_FCONSTANT) {
990 ElemTy = ElemMI->getOperand(1).getFPImm()->getType();
991 } else {
992 if (SPIRVTypeInst ElemSpvType =
993 GR->getSPIRVTypeForVReg(MI.getOperand(1).getReg(), &MF))
994 ElemTy = const_cast<Type *>(GR->getTypeForSPIRVType(ElemSpvType));
995 }
996 if (ElemTy)
997 Ty = VectorType::get(
998 ElemTy, MI.getNumExplicitOperands() - MI.getNumExplicitDefs(),
999 false);
1000 else
1001 NeedAssignType = false;
1002 }
1003 if (NeedAssignType)
1004 updateRegType(Reg, Ty, nullptr, GR, MIB, MRI);
1005 } else if (MIOp == TargetOpcode::G_GLOBAL_VALUE) {
1006 propagateSPIRVType(&MI, GR, MRI, MIB);
1007 }
1008
1009 if (MII == Begin)
1010 ReachedBegin = true;
1011 else
1012 --MII;
1013 }
1014 }
1015 for (MachineInstr *MI : ToErase) {
1016 auto It = RegsAlreadyAddedToDT.find(MI);
1017 if (It != RegsAlreadyAddedToDT.end())
1018 MRI.replaceRegWith(MI->getOperand(0).getReg(), It->second);
1020 }
1021
1022 // Address the case when IRTranslator introduces instructions with new
1023 // registers without associated SPIRV type.
1024 for (MachineBasicBlock &MBB : MF) {
1025 for (MachineInstr &MI : MBB) {
1026 switch (MI.getOpcode()) {
1027 case TargetOpcode::G_TRUNC:
1028 case TargetOpcode::G_ANYEXT:
1029 case TargetOpcode::G_SEXT:
1030 case TargetOpcode::G_ZEXT:
1031 case TargetOpcode::G_PTRTOINT:
1032 case TargetOpcode::COPY:
1033 case TargetOpcode::G_ADDRSPACE_CAST:
1034 propagateSPIRVType(&MI, GR, MRI, MIB);
1035 break;
1036 }
1037 }
1038 }
1039}
1040
1043 MachineIRBuilder MIB) {
1044 MachineRegisterInfo &MRI = MF.getRegInfo();
1045 for (MachineBasicBlock &MBB : MF)
1046 for (MachineInstr &MI : MBB)
1047 if (isTypeFoldingSupported(MI.getOpcode()))
1048 processInstr(MI, MIB, MRI, GR, nullptr);
1049}
1050
1051static Register
1053 SmallVector<unsigned, 4> *Ops = nullptr) {
1054 Register DefReg;
1055 unsigned StartOp = InlineAsm::MIOp_FirstOperand,
1056 AsmDescOp = InlineAsm::MIOp_FirstOperand;
1057 for (unsigned Idx = StartOp, MISz = MI->getNumOperands(); Idx != MISz;
1058 ++Idx) {
1059 const MachineOperand &MO = MI->getOperand(Idx);
1060 if (MO.isMetadata())
1061 continue;
1062 if (Idx == AsmDescOp && MO.isImm()) {
1063 // compute the index of the next operand descriptor
1064 const InlineAsm::Flag F(MO.getImm());
1065 AsmDescOp += 1 + F.getNumOperandRegisters();
1066 continue;
1067 }
1068 if (MO.isReg() && MO.isDef()) {
1069 if (!Ops)
1070 return MO.getReg();
1071 DefReg = MO.getReg();
1072 } else if (Ops) {
1073 Ops->push_back(Idx);
1074 }
1075 }
1076 return DefReg;
1077}
1078
1079static void
1081 const SPIRVSubtarget &ST, MachineIRBuilder MIRBuilder,
1082 const SmallVector<MachineInstr *> &ToProcess) {
1083 MachineRegisterInfo &MRI = MF.getRegInfo();
1084 Register AsmTargetReg;
1085 for (unsigned i = 0, Sz = ToProcess.size(); i + 1 < Sz; i += 2) {
1086 MachineInstr *I1 = ToProcess[i], *I2 = ToProcess[i + 1];
1087 assert(isSpvIntrinsic(*I1, Intrinsic::spv_inline_asm) && I2->isInlineAsm());
1088 MIRBuilder.setInsertPt(*I2->getParent(), *I2);
1089
1090 if (!AsmTargetReg.isValid()) {
1091 // define vendor specific assembly target or dialect
1092 AsmTargetReg = MRI.createGenericVirtualRegister(LLT::scalar(32));
1093 MRI.setRegClass(AsmTargetReg, &SPIRV::iIDRegClass);
1094 auto AsmTargetMIB =
1095 MIRBuilder.buildInstr(SPIRV::OpAsmTargetINTEL).addDef(AsmTargetReg);
1096 addStringImm(ST.getTargetTripleAsStr(), AsmTargetMIB);
1097 GR->add(AsmTargetMIB.getInstr(), AsmTargetMIB);
1098 }
1099
1100 // create types
1101 const MDNode *IAMD = I1->getOperand(1).getMetadata();
1104 for (const auto &ArgTy : FTy->params())
1105 ArgTypes.push_back(GR->getOrCreateSPIRVType(
1106 ArgTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite, true));
1107 SPIRVTypeInst RetType =
1108 GR->getOrCreateSPIRVType(FTy->getReturnType(), MIRBuilder,
1109 SPIRV::AccessQualifier::ReadWrite, true);
1111 FTy, RetType, ArgTypes, MIRBuilder);
1112
1113 // define vendor specific assembly instructions string
1115 MRI.setRegClass(AsmReg, &SPIRV::iIDRegClass);
1116 auto AsmMIB = MIRBuilder.buildInstr(SPIRV::OpAsmINTEL)
1117 .addDef(AsmReg)
1118 .addUse(GR->getSPIRVTypeID(RetType))
1119 .addUse(GR->getSPIRVTypeID(FuncType))
1120 .addUse(AsmTargetReg);
1121 // inline asm string:
1122 addStringImm(I2->getOperand(InlineAsm::MIOp_AsmString).getSymbolName(),
1123 AsmMIB);
1124 // inline asm constraint string:
1125 addStringImm(cast<MDString>(I1->getOperand(2).getMetadata()->getOperand(0))
1126 ->getString(),
1127 AsmMIB);
1128 GR->add(AsmMIB.getInstr(), AsmMIB);
1129
1130 // calls the inline assembly instruction
1131 unsigned ExtraInfo = I2->getOperand(InlineAsm::MIOp_ExtraInfo).getImm();
1132 if (ExtraInfo & InlineAsm::Extra_HasSideEffects)
1133 MIRBuilder.buildInstr(SPIRV::OpDecorate)
1134 .addUse(AsmReg)
1135 .addImm(static_cast<uint32_t>(SPIRV::Decoration::SideEffectsINTEL));
1136
1138 if (!DefReg.isValid()) {
1139 DefReg = MRI.createGenericVirtualRegister(LLT::scalar(32));
1140 MRI.setRegClass(DefReg, &SPIRV::iIDRegClass);
1141 SPIRVTypeInst VoidType = GR->getOrCreateSPIRVType(
1142 Type::getVoidTy(MF.getFunction().getContext()), MIRBuilder,
1143 SPIRV::AccessQualifier::ReadWrite, true);
1144 GR->assignSPIRVTypeToVReg(VoidType, DefReg, MF);
1145 }
1146
1147 auto AsmCall = MIRBuilder.buildInstr(SPIRV::OpAsmCallINTEL)
1148 .addDef(DefReg)
1149 .addUse(GR->getSPIRVTypeID(RetType))
1150 .addUse(AsmReg);
1151 for (unsigned IntrIdx = 3; IntrIdx < I1->getNumOperands(); ++IntrIdx)
1152 AsmCall.addUse(I1->getOperand(IntrIdx).getReg());
1153
1154 // IRTranslator gets a bit confused when lowering inline ASM with outputs
1155 // and inserts a spurious COPY & TRUNC as registers are assumed to be i64;
1156 // we have to clean that up here to prevent erroneous trunc casts either on
1157 // a struct (for multiple outputs) or same width integers to get lowered
1158 // into SPIR-V
1159 if (MRI.hasOneUse(DefReg)) {
1160 MachineInstr &CopyMI = *MRI.use_instr_begin(DefReg);
1161 if (CopyMI.getOpcode() == TargetOpcode::COPY) {
1162 Register CopyDst = CopyMI.getOperand(0).getReg();
1163 if (MRI.hasOneUse(CopyDst)) {
1164 MachineInstr &TruncMI = *MRI.use_instr_begin(CopyDst);
1165 if (TruncMI.getOpcode() == TargetOpcode::G_TRUNC) {
1166 MRI.setType(DefReg, GR->getRegType(RetType));
1167 Register TruncReg = TruncMI.defs().begin()->getReg();
1168 MRI.replaceRegWith(TruncReg, DefReg);
1169 invalidateAndEraseMI(GR, &TruncMI);
1170 invalidateAndEraseMI(GR, &CopyMI);
1171 }
1172 }
1173 }
1174 }
1175 }
1176 for (MachineInstr *MI : ToProcess)
1178}
1179
1181 const SPIRVSubtarget &ST,
1182 MachineIRBuilder MIRBuilder) {
1184 for (MachineBasicBlock &MBB : MF) {
1185 for (MachineInstr &MI : MBB) {
1186 if (isSpvIntrinsic(MI, Intrinsic::spv_inline_asm) ||
1187 MI.getOpcode() == TargetOpcode::INLINEASM)
1188 ToProcess.push_back(&MI);
1189 }
1190 }
1191 if (ToProcess.size() == 0)
1192 return;
1193
1194 if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_inline_assembly))
1195 report_fatal_error("Inline assembly instructions require the "
1196 "following SPIR-V extension: SPV_INTEL_inline_assembly",
1197 false);
1198
1199 insertInlineAsmProcess(MF, GR, ST, MIRBuilder, ToProcess);
1200}
1201
1203 MachineIRBuilder MIB) {
1206 for (MachineBasicBlock &MBB : MF) {
1207 for (MachineInstr &MI : MBB) {
1208 if (!isSpvIntrinsic(MI, Intrinsic::spv_assign_decoration) &&
1209 !isSpvIntrinsic(MI, Intrinsic::spv_assign_aliasing_decoration) &&
1210 !isSpvIntrinsic(MI, Intrinsic::spv_assign_fpmaxerror_decoration))
1211 continue;
1212 MIB.setInsertPt(*MI.getParent(), MI.getNextNode());
1213 if (isSpvIntrinsic(MI, Intrinsic::spv_assign_decoration)) {
1214 buildOpSpirvDecorations(MI.getOperand(1).getReg(), MIB,
1215 MI.getOperand(2).getMetadata(), ST);
1216 } else if (isSpvIntrinsic(MI,
1217 Intrinsic::spv_assign_fpmaxerror_decoration)) {
1219 MI.getOperand(2).getMetadata()->getOperand(0));
1220 uint32_t OpValue = OpV->getValueAPF().bitcastToAPInt().getZExtValue();
1221
1222 buildOpDecorate(MI.getOperand(1).getReg(), MIB,
1223 SPIRV::Decoration::FPMaxErrorDecorationINTEL,
1224 {OpValue});
1225 } else {
1226 GR->buildMemAliasingOpDecorate(MI.getOperand(1).getReg(), MIB,
1227 MI.getOperand(2).getImm(),
1228 MI.getOperand(3).getMetadata());
1229 }
1230
1231 ToErase.push_back(&MI);
1232 }
1233 }
1234 for (MachineInstr *MI : ToErase)
1236}
1237
1238// Returns the value of the switch case operand in Reg. The case value stays a
1239// G_CONSTANT until the module emits a SPIR-V constant for the same value, at
1240// which point the case register is replaced with the one defining that
1241// constant, which keeps its value in literal operands rather than in a CImm.
1243 const MachineRegisterInfo &MRI,
1244 LLVMContext &Ctx) {
1245 APInt Val;
1246 if (mi_match(Reg, MRI, m_ICst(Val)))
1247 return ConstantInt::get(Ctx, Val);
1248
1249 const MachineInstr *Def = nullptr;
1250 if (!mi_match(Reg, MRI, m_MInstr(Def)))
1251 llvm_unreachable("Switch case operand has no definition");
1252
1253 LLT Ty = MRI.getType(Reg);
1254 assert(Ty.isValid() && "Expected a typed switch case value");
1255 Val = APInt(Ty.getScalarSizeInBits(), 0);
1256
1257 switch (Def->getOpcode()) {
1258 case SPIRV::OpConstantNull:
1259 case SPIRV::OpConstantI:
1260 // The operands after the type are 32-bit literal words, least significant
1261 // first, as written by addNumImm(). OpConstantNull carries none, so it
1262 // decodes to zero without a case of its own.
1263 for (unsigned I = 2, E = Def->getNumExplicitOperands(); I != E; ++I) {
1264 uint32_t Word = static_cast<uint32_t>(Def->getOperand(I).getImm());
1265 Val |= APInt(Val.getBitWidth(), Word).shl((I - 2) * 32);
1266 }
1267 break;
1268 default:
1269 llvm_unreachable("Unexpected definition of a switch case value");
1270 }
1271 return ConstantInt::get(Ctx, Val);
1272}
1273
1274// LLVM allows the switches to use registers as cases, while SPIR-V required
1275// those to be immediate values. This function replaces such operands with the
1276// equivalent immediate constant.
1279 MachineIRBuilder MIB) {
1280 MachineRegisterInfo &MRI = MF.getRegInfo();
1281 LLVMContext &Ctx = MF.getFunction().getContext();
1282 for (MachineBasicBlock &MBB : MF) {
1283 for (MachineInstr &MI : MBB) {
1284 if (!isSpvIntrinsic(MI, Intrinsic::spv_switch))
1285 continue;
1286
1288 NewOperands.push_back(MI.getOperand(0)); // Opcode
1289 NewOperands.push_back(MI.getOperand(1)); // Condition
1290 NewOperands.push_back(MI.getOperand(2)); // Default
1291 for (unsigned i = 3; i < MI.getNumOperands(); i += 2) {
1292 Register Reg = MI.getOperand(i).getReg();
1293 NewOperands.push_back(
1295
1296 NewOperands.push_back(MI.getOperand(i + 1));
1297 }
1298
1299 assert(MI.getNumOperands() == NewOperands.size());
1300 while (MI.getNumOperands() > 0)
1301 MI.removeOperand(0);
1302 for (auto &MO : NewOperands)
1303 MI.addOperand(MO);
1304 }
1305 }
1306}
1307
1308// Some instructions are used during CodeGen but should never be emitted.
1309// Cleaning up those.
1311 SPIRVGlobalRegistry *GR) {
1313 for (MachineBasicBlock &MBB : MF) {
1314 for (MachineInstr &MI : MBB) {
1315 if (isSpvIntrinsic(MI, Intrinsic::spv_track_constant) ||
1316 MI.getOpcode() == TargetOpcode::G_BRINDIRECT)
1317 ToEraseMI.push_back(&MI);
1318 }
1319 }
1320
1321 for (MachineInstr *MI : ToEraseMI)
1323}
1324
1325// Find all usages of G_BLOCK_ADDR in our intrinsics and replace those
1326// operands/registers by the actual MBB it references.
1328 MachineIRBuilder MIB) {
1329 // Gather the reverse-mapping BB -> MBB.
1331 for (MachineBasicBlock &MBB : MF)
1332 BB2MBB[MBB.getBasicBlock()] = &MBB;
1333
1334 // Gather instructions requiring patching. For now, only those can use
1335 // G_BLOCK_ADDR.
1336 SmallVector<MachineInstr *, 8> InstructionsToPatch;
1337 for (MachineBasicBlock &MBB : MF) {
1338 for (MachineInstr &MI : MBB) {
1339 if (isSpvIntrinsic(MI, Intrinsic::spv_switch) ||
1340 isSpvIntrinsic(MI, Intrinsic::spv_loop_merge) ||
1341 isSpvIntrinsic(MI, Intrinsic::spv_selection_merge))
1342 InstructionsToPatch.push_back(&MI);
1343 }
1344 }
1345
1346 // For each instruction to fix, we replace all the G_BLOCK_ADDR operands by
1347 // the actual MBB it references. Once those references have been updated, we
1348 // can cleanup remaining G_BLOCK_ADDR references.
1349 SmallPtrSet<MachineBasicBlock *, 8> ClearAddressTaken;
1351 MachineRegisterInfo &MRI = MF.getRegInfo();
1352 for (MachineInstr *MI : InstructionsToPatch) {
1354 for (unsigned i = 0; i < MI->getNumOperands(); ++i) {
1355 // The operand is not a register, keep as-is.
1356 if (!MI->getOperand(i).isReg()) {
1357 NewOps.push_back(MI->getOperand(i));
1358 continue;
1359 }
1360
1361 Register Reg = MI->getOperand(i).getReg();
1362 MachineInstr *BuildMBB = MRI.getVRegDef(Reg);
1363 // The register is not the result of G_BLOCK_ADDR, keep as-is.
1364 if (!BuildMBB || BuildMBB->getOpcode() != TargetOpcode::G_BLOCK_ADDR) {
1365 NewOps.push_back(MI->getOperand(i));
1366 continue;
1367 }
1368
1369 assert(BuildMBB && BuildMBB->getOpcode() == TargetOpcode::G_BLOCK_ADDR &&
1370 BuildMBB->getOperand(1).isBlockAddress() &&
1371 BuildMBB->getOperand(1).getBlockAddress());
1372 BasicBlock *BB =
1373 BuildMBB->getOperand(1).getBlockAddress()->getBasicBlock();
1374 auto It = BB2MBB.find(BB);
1375 if (It == BB2MBB.end())
1376 report_fatal_error("cannot find a machine basic block by a basic block "
1377 "in a switch statement");
1378 MachineBasicBlock *ReferencedBlock = It->second;
1379 NewOps.push_back(MachineOperand::CreateMBB(ReferencedBlock));
1380
1381 ClearAddressTaken.insert(ReferencedBlock);
1382 ToEraseMI.insert(BuildMBB);
1383 }
1384
1385 // Replace the operands.
1386 assert(MI->getNumOperands() == NewOps.size());
1387 while (MI->getNumOperands() > 0)
1388 MI->removeOperand(0);
1389 for (auto &MO : NewOps)
1390 MI->addOperand(MO);
1391
1392 if (MachineInstr *Next = MI->getNextNode()) {
1393 if (isSpvIntrinsic(*Next, Intrinsic::spv_track_constant)) {
1394 ToEraseMI.insert(Next);
1395 Next = MI->getNextNode();
1396 }
1397 if (Next && Next->getOpcode() == TargetOpcode::G_BRINDIRECT)
1398 ToEraseMI.insert(Next);
1399 }
1400 }
1401
1402 // BlockAddress operands were used to keep information between passes,
1403 // let's undo the "address taken" status to reflect that Succ doesn't
1404 // actually correspond to an IR-level basic block.
1405 for (MachineBasicBlock *Succ : ClearAddressTaken)
1406 Succ->setAddressTakenIRBlock(nullptr);
1407
1408 // If we just delete G_BLOCK_ADDR instructions with BlockAddress operands,
1409 // this leaves their BasicBlock counterparts in a "address taken" status. This
1410 // would make AsmPrinter to generate a series of unneeded labels of a "Address
1411 // of block that was removed by CodeGen" kind. Let's first ensure that we
1412 // don't have a dangling BlockAddress constants by zapping the BlockAddress
1413 // nodes, and only after that proceed with erasing G_BLOCK_ADDR instructions.
1414 Constant *Replacement =
1415 ConstantInt::get(Type::getInt32Ty(MF.getFunction().getContext()), 1);
1416 for (MachineInstr *BlockAddrI : ToEraseMI) {
1417 if (BlockAddrI->getOpcode() == TargetOpcode::G_BLOCK_ADDR) {
1418 BlockAddress *BA = const_cast<BlockAddress *>(
1419 BlockAddrI->getOperand(1).getBlockAddress());
1421 ConstantExpr::getIntToPtr(Replacement, BA->getType()));
1422 BA->destroyConstant();
1423 }
1424 invalidateAndEraseMI(GR, BlockAddrI);
1425 }
1426}
1427
1429 if (MBB.empty())
1430 return MBB.getNextNode() != nullptr;
1431
1432 // Branching SPIR-V intrinsics are not detected by this generic method.
1433 // Thus, we can only trust negative result.
1434 if (!MBB.canFallThrough())
1435 return false;
1436
1437 // Otherwise, we must manually check if we have a SPIR-V intrinsic which
1438 // prevent an implicit fallthrough.
1439 for (MachineBasicBlock::reverse_iterator It = MBB.rbegin(), E = MBB.rend();
1440 It != E; ++It) {
1441 if (isSpvIntrinsic(*It, Intrinsic::spv_switch))
1442 return false;
1443 }
1444 return true;
1445}
1446
1448 MachineIRBuilder MIB) {
1449 // It is valid for MachineBasicBlocks to not finish with a branch instruction.
1450 // In such cases, they will simply fallthrough their immediate successor.
1451 for (MachineBasicBlock &MBB : MF) {
1453 continue;
1454
1455 assert(MBB.succ_size() == 1);
1456 MIB.setInsertPt(MBB, MBB.end());
1457 MIB.buildBr(**MBB.successors().begin());
1458 }
1459}
1460
1462 // Initialize the type registry.
1463 const SPIRVSubtarget &ST = MF.getSubtarget<SPIRVSubtarget>();
1464 SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
1465 GR->setCurrentFunc(MF);
1466 MachineIRBuilder MIB(MF);
1467 // a registry of target extension constants
1468 DenseMap<MachineInstr *, Type *> TargetExtConstTypes;
1469 // to keep record of tracked constants
1470 addConstantsToTrack(MF, GR, ST, TargetExtConstTypes);
1471 foldConstantsIntoIntrinsics(MF, GR, MIB);
1472 insertBitcasts(MF, GR, MIB);
1473 generateAssignInstrs(MF, GR, MIB, TargetExtConstTypes);
1474
1475 processSwitchesConstants(MF, GR, MIB);
1476 processBlockAddr(MF, GR, MIB);
1478
1479 processInstrsWithTypeFolding(MF, GR, MIB);
1481 insertSpirvDecorations(MF, GR, MIB);
1482 insertInlineAsm(MF, GR, ST, MIB);
1483 lowerBitcasts(MF, GR, MIB);
1484
1485 return true;
1486}
1487
1488INITIALIZE_PASS(SPIRVPreLegalizerLegacy, DEBUG_TYPE, "SPIRV pre legalizer",
1489 false, false)
1490
1491char SPIRVPreLegalizerLegacy::ID = 0;
1492
1493FunctionPass *llvm::createSPIRVPreLegalizerLegacyPass() {
1494 return new SPIRVPreLegalizerLegacy();
1495}
1496
1497bool SPIRVPreLegalizerLegacy::runOnMachineFunction(MachineFunction &MF) {
1498 return runPreLegalizer(MF);
1499}
1500
1501PreservedAnalyses
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
Contains matchers for matching SSA Machine Instructions.
Register Reg
Register const TargetRegisterInfo * TRI
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 std::optional< unsigned > getNarrowScalarWidth(Register Reg, const MachineRegisterInfo &MRI)
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 NarrowWideningInfo recordNarrowOperandWidths(MachineFunction &MF, const MachineRegisterInfo &MRI)
static void removeImplicitFallthroughs(MachineFunction &MF, MachineIRBuilder MIB)
static unsigned widenBitWidthToNextPow2(unsigned BitWidth)
static void setInsertPtAfterDef(MachineIRBuilder &MIB, MachineInstr *Def)
static bool isWidthSensitiveBitCountOp(unsigned Opcode)
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 widenSignSensitiveOps(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB, MachineRegisterInfo &MRI, const NarrowWideningInfo &Info)
static void buildOpBitcast(SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB, Register ResVReg, Register OpReg)
static void processBlockAddr(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
static void widenBitCountOps(SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB, MachineRegisterInfo &MRI, const NarrowWideningInfo &Info)
static void widenScalarType(Register Reg, MachineRegisterInfo &MRI)
static const ConstantInt * getSwitchCaseValue(Register Reg, const MachineRegisterInfo &MRI, LLVMContext &Ctx)
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)
The Input class is used to parse a yaml document into in-memory structs and vectors.
APInt bitcastToAPInt() const
Definition APFloat.h:1475
Class for arbitrary precision integers.
Definition APInt.h:78
uint64_t getZExtValue() const
Get zero extended value.
Definition APInt.h:1560
LLVM_ABI APInt zextOrTrunc(unsigned width) const
Zero extend or truncate to width.
Definition APInt.cpp:1078
unsigned getBitWidth() const
Return the number of bits in the APInt.
Definition APInt.h:1508
APInt shl(unsigned shiftAmt) const
Left-shift function.
Definition APInt.h:875
bool isSubsetOf(const APInt &RHS) const
This operation checks that all bits set in this APInt are also set in RHS.
Definition APInt.h:1261
static APInt getLowBitsSet(unsigned numBits, unsigned loBitsSet)
Constructs an APInt value that has the bottom loBitsSet bits set.
Definition APInt.h:302
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
Definition APInt.h:235
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:782
iterator end()
Definition DenseMap.h:702
bool erase(const KeyT &Val)
Definition DenseMap.h:946
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
Definition DenseMap.h:872
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:356
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.
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:68
Metadata node.
Definition Metadata.h:1081
const MDOperand & getOperand(unsigned I) const
Definition Metadata.h:1437
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 buildZExtInReg(const DstOp &Res, const SrcOp &Op, int64_t ImmOp)
Build and inserts Res = G_AND Op, LowBitsSet(ImmOp) Since there is no G_ZEXT_INREG like G_SEXT_INREG,...
MachineInstrBuilder buildAnd(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1)
Build and insert Res = G_AND Op0, Op1.
MachineInstrBuilder buildSub(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_SUB Op0, Op1.
MachineInstrBuilder buildShl(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
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.
void setInstrAndDebugLoc(MachineInstr &MI)
Set the insertion point to before MI, and set the debug loc to MI's loc.
MachineInstrBuilder buildBitcast(const DstOp &Dst, const SrcOp &Src)
Build and insert Dst = G_BITCAST Src.
MachineRegisterInfo * getMRI()
Getter for MRI.
MachineInstrBuilder buildOr(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_OR Op0, Op1.
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.
const TargetRegisterInfo * getTargetRegisterInfo() const
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
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
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:299
static LLVM_ABI Type * getVoidTy(LLVMContext &C)
Definition Type.cpp:272
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:257
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.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
operand_type_match m_Reg()
ConstantMatch< APInt > m_ICst(APInt &Cst)
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
BinaryOp_match< LHS, RHS, TargetOpcode::G_AND, true > m_GAnd(const LHS &L, const RHS &R)
bind_ty< MachineInstr * > m_MInstr(MachineInstr *&MI)
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > dyn_extract(Y &&MD)
Extract a Value from Metadata, if any.
Definition Metadata.h:707
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
Register createVirtualRegister(SPIRVTypeInst SpvType, SPIRVGlobalRegistry *GR, MachineRegisterInfo *MRI, const MachineFunction &MF)
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)
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
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)
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
Definition InstrProf.h:145
DWARFExpression::Operation Op
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)
SmallVector< MachineInstr * > SignSensitiveWorklist
DenseMap< Register, unsigned > OrigWidth
SmallVector< std::pair< MachineInstr *, unsigned > > BitCountWorklist