[llvm] [AArch64][GlobalISel] Fix invalid subregister copies for truncating stores (PR #213935)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Aug 4 07:20:39 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-aarch64
Author: Cullen Rhodes (c-rhodes)
<details>
<summary>Changes</summary>
The custom truncating store selector always created a subregister copy matching the memory type. When storing an i16 value to i8 both types used GPR32, producing an invalid copy:
```
*** Bad machine code: Invalid subregister index for virtual register ***
- function: truncstores
- basic block: %bb.0 (0xb1a58e8738c0)
- instruction: %2:gpr32 = COPY %val16.sub_32:gpr32
- operand 1: %val16.sub_32:gpr32
Register class GPR32 does not support subreg index sub_32
LLVM ERROR: Found 1 machine code errors.
```
Only create the subregister copy when the value and memory types use different register classes. When the classes match, the store can consume the original register directly.
The existing RegBankSelect avoids this by inserting a G_ANYEXT from i16 to i32, allowing the imported pattern to match. It was exposed by the type-based RegBankSelect prototype in #<!-- -->199040.
Assisted-by: codex
---
Full diff: https://github.com/llvm/llvm-project/pull/213935.diff
2 Files Affected:
- (modified) llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp (+19-8)
- (modified) llvm/test/CodeGen/AArch64/GlobalISel/select-store.mir (+6)
``````````diff
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
index 7e9135b15144a..b854c64d2a984 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
@@ -3035,18 +3035,29 @@ bool AArch64InstructionSelector::select(MachineInstr &I) {
// The code below doesn't support truncating stores, so we need to split it
// again.
if (isa<GStore>(LdSt) && ValTy.getSizeInBits() > MemSizeInBits) {
- unsigned SubReg;
LLT MemTy = LdSt.getMMO().getMemoryType();
auto *RC = getRegClassForTypeOnBank(MemTy, RB);
- if (!getSubRegForClass(RC, TRI, SubReg))
+ if (!RC)
return false;
+ auto *ValRC = getRegClassForTypeOnBank(ValTy, RB);
+ if (!ValRC)
+ return false;
+
+ // Only insert a subregister copy when truncating changes register class.
+ // If both types use the same class, the store can consume ValReg
+ // directly.
+ if (ValRC != RC) {
+ unsigned SubReg;
+ if (!getSubRegForClass(RC, TRI, SubReg))
+ return false;
- // Generate a subreg copy.
- auto Copy = MIB.buildInstr(TargetOpcode::COPY, {MemTy}, {})
- .addReg(ValReg, {}, SubReg)
- .getReg(0);
- RBI.constrainGenericRegister(Copy, *RC, MRI);
- LdSt.getOperand(0).setReg(Copy);
+ // Generate a subreg copy.
+ auto Copy = MIB.buildInstr(TargetOpcode::COPY, {MemTy}, {})
+ .addReg(ValReg, {}, SubReg)
+ .getReg(0);
+ RBI.constrainGenericRegister(Copy, *RC, MRI);
+ LdSt.getOperand(0).setReg(Copy);
+ }
} else if (isa<GLoad>(LdSt) && ValTy.getSizeInBits() > MemSizeInBits) {
// If this is an any-extending load from the FPR bank, split it into a regular
// load + extend.
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/select-store.mir b/llvm/test/CodeGen/AArch64/GlobalISel/select-store.mir
index 3cc6ef4d4cb0b..0d6dfd5da82c1 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/select-store.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/select-store.mir
@@ -728,6 +728,8 @@ body: |
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr64sp = COPY $x0
; CHECK-NEXT: %val32:gpr32 = COPY $w1
; CHECK-NEXT: %val64:gpr64 = COPY $x2
+ ; CHECK-NEXT: %val16:gpr32 = IMPLICIT_DEF
+ ; CHECK-NEXT: STRBBui %val16, [[COPY]], 0 :: (store (i8))
; CHECK-NEXT: STRBBui %val32, [[COPY]], 0 :: (store (i8))
; CHECK-NEXT: STRBBui %val32, [[COPY]], 43 :: (store (i8))
; CHECK-NEXT: STRHHui %val32, [[COPY]], 0 :: (store (i16))
@@ -743,6 +745,10 @@ body: |
%0:gpr(p0) = COPY $x0
%val32:gpr(i32) = COPY $w1
%val64:gpr(i64) = COPY $x2
+ %val16:gpr(i16) = G_IMPLICIT_DEF
+
+ G_STORE %val16, %0 :: (store (i8))
+
G_STORE %val32, %0 :: (store (i8))
; unscaled offset:
%cst:gpr(i64) = G_CONSTANT i64 43
``````````
</details>
https://github.com/llvm/llvm-project/pull/213935
More information about the llvm-commits
mailing list