Skip to content

Commit dd1d522

Browse files
committed
[SPIRV] Expand spv_bitcast intrinsic during instruction selection
The spv_bitcast intrinsic is currently replaced by an OpBitcast during prelegalization. This will cause a problem when we need to legalize the OpBitcast. The legalizer assumes that instruction already lowered to a target specific opcode is legal. We cannot lower it to a G_BITCAST because the bitcasts sometimes the LLT type will be the same, causing an error in the verifier, even if the SPIR-V types will be different. This commit keeps the intrinsic around until instructoin selection. We can create rules to legalize a G_INTRINISIC* instruction, and it does not create problem for the verifier.
1 parent 6bee6b2 commit dd1d522

File tree

2 files changed

+37
-27
lines changed

2 files changed

+37
-27
lines changed

llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3119,6 +3119,14 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
31193119
return selectInsertElt(ResVReg, ResType, I);
31203120
case Intrinsic::spv_gep:
31213121
return selectGEP(ResVReg, ResType, I);
3122+
case Intrinsic::spv_bitcast: {
3123+
Register OpReg = I.getOperand(2).getReg();
3124+
SPIRVType *OpType =
3125+
OpReg.isValid() ? GR.getSPIRVTypeForVReg(OpReg) : nullptr;
3126+
if (!GR.isBitcastCompatible(ResType, OpType))
3127+
report_fatal_error("incompatible result and operand types in a bitcast");
3128+
return selectOpWithSrcs(ResVReg, ResType, I, {OpReg}, SPIRV::OpBitcast);
3129+
}
31223130
case Intrinsic::spv_unref_global:
31233131
case Intrinsic::spv_init_global: {
31243132
MachineInstr *MI = MRI->getVRegDef(I.getOperand(1).getReg());

llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -192,31 +192,38 @@ static void buildOpBitcast(SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB,
192192
.addUse(OpReg);
193193
}
194194

195-
// We do instruction selections early instead of calling MIB.buildBitcast()
196-
// generating the general op code G_BITCAST. When MachineVerifier validates
197-
// G_BITCAST we see a check of a kind: if Source Type is equal to Destination
198-
// Type then report error "bitcast must change the type". This doesn't take into
199-
// account the notion of a typed pointer that is important for SPIR-V where a
200-
// user may and should use bitcast between pointers with different pointee types
201-
// (https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpBitcast).
202-
// It's important for correct lowering in SPIR-V, because interpretation of the
203-
// data type is not left to instructions that utilize the pointer, but encoded
204-
// by the pointer declaration, and the SPIRV target can and must handle the
205-
// declaration and use of pointers that specify the type of data they point to.
206-
// It's not feasible to improve validation of G_BITCAST using just information
207-
// provided by low level types of source and destination. Therefore we don't
208-
// produce G_BITCAST as the general op code with semantics different from
209-
// OpBitcast, but rather lower to OpBitcast immediately. As for now, the only
210-
// difference would be that CombinerHelper couldn't transform known patterns
211-
// around G_BUILD_VECTOR. See discussion
212-
// in https://github.com/llvm/llvm-project/pull/110270 for even more context.
213-
static void selectOpBitcasts(MachineFunction &MF, SPIRVGlobalRegistry *GR,
214-
MachineIRBuilder MIB) {
195+
// We lower G_BITCAST to OpBitcast here to avoid a MachineVerifier error.
196+
// The verifier checks if the source and destination LLTs of a G_BITCAST are
197+
// different, but this check is too strict for SPIR-V's typed pointers, which
198+
// may have the same LLT but different SPIRVType (e.g. pointers to different
199+
// pointee types). By lowering to OpBitcast here, we bypass the verifier's
200+
// check. See discussion in https://github.com/llvm/llvm-project/pull/110270
201+
// for more context.
202+
//
203+
// We also handle the llvm.spv.bitcast intrinsic here. If the source and
204+
// destination SPIR-V types are the same, we lower it to a COPY to enable
205+
// further optimizations like copy propagation.
206+
static void lowerBitcasts(MachineFunction &MF, SPIRVGlobalRegistry *GR,
207+
MachineIRBuilder MIB) {
215208
SmallVector<MachineInstr *, 16> ToErase;
216209
for (MachineBasicBlock &MBB : MF) {
217210
for (MachineInstr &MI : MBB) {
211+
if (isSpvIntrinsic(MI, Intrinsic::spv_bitcast)) {
212+
Register DstReg = MI.getOperand(0).getReg();
213+
Register SrcReg = MI.getOperand(2).getReg();
214+
SPIRVType *DstType = GR->getSPIRVTypeForVReg(DstReg);
215+
SPIRVType *SrcType = GR->getSPIRVTypeForVReg(SrcReg);
216+
if (DstType && SrcType && DstType == SrcType) {
217+
MIB.setInsertPt(*MI.getParent(), MI);
218+
MIB.buildCopy(DstReg, SrcReg);
219+
ToErase.push_back(&MI);
220+
continue;
221+
}
222+
}
223+
218224
if (MI.getOpcode() != TargetOpcode::G_BITCAST)
219225
continue;
226+
220227
MIB.setInsertPt(*MI.getParent(), MI);
221228
buildOpBitcast(GR, MIB, MI.getOperand(0).getReg(),
222229
MI.getOperand(1).getReg());
@@ -237,16 +244,11 @@ static void insertBitcasts(MachineFunction &MF, SPIRVGlobalRegistry *GR,
237244
SmallVector<MachineInstr *, 10> ToErase;
238245
for (MachineBasicBlock &MBB : MF) {
239246
for (MachineInstr &MI : MBB) {
240-
if (!isSpvIntrinsic(MI, Intrinsic::spv_bitcast) &&
241-
!isSpvIntrinsic(MI, Intrinsic::spv_ptrcast))
247+
if (!isSpvIntrinsic(MI, Intrinsic::spv_ptrcast))
242248
continue;
243249
assert(MI.getOperand(2).isReg());
244250
MIB.setInsertPt(*MI.getParent(), MI);
245251
ToErase.push_back(&MI);
246-
if (isSpvIntrinsic(MI, Intrinsic::spv_bitcast)) {
247-
MIB.buildBitcast(MI.getOperand(0).getReg(), MI.getOperand(2).getReg());
248-
continue;
249-
}
250252
Register Def = MI.getOperand(0).getReg();
251253
Register Source = MI.getOperand(2).getReg();
252254
Type *ElemTy = getMDOperandAsType(MI.getOperand(3).getMetadata(), 0);
@@ -1089,7 +1091,7 @@ bool SPIRVPreLegalizer::runOnMachineFunction(MachineFunction &MF) {
10891091
removeImplicitFallthroughs(MF, MIB);
10901092
insertSpirvDecorations(MF, GR, MIB);
10911093
insertInlineAsm(MF, GR, ST, MIB);
1092-
selectOpBitcasts(MF, GR, MIB);
1094+
lowerBitcasts(MF, GR, MIB);
10931095

10941096
return true;
10951097
}

0 commit comments

Comments
 (0)