[SPIRV] Legalize byte-buffer reinterpretation ptrcasts (#192523) (#212999)
Fixes #192523 by extending SPIRVLegalizePointerCast to legalize
reinterpretation spv.ptrcasts on byte-addressable buffers ([0 x i8] /
RWByteAddressBuffer). When Clang emits a typed load or store through
such a pointer (e.g. i32, <4 x i32>), the pass now lowers it to valid
logical SPIR-V instead of hitting an unreachable or producing invalid
OpAccessChain into uchar storage.
For HLSL/Vulkan byte-address buffers, codegen produced IR like:
1. spv.resource.getpointer → pointer tagged as i8 byte storage
2. spv.ptrcast → pointer tagged as the access type (i32, vector, etc.)
3. Typed load/store through the cast
The existing legalizer only handled aggregate layout mismatches (GEP
drilling, partial vector loads). When getPointerToFirstCompatibleType()
found no compatible nested type—as with flat byte buffers—it hit
llvm_unreachable.
A naive fix (retag the original pointer to the access type and emit a
single typed access) avoids the crash but produces invalid SPIR-V:
OpAccessChain with a vector/scalar result type into a uchar runtime
array, which spirv-val rejects.
Solution is to add a reinterpretation fallback when aggregate drilling
fails. The pass classifies the case and chooses one of two strategies:
- ByteWise : when original layout is i8, access is multi-byte
scalar/vector use per-byte i8 load/store loop
- RetagDirect : other reinterpretations (e.g. single-byte access) simply
retag pointer via spv_assign_ptr_type, then use typed access
Co-authored-by: Cursor