Issue 175394
Summary [x86-Backend] Attrocious code when using a multiple of the index of the most significant bit.
Labels new issue
Assignees
Reporter ActuallyaDeviloper
    I have been looking at some cases of bad code generation around `llvm.ctlz` with x86. One case that is particularly badly handled is if an integer multiple of the index of the most significant bit is used.

C code:
```
static inline int findFirstBit(int i) { return 31 - __builtin_clz(i); }

int getFloatOffset(int pattern) { return findFirstBit(pattern) * 4; }
int getDoubleOffset(int pattern) { return findFirstBit(pattern) * 8; }
```

LLVM Bitcode before codegen:
```
define dso_local noundef range(i32 0, 125) i32 @getFloatOffset(int)(i32 noundef %pattern) local_unnamed_addr {
entry:
  %0 = tail call range(i32 0, 33) i32 @llvm.ctlz.i32(i32 %pattern, i1 true)
 %sub.i = shl nuw nsw i32 %0, 2
  %mul = xor i32 %sub.i, 124
  ret i32 %mul
}

define dso_local noundef range(i32 0, 249) i32 @getDoubleOffset(int)(i32 noundef %pattern) local_unnamed_addr {
entry:
 %0 = tail call range(i32 0, 33) i32 @llvm.ctlz.i32(i32 %pattern, i1 true)
 %sub.i = shl nuw nsw i32 %0, 3
  %mul = xor i32 %sub.i, 248
  ret i32 %mul
}
```

LLVM is trying to be smart about the XOR. Doesn't help if you try outsmart it with "31 - x".

Now as a result, the assembly becomes attrocious:
```
getFloatOffset(int):
        bsr     eax, edi
        xor eax, 31
        shl     eax, 2
        xor     eax, 124
 ret

getDoubleOffset(int):
        bsr     eax, edi
        xor     eax, 31
        xor     eax, 31 ; Are you serious?
        shl     eax, 3
 ret
```

When compiling for AVX2, the compiler uses `lzcnt` which makes it look a bit less bad but `bsr` would be best still.

This issue seems related although the case is a bit different: https://github.com/llvm/llvm-project/issues/150954.
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to