| Issue |
204519
|
| Summary |
LLVM generates UNPREDICTABLE T2 encoding for `CMP` on low registers at -O0
|
| Labels |
new issue
|
| Assignees |
|
| Reporter |
sirchnik
|
When compiling an atomic compare-and-swap loop for `thumbv8m.main-none-eabi` at `-O0`, LLVM generates an invalid instruction encoding for a `CMP` instruction.
Specifically, it emits the T2 encoding of `CMP (register)` (`0x4508`) to compare `r0` and `r1`. Per the Armv8-M Architecture Reference Manual, the T2 encoding has a strict constraint: `Rn` and `Rm` must not both be from `R0-R7`, otherwise the instruction is UNPREDICTABLE. Because both registers are low registers here, the T1 encoding (`4288`) should be used instead.
This only triggers at `-O0`; higher optimization levels (`-Os`, `-O2`) lower the atomic loop using different instructions.
### Reproduction
```c
// test.c
#include <stdbool.h>
#include <stdatomic.h>
_Atomic unsigned int bound_to_thread = 0;
bool try_begin_binding(void) {
unsigned int expected = 0;
return atomic_compare_exchange_strong_explicit(
&bound_to_thread, &expected, 1, memory_order_relaxed, memory_order_relaxed
);
}
```
```bash
clang -target thumbv8m.main-none-eabi -O0 -g0 -c test.c -o test.o && arm-none-eabi-objdump -d test.o
```
### Actual
```asm
18: e853 0f00 ldrex r0, [r3]
1c: 4508 cmp r0, r1 <-- Invalid T2 encoding for low regs
1e: d103 bne.n 28 <try_begin_binding+0x28>
20: e843 c200 strex r2, ip, [r3]
```
### Expected
The compiler should emit the T1 encoding (`4288` / `cmp r0, r1`):
```asm
18: e853 0f00 ldrex r0, [r3]
1c: 4288 cmp r0, r1
1e: d103 bne.n 28 <try_begin_binding+0x28>
20: e843 c200 strex r2, ip, [r3]
```
### Environment
* Clang version: 22.1.6
* Target: `thumbv8m.main-none-eabi`
First found for Rust [here](https://github.com/rust-lang/rust/issues/157956)
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs