<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/66675>66675</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            [LoopRotate] Incorrect branch weights updating
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          aleks-tmb
      </td>
    </tr>
</table>

<pre>
    In the revision https://reviews.llvm.org/D157462 branch weights updating was added to the `LoopRotate`. 
But let's run the pass `bin/opt -passes=loop-rotate test.ll` on with the test case with `1:0` weights ratio:
```llvm
declare void @llvm.experimental.deoptimize.isVoid(...)

define void @test(ptr addrspace(1) %0, i32 %limit) {
  br label %loop

loop: ; preds = %guarded, %1
  %iv = phi i32 [ %iv.next, %guarded ], [ 0, %1 ]
  %gc = icmp slt i32 %iv, %limit
  br i1 %gc, label %guarded, label %exit, !prof !0

guarded: ; preds = %loop
  %iv.next = add i32 %iv, 1
 %load = load atomic ptr addrspace(1), ptr addrspace(1) %0 unordered, align 8
  %ec = icmp eq ptr addrspace(1) %load, null
  br i1 %ec, label %deopt, label %loop

deopt: ; preds = %guarded
  call void (...) @llvm.experimental.deoptimize.isVoid(i32 11) [ "deopt"(i32 0) ]
  ret void

exit:                                             ; preds = %loop
  ret void
}

!0 = !{!"branch_weights", i32 1, i32 0}
```
Resulting branch weigths looks weird:
```llvm
define void @test(ptr addrspace(1) %0, i32 %limit) {
  %gc1 = icmp slt i32 0, %limit
  br i1 %gc1, label %guarded.lr.ph, label %exit, !prof !0

guarded.lr.ph:                                    ; preds = %1
 br label %guarded

loop:                                             ; preds = %guarded
  %iv = phi i32 [ %iv.next, %guarded ]
  %gc = icmp slt i32 %iv, %limit
  br i1 %gc, label %guarded, label %loop.exit_crit_edge, !prof !1

guarded: ; preds = %guarded.lr.ph, %loop
  %iv2 = phi i32 [ 0, %guarded.lr.ph ], [ %iv, %loop ]
  %iv.next = add i32 %iv2, 1
  %load = load atomic ptr addrspace(1), ptr addrspace(1) %0 unordered, align 8
  %ec = icmp eq ptr addrspace(1) %load, null
  br i1 %ec, label %deopt, label %loop

deopt:                                            ; preds = %guarded
  call void (...) @llvm.experimental.deoptimize.isVoid(i32 11) [ "deopt"(i32 0) ]
  ret void

loop.exit_crit_edge: ; preds = %loop
  br label %exit

exit: ; preds = %loop.exit_crit_edge, %1
  ret void
}

!0 = !{!"branch_weights", i32 -1, i32 1}
!1 = !{!"branch_weights", i32 -2147483647, i32 -1}
```

It seems the reason is that we don't scale `OrigLoopExitWeight` when it's `0`:
https://github.com/llvm/llvm-project/blob/main/llvm/lib/Transforms/Utils/LoopRotationUtils.cpp#L314
```cpp
 // Scale up counts if necessary so we can match `ZeroTripCountWeights` for
      // the `ExitWeight0`:`ExitWeight1` (aka `x0`:`x1` ratio`) ratio.
      while (OrigLoopExitWeight < ZeroTripCountWeights[1] + ExitWeight0) {
        // ... but don't overflow.
        uint32_t const HighBit = uint32_t{1} << (sizeof(uint32_t) * 8 - 1);
        if ((OrigLoopBackedgeWeight & HighBit) != 0 ||
 (OrigLoopExitWeight & HighBit) != 0)
          break;
 OrigLoopBackedgeWeight <<= 1;
        OrigLoopExitWeight <<= 1;
 }
