Issue 203586
Summary SPIRV backend asserts on addl/subc intrinsics used in switch
Labels new issue
Assignees
Reporter sarnex
    Given the following example

```
unsigned long f(unsigned long a, unsigned long b, int sel) {
  unsigned long v;
 int of;
  switch (sel) {
  case 0:
    of = __builtin_uaddl_overflow(a, b, &v);
    break;
  case 1:
    of = __builtin_usubl_overflow(a, b, &v);
 break;
  default:
    of = __builtin_uaddl_overflow(a, a, &v);
 break;
  }
  return of ? v : v + 1;
}
```

We see the below asserting when compiling for `spirv64` with `O2`:

```
nsarnie:/llvm/build$ bin/clang -target spirv64 -O2 repro.c
PHI node operands are not the same type as the result!
  %.pn = phi i32 [ %2, %sw.default ], [ %1, %sw.bb ], [ %0, %sw.bb1 ]
in function f
fatal error: error in backend: Broken function found, compilation aborted!

```

The IR before `spirv-emit-intrinsics` looks like

```
define spir_func i64 @f(i64 noundef %a, i64 noundef %b, i32 noundef %sel) local_unnamed_addr #0 {
entry:
  switch i32 %sel, label %sw.default [
    i32 0, label %sw.bb
    i32 1, label %sw.bb1
 ]

sw.bb1:                                           ; preds = %entry
  %0 = tail call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %a, i64 %b)
  br label %sw.epilog

sw.bb:                                            ; preds = %entry
  %1 = tail call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 %a, i64 %b)
  br label %sw.epilog

sw.default: ; preds = %entry
  %2 = tail call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 %a, i64 %a)
  br label %sw.epilog

sw.epilog:                                        ; preds = %sw.default, %sw.bb1, %sw.bb
  %.pn = phi { i64, i1 } [ %2, %sw.default ], [ %1, %sw.bb ], [ %0, %sw.bb1 ]
  %of.0.in = extractvalue { i64, i1 } %.pn, 1
  %v.0 = extractvalue { i64, i1 } %.pn, 0
  %not.of.0.in = xor i1 %of.0.in, true
  %add = zext i1 %not.of.0.in to i64
  %cond = add i64 %v.0, %add
  ret i64 %cond
}
```

The problem is that in `spirv-emit-intrinsics`, we mutate the type of the PHI node to be i32 to prevent the IRTranslator from seeing a multi-register type (added [here](https://github.com/llvm/llvm-project/pull/186086)), but nothing mutates the incoming blocks to the PHI, so there is a type mismatch(`i32` vs `{ i64, i1 }`), causing the problem.

I'm not totally sure what the fix would be. It seems like we have to mutate the PHI to `i32` to prevent other issues, but then we need to deal with the `CallInst` somehow. Maybe we need a new `spv_usub_with_overflow`? Not sure.


_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to