[all-commits] [llvm/llvm-project] 6b9952: [SimplifyCFG] Simplify switch instruction that has...

Michael Maitland via All-commits all-commits at lists.llvm.org
Fri Nov 15 06:38:55 PST 2024


  Branch: refs/heads/main
  Home:   https://github.com/llvm/llvm-project
  Commit: 6b9952759f66c8bc62ef4c6700f586053f009296
      https://github.com/llvm/llvm-project/commit/6b9952759f66c8bc62ef4c6700f586053f009296
  Author: Michael Maitland <michaeltmaitland at gmail.com>
  Date:   2024-11-15 (Fri, 15 Nov 2024)

  Changed paths:
    M llvm/lib/Transforms/Utils/SimplifyCFG.cpp
    M llvm/test/Transforms/PhaseOrdering/switch-sext.ll
    M llvm/test/Transforms/SimplifyCFG/ForwardSwitchConditionToPHI.ll
    M llvm/test/Transforms/SimplifyCFG/HoistCode.ll
    A llvm/test/Transforms/SimplifyCFG/switch-dup-bbs.ll
    M llvm/test/Transforms/SimplifyCFG/switch-to-select-two-case.ll

  Log Message:
  -----------
  [SimplifyCFG] Simplify switch instruction that has duplicate arms (#114262)

I noticed that the two C functions emitted different IR:

```
int switch_duplicate_arms(int switch_val, int v, int w) {
  switch (switch_val) {
  default:
    break;
  case 0:
    w = v;
    break;
  case 1:
    w = v;
    break;
  }
  return w;
}

int if_duplicate_arms(int switch_val, int v, int w) {
  if (switch_val == 0)
    w = v;
  else if (switch_val == 1)
    w = v;
  return v0;
}
```

We generate IR that looks like this:

```
define i32 @switch_duplicate_arms(i32 %0, i32 %1, i32 %2, i32 %3) {
  switch i32 %1, label %7 [
    i32 0, label %5
    i32 1, label %6
  ]

5:
  br label %7

6:
  br label %7

7:
  %8 = phi i32 [ %3, %4 ], [ %2, %6 ], [ %2, %5 ]
  ret i32 %8
}

define i32 @if_duplicate_arms(i32 %0, i32 %1, i32 %2, i32 %3) {
  %5 = icmp ult i32 %1, 2
  %6 = select i1 %5, i32 %2, i32 %3
  ret i32 %6
}
```

For `switch_duplicate_arms`, taking case 0 and 1 are the same since %5
and %6
branch to the same location and the incoming values for %8 are the same
from
those blocks. We could remove one on the duplicate switch targets and
update
the switch with the single target.

On RISC-V, prior to this patch, we generate the following code:
```
switch_duplicate_arms:
        li      a4, 1
        beq     a1, a4, .LBB0_2
        mv      a0, a3
        bnez    a1, .LBB0_3
.LBB0_2:
        mv      a0, a2
.LBB0_3:
        ret

if_duplicate_arms:
        li      a4, 2
        mv      a0, a2
        bltu    a1, a4, .LBB1_2
        mv      a0, a3
.LBB1_2:
        ret
```

After this patch, the O3 code is optimized to the icmp + select pair,
which
gives us the same code gen as `if_duplicate_arms`, as desired. This
results
is one less branch instruction in the final assembly.

This may help with both code size and further switch simplification. I
found
that this patch causes no significant impact to spec2006/int/ref and
spec2017/intrate/ref.

---------

Co-authored-by: Min Hsu <min at myhsu.dev>



To unsubscribe from these emails, change your notification settings at https://github.com/llvm/llvm-project/settings/notifications


More information about the All-commits mailing list