[SPIRV] Expand aggregate instructions with mutated-type uses (#206835)
This is a workaround for the problem in GH issue
https://github.com/llvm/llvm-project/issues/203586.
The problem is that we need to mutate aggregate-typed PHI nodes to
`i32`, however that means all incoming values need to have a matching
type, but we can't always easily mutate the incoming types to i32, as in
the case in the GH issue with a math intrinsic that returns a struct
by-value.
We do the same mutation for some other cases like `freeze`, the
workaround is the same.
The workaround is to expand the incoming values to a form that will also
be mutated to i32 so the types match. An example transformation is
below:
Before
```
...
bb1: ; preds = %entry
%0 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %a, i64 %b)
br label %epilog
...
%2 = phi { i64, i1 } [ %1, %bb0 ], [ %0, %bb1 ]
```
After
```
...
bb1: ; preds = %entry
%0 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %a, i64 %b)
%1 = extractvalue { i64, i1 } %0, 0
%2 = insertvalue { i64, i1 } poison, i64 %1, 0
%3 = extractvalue { i64, i1 } %0, 1
%4 = insertvalue { i64, i1 } %2, i1 %3, 1
br label %epilog
...
%10 = phi { i64, i1 } [ %9, %bb0 ], [ %4, %bb1 ]
```
`insertvalue` get replaced with a SPIR-V intrinsic later in the pass
which is also type-mutated, so the IR is correct:
```
...
bb1: ; preds = %entry
%0 = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %a, i64 %b)
call void @llvm.spv.value.md(metadata !0)
call void (...) @llvm.fake.use({ i64, i1 } %0)
%1 = extractvalue { i64, i1 } %0, 0
call void @llvm.spv.assign.type.i64(i64 %1, metadata i64 poison)
call void @llvm.spv.assign.type.i32(i32 undef, metadata { i64, i1 } poison)
%2 = call i32 (i32, i64, ...) @llvm.spv.insertv.i64(i32 undef, i64 %1, i32 0)
call void @llvm.spv.assign.type.i32(i32 %2, metadata { i64, i1 } poison)
%3 = extractvalue { i64, i1 } %0, 1
call void @llvm.spv.assign.type.i1(i1 %3, metadata i1 poison)
%4 = call i32 (i32, i1, ...) @llvm.spv.insertv.i1(i32 %2, i1 %3, i32 1)
call void @llvm.spv.assign.type.i32(i32 %4, metadata { i64, i1 } poison)
br label %epilog
...
%10 = phi i32 [ %9, %bb0 ], [ %4, %bb1 ]
```
This is the simplest change I could come up with, my other ideas were
much more complicated and/or risky.
This fix is important for us because this pattern comes up in libc's
implementation on FMA, so this is blocking SPIR-V libc support.
Fixes: https://github.com/llvm/llvm-project/issues/203586
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Nick Sarnie <nick.sarnie@intel.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>