```
and the subsequent computation overflowing:
`uint32_t ExitWeight1 = OrigLoopExitWeight - ExitWeight0; `
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzkWE2P2zYT_jX0ZbCCSFmyfPBhvX6NN0CAAmnaAL0sKGlssUuRCkmtN_n1BSnJltd2vhq0hy6MtTQcDp_5ekiTWyv2CnFF0jVJNzPeuVqbFZf4ZO9cU8wKXX1avVHgagSDz8IKraB2rrUkuSdsS9jWi_FgIymfm0ibPWHbDU0X84xBYbgqazig2NfOQtdW3Am1hwO3wKsKK3A6mCZZ_Fbr9p123CHJ4ghIvCHx_bpzINERtrBguh5Gy631EwqhCNvq1sGdF6ElyUZq3d6ZYAUcWhdJSbIYtIKDcHWY7sVQcou9iGQxJcl97NVGnIY7ob1_AQPJ4v7jHexFFZaSG4RnLSog8zAS4UuLRjSoHJdRhbp1ohGfMRL2dy0qwvIoighbDkYHOzuhTmY8NMLy1hkfHWNbXiJhOSVsCYSlMWEPIBLmn6VohAvyxbq3BVAYkLxAGca1bqcrhffkHkiyhtZgZYEkG6-477ipsPKmCUvpaIuwVDwHnbYW_aLpupdGCl_coD_MBpJugiRdQzyaCsKTuX0ZzImyacFKNzoingf93qOTK4L2s_zw0a0J2qMMX8QAh7ZG7_x3PHV9nHPN-1OYYOJcGOVVdY5xjE2YxqugFB64040o4Vra_Lyb6YROaVOh6f3hUuwV5BM0OIkYfrxpx2PwBlQn5UX88Dx-oSzPJK8Lpdf4UqUMS5RcyqFyx9L-9lbwgaW9A6Gs2ACMDWNxP3SsH4MurDVFGvKe3MP3_H2xAF4tsthMV_NVNUyivucYJYz1_PY48EaA33coHR_ik5mRRvrXd2g7GchwQpKutiC1frL-zVRfpqCfSR2h0-hlg8ZfaU56rTsjaaK2_pEeHWZ-W1Ivcjk26JQHz4r2nAr_Vt28aoYfoMt_gBm9p5EP_WNphHvEao-vkkC_lSgvUnuNPNlFBOJzx_vp093izE-t21ehuUnIbMrI_xVK_okF-6-z97Xa_NoOPW3swChXdoOrBq42wemw8xOJ_46etoCjHUbpd1hgdL6Y50k2X0yM3thF-v9vHFjExg6ndG61AuHfuIMDQqUVYQsHtuQyHLV_MWLvj9v_exHuQwAQTr81KhD9WZtkcVhk3IDOT_x74equiErdELYNW1L_ddca_SeWjrBtIXVB2Lbh4ZA-6ggve2-4sjttGkvY9jcnpP8-nv6FVkEWlW1LWPI2ofNXnvuB8STm0cCvwa-uhVJ3ylkQO1BYorXcfAKrfQhKrqDhrgzn_T_Q6PdGtA9e_cOQgCyGnTZjRYQW6q0PP09OsRoDM5VRP5-wnD9xr_xy0nkJQ_0viiw0RniOpisdauETw_LLxABJHuAq4HRNSeprag1TbOf7-pknURRB0bljPehnNDupD9G5dieUS9ijg1Ir6-D_Yl-vRU_B4xBZrH1JenAeH2G5FZ9R7wjLjyqBCe8hhzsItJu8AiX8BpRPnF7z8sl35-g4y8a1e1vUI4iBLB78Z6yAqzG7PvX44-tEk4VB_nSCdgtKcNPboBduXE_ZpfqtDuaqCiVmu8Lixw6Vj3vTdn0rHHMk1H56GjzmaFKCIUNX4Nyd1Uey9gU6q1ZJtUyWfIYrmi3TOM2zdD6rV1lBOe6WdLEsWI55MafLdImsyHaszFNWzMSKxSyJlzSni2SRzCOaYJrlvEyTnKbxAsk8xoYLebwPmAlrO1xlWbZIZ4G_bbhuYEzhAcKgp790MzOrwCJFt7d-LxLWnW4VZk44Ge4pJhcF6QbeqFIbg6W7ddkw64xcfTd_BViemALsvwIAAP__TCDe-g">