<html>
    <head>
      <base href="https://bugs.llvm.org/">
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - Folding common switch code"
   href="https://bugs.llvm.org/show_bug.cgi?id=52396">52396</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>Folding common switch code
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>libraries
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>trunk
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>PC
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>Windows NT
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>enhancement
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>Scalar Optimizations
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>unassignedbugs@nondot.org
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>llvm@rifkin.dev
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>llvm-bugs@lists.llvm.org
          </td>
        </tr></table>
      <p>
        <div>
        <pre>LLVM optimizes common switch cases but clang is not producing the best codegen
for the following example:

void foo(int x) {
    switch(x) {
        case 2: func(x); break;
        case 3: func(x); break;
        case 4: func(x); break;
        case 5: func(x); break;
        case 6: func(x); break;
        default: __builtin_unreachable();
    }
}

void bar(int x) {
    switch(x) {
        case 1: func(x); break;
        case 4: func(x); break;
        case 7: func(x); break;
        case 3: func(x); break;
        case 9: func(x); break;
        default: __builtin_unreachable();
    }
}

foo(int):                                # @foo(int)
        jmp     func2(int)                       # TAILCALL

bar(int):                                # @bar(int)
        add     edi, -1
        movsxd  rax, edi
        mov     edi, dword ptr [4*rax + .Lswitch.table.bar(int)]
        jmp     func2(int)                       # TAILCALL
.Lswitch.table.bar(int):
        .long   1                               # 0x1
        .long   1                               # 0x1
        .long   3                               # 0x3
        .long   4                               # 0x4
        .long   1                               # 0x1
        .long   1                               # 0x1
        .long   7                               # 0x7
        .long   1                               # 0x1
        .long   9                               # 0x9

<a href="https://godbolt.org/z/Ya34bneoT">https://godbolt.org/z/Ya34bneoT</a>

It appears LLVM propagates the constant x early in the optimization, pulls out
the common calls to func(), then later eliminates the switches during
SimplifyCFG. LLVM optimizes foo based off the switch case values being
sequential, with non-sequential values it doesn't undo the constant
propagation:

*** IR Dump After InstCombinePass on _Z3bari ***
; Function Attrs: mustprogress uwtable
define dso_local void @_Z3bari(i32 %0) local_unnamed_addr #0 {
  switch i32 %0, label %6 [
    i32 1, label %7
    i32 4, label %2
    i32 7, label %3
    i32 3, label %4
    i32 9, label %5
  ]
2:                                                ; preds = %1
  br label %7
3:                                                ; preds = %1
  br label %7
4:                                                ; preds = %1
  br label %7
5:                                                ; preds = %1
  br label %7
6:                                                ; preds = %1
  unreachable
7:                                                ; preds = %1, %5, %4, %3, %2
  %8 = phi i32 [ 9, %5 ], [ 3, %4 ], [ 7, %3 ], [ 4, %2 ], [ 1, %1 ]
  tail call void @_Z4funci(i32 %8)
  ret void
}
*** IR Dump After SimplifyCFGPass on _Z3bari ***
; Function Attrs: mustprogress uwtable
define dso_local void @_Z3bari(i32 %0) local_unnamed_addr #0 {
  %2 = sub i32 %0, 1
  %3 = trunc i32 %2 to i16
  %4 = lshr i16 333, %3
  %5 = trunc i16 %4 to i1
  call void @llvm.assume(i1 %5)
  %6 = getelementptr inbounds [9 x i32], [9 x i32]* @switch.table._Z3bari, i32
0, i32 %2
  %7 = load i32, i32* %6, align 4
  tail call void @_Z4funci(i32 %7)
  ret void
}</pre>
        </div>
      </p>


      <hr>
      <span>You are receiving this mail because:</span>

      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>