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