Skip to content

[LoongArch] Incorrect register allocation for [G]CSRXCHG - rj must not be R0 ro R1 #140842

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
heiher opened this issue May 21, 2025 · 1 comment · Fixed by #140862
Closed

[LoongArch] Incorrect register allocation for [G]CSRXCHG - rj must not be R0 ro R1 #140842

heiher opened this issue May 21, 2025 · 1 comment · Fixed by #140862

Comments

@heiher
Copy link
Member

heiher commented May 21, 2025

In the LoongArch target, the [G]CSRXCHG instruction has a special encoding constraint:

If the rj operand is assigned to register R0 or R1, the instruction encoding will be interpreted as [G]CSRRD or [G]CSRWR respectively, not [G]CSRXCHG.

Currently, LLVM’s register allocator may assign R0 or R1 to the rj operand of a [G]CSRXCHG instruction, which leads to incorrect code generation and unintended semantics.

Reproduce case:

declare i64 @llvm.loongarch.csrxchg.d(i64, i64, i32 immarg);

define dso_local i64 @csrxchg() {
entry:
  %0 = tail call i64 asm sideeffect "", "=r,r,i,{$r4},{$r5},{$r6},{$r7},{$r8},{$r9},{$r10},{$r11},{$r12},{$r13},{$r14},{$r15},{$r16},{$r17},{$r18},{$r19},{$r20},{$r23},{$r24},{$r25},{$r26},{$r27},{$r28},{$r29},{$r30},{$r31},0,~{memory}"(i32 4, i32 0, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i64 0)
  %1 = tail call i64 @llvm.loongarch.csrxchg.d(i64 %0, i64 4, i32 0)
  %2 = tail call i64 asm sideeffect "", "=r,r,i,{$r4},{$r5},{$r6},{$r7},{$r8},{$r9},{$r10},{$r11},{$r12},{$r13},{$r14},{$r15},{$r16},{$r17},{$r18},{$r19},{$r20},{$r23},{$r24},{$r25},{$r26},{$r27},{$r28},{$r29},{$r30},{$r31},0,~{memory}"(i32 4, i32 0, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i64 %1)
  ret i64 %2
}
@llvmbot
Copy link
Member

llvmbot commented May 21, 2025

@llvm/issue-subscribers-backend-loongarch

Author: hev (heiher)

In the LoongArch target, the `{G}CSRXCHG` instruction has a special encoding constraint:

If the rj operand is assigned to register R0 or R1, the instruction encoding will be interpreted as {G}CSRRD or {G}CSRWR respectively, not {G}CSRXCHG.

Currently, LLVM’s register allocator may assign R0 or R1 to the rj operand of a {G}CSRXCHG instruction, which leads to incorrect code generation and unintended semantics.

Reproduce case:

declare i64 @<!-- -->llvm.loongarch.csrxchg.d(i64, i64, i32 immarg);

define dso_local i64 @<!-- -->csrxchg() {
entry:
  %0 = tail call i64 asm sideeffect "", "=r,r,i,{$r4},{$r5},{$r6},{$r7},{$r8},{$r9},{$r10},{$r11},{$r12},{$r13},{$r14},{$r15},{$r16},{$r17},{$r18},{$r19},{$r20},{$r23},{$r24},{$r25},{$r26},{$r27},{$r28},{$r29},{$r30},{$r31},0,~{memory}"(i32 4, i32 0, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i64 0)
  %1 = tail call i64 @<!-- -->llvm.loongarch.csrxchg.d(i64 %0, i64 4, i32 0)
  %2 = tail call i64 asm sideeffect "", "=r,r,i,{$r4},{$r5},{$r6},{$r7},{$r8},{$r9},{$r10},{$r11},{$r12},{$r13},{$r14},{$r15},{$r16},{$r17},{$r18},{$r19},{$r20},{$r23},{$r24},{$r25},{$r26},{$r27},{$r28},{$r29},{$r30},{$r31},0,~{memory}"(i32 4, i32 0, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i64 %1)
  ret i64 %2
}

@heiher heiher self-assigned this May 21, 2025
heiher added a commit to heiher/llvm-project that referenced this issue May 21, 2025
The {G}CSRXCHG instruction must not use R0 or R1 as the rj operand, as
encoding rj as 0 or 1 will be interpreted as {G}CSRRD OR {G}CSRWR,
respectively, rather than {G}CSRXCHG.

This patch introduces a new register class `GPRNoR0R1` and updates the
{G}CSRXCHG instruction definition to use it for the rj operand, ensuring
the register allocator avoids assigning R0 or R1.

Fixes llvm#140842
@heiher heiher changed the title [LoongArch] Incorrect register allocation for {G}CSRXCHG - rj must not be R0 ro R1 [LoongArch] Incorrect register allocation for [G]CSRXCHG - rj must not be R0 ro R1 May 22, 2025
heiher added a commit that referenced this issue May 22, 2025
…40862)

The `[G]CSRXCHG` instruction must not use R0 or R1 as the `rj` operand,
as encoding `rj` as 0 or 1 will be interpreted as `[G]CSRRD` OR
`[G]CSRWR`, respectively, rather than `[G]CSRXCHG`.

This patch introduces a new register class `GPRNoR0R1` and updates the
`[G]CSRXCHG` instruction definition to use it for the `rj` operand,
ensuring the register allocator avoids assigning R0 or R1.

Fixes #140842
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants