@@ -192,31 +192,43 @@ 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+ assert (
216+ DstType &&
217+ " Expected destination SPIR-V type to have been assigned already." );
218+ SPIRVType *SrcType = GR->getSPIRVTypeForVReg (SrcReg);
219+ assert (SrcType &&
220+ " Expected source SPIR-V type to have been assigned already." );
221+ if (DstType == SrcType) {
222+ MIB.setInsertPt (*MI.getParent (), MI);
223+ MIB.buildCopy (DstReg, SrcReg);
224+ ToErase.push_back (&MI);
225+ continue ;
226+ }
227+ }
228+
218229 if (MI.getOpcode () != TargetOpcode::G_BITCAST)
219230 continue ;
231+
220232 MIB.setInsertPt (*MI.getParent (), MI);
221233 buildOpBitcast (GR, MIB, MI.getOperand (0 ).getReg (),
222234 MI.getOperand (1 ).getReg ());
@@ -237,16 +249,11 @@ static void insertBitcasts(MachineFunction &MF, SPIRVGlobalRegistry *GR,
237249 SmallVector<MachineInstr *, 10 > ToErase;
238250 for (MachineBasicBlock &MBB : MF) {
239251 for (MachineInstr &MI : MBB) {
240- if (!isSpvIntrinsic (MI, Intrinsic::spv_bitcast) &&
241- !isSpvIntrinsic (MI, Intrinsic::spv_ptrcast))
252+ if (!isSpvIntrinsic (MI, Intrinsic::spv_ptrcast))
242253 continue ;
243254 assert (MI.getOperand (2 ).isReg ());
244255 MIB.setInsertPt (*MI.getParent (), MI);
245256 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- }
250257 Register Def = MI.getOperand (0 ).getReg ();
251258 Register Source = MI.getOperand (2 ).getReg ();
252259 Type *ElemTy = getMDOperandAsType (MI.getOperand (3 ).getMetadata (), 0 );
@@ -1089,7 +1096,7 @@ bool SPIRVPreLegalizer::runOnMachineFunction(MachineFunction &MF) {
10891096 removeImplicitFallthroughs (MF, MIB);
10901097 insertSpirvDecorations (MF, GR, MIB);
10911098 insertInlineAsm (MF, GR, ST, MIB);
1092- selectOpBitcasts (MF, GR, MIB);
1099+ lowerBitcasts (MF, GR, MIB);
10931100
10941101 return true ;
10951102}
0 commit comments