Skip to content

Use utxb rN, rM, ror #8 to zext from shifts on armv6#197352

Open
mike-goutokuji wants to merge 2 commits into
llvm:mainfrom
mike-goutokuji:thumb-
Open

Use utxb rN, rM, ror #8 to zext from shifts on armv6#197352
mike-goutokuji wants to merge 2 commits into
llvm:mainfrom
mike-goutokuji:thumb-

Conversation

@mike-goutokuji
Copy link
Copy Markdown
Contributor

No description provided.

@llvmorg-github-actions
Copy link
Copy Markdown

llvmorg-github-actions Bot commented May 13, 2026

@llvm/pr-subscribers-backend-amdgpu
@llvm/pr-subscribers-backend-risc-v
@llvm/pr-subscribers-backend-aarch64
@llvm/pr-subscribers-backend-arm

@llvm/pr-subscribers-llvm-selectiondag

Author: LumioseSil (LumioseSil)

Changes

Full diff: https://github.com/llvm/llvm-project/pull/197352.diff

3 Files Affected:

  • (modified) llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp (+12)
  • (modified) llvm/lib/Target/ARM/ARMInstrInfo.td (+13)
  • (added) llvm/test/CodeGen/ARM/extract-ext-armv6.ll (+62)
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 14bf2b704c4da..1a8d0067916c0 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -11349,6 +11349,18 @@ SDValue DAGCombiner::visitSRA(SDNode *N) {
                                     Shift);
         return DAG.getNode(ISD::SIGN_EXTEND, DL,
                            N->getValueType(0), Trunc);
+      } else if ((ShiftAmt > 0) &&
+                 (!LegalOperations ||
+                  TLI.isOperationLegal(ISD::SIGN_EXTEND_INREG, TruncVT))) {
+        // Only if the truncate+sext path above does not apply: same
+        // sign-extract value as sign_extend(truncate(srl ...)), but represented
+        // as sign_extend_inreg(srl ...) when truncate is not free. Guard
+        // matches visitSIGN_EXTEND's (sext(trunc)) -> sign_extend_inreg fold.
+        SDValue Amt = DAG.getShiftAmountConstant(ShiftAmt, VT, DL);
+        SDValue Shift = DAG.getNode(ISD::SRL, DL, VT,
+                                    N0.getOperand(0), Amt);
+        return DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, N->getValueType(0),
+                           Shift, DAG.getValueType(TruncVT));
       }
     }
   }
diff --git a/llvm/lib/Target/ARM/ARMInstrInfo.td b/llvm/lib/Target/ARM/ARMInstrInfo.td
index c74c84a2602b1..8145f2e19fc60 100644
--- a/llvm/lib/Target/ARM/ARMInstrInfo.td
+++ b/llvm/lib/Target/ARM/ARMInstrInfo.td
@@ -3941,6 +3941,15 @@ def : ARMV6Pat<(add rGPR:$Rn, (and (srl rGPR:$Rm, rot_imm:$rot), 0xFF)),
                (UXTAB rGPR:$Rn, rGPR:$Rm, rot_imm:$rot)>;
 def : ARMV6Pat<(add rGPR:$Rn, (and (srl rGPR:$Rm, imm8_or_16:$rot), 0xFFFF)),
                (UXTAH rGPR:$Rn, rGPR:$Rm, rot_imm:$rot)>;
+
+// Standalone (srl; and #0xff) is equivalent to uxtb with ROR — avoids a
+// separate logical shift when extracting bytes from a word (e.g. popcount
+// LUT indexing).
+def : ARMV6Pat<(and (srl GPRnopc:$Rm, rot_imm:$rot), 0xFF),
+               (UXTB GPRnopc:$Rm, rot_imm:$rot)>;
+// Same for 16-bit zero-extract: (srl; and #0xffff) -> uxth with ROR.
+def : ARMV6Pat<(and (srl GPRnopc:$Rm, rot_imm:$rot), 0xFFFF),
+               (UXTH GPRnopc:$Rm, rot_imm:$rot)>;
 }
 
 // This isn't safe in general, the add is two 16-bit units, not a 32-bit add.
@@ -6319,6 +6328,10 @@ def : ARMV6Pat<(add GPR:$Rn, (and GPR:$Rm, 0xFFFF)),
 
 def : ARMV6Pat<(sext_inreg GPR:$Src, i8),  (SXTB GPR:$Src, 0)>;
 def : ARMV6Pat<(sext_inreg GPR:$Src, i16), (SXTH GPR:$Src, 0)>;
+def : ARMV6Pat<(sext_inreg (srl GPRnopc:$Rm, rot_imm:$rot), i8),
+               (SXTB GPRnopc:$Rm, rot_imm:$rot)>;
+def : ARMV6Pat<(sext_inreg (srl GPRnopc:$Rm, rot_imm:$rot), i16),
+               (SXTH GPRnopc:$Rm, rot_imm:$rot)>;
 
 def : ARMV6Pat<(add GPR:$Rn, (sext_inreg GPRnopc:$Rm, i8)),
                (SXTAB GPR:$Rn, GPRnopc:$Rm, 0)>;
diff --git a/llvm/test/CodeGen/ARM/extract-ext-armv6.ll b/llvm/test/CodeGen/ARM/extract-ext-armv6.ll
new file mode 100644
index 0000000000000..d6ae1759ebe3a
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/extract-ext-armv6.ll
@@ -0,0 +1,62 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=armv6-none-eabi -O3 %s -o - | FileCheck %s
+
+define i32 @zext_u8_from_shift8(i32 %0) {
+; CHECK-LABEL: zext_u8_from_shift8:
+; CHECK:       @ %bb.0:
+; CHECK-NEXT:    uxtb r0, r0, ror #8
+; CHECK-NEXT:    bx lr
+  %2 = lshr i32 %0, 8
+  %3 = and i32 %2, 255
+  ret i32 %3
+}
+
+define i32 @zext_u8_from_shift16(i32 %0) {
+; CHECK-LABEL: zext_u8_from_shift16:
+; CHECK:       @ %bb.0:
+; CHECK-NEXT:    uxtb r0, r0, ror #16
+; CHECK-NEXT:    bx lr
+  %2 = lshr i32 %0, 16
+  %3 = and i32 %2, 255
+  ret i32 %3
+}
+
+define i32 @sext_i8_from_bits8(i32 %0) {
+; CHECK-LABEL: sext_i8_from_bits8:
+; CHECK:       @ %bb.0:
+; CHECK-NEXT:    sxtb r0, r0, ror #8
+; CHECK-NEXT:    bx lr
+  %2 = shl i32 %0, 16
+  %3 = ashr i32 %2, 24
+  ret i32 %3
+}
+
+define i32 @sext_i8_from_bits16(i32 %0) {
+; CHECK-LABEL: sext_i8_from_bits16:
+; CHECK:       @ %bb.0:
+; CHECK-NEXT:    sxtb r0, r0, ror #16
+; CHECK-NEXT:    bx lr
+  %2 = shl i32 %0, 8
+  %3 = ashr i32 %2, 24
+  ret i32 %3
+}
+
+define i32 @zext_u16_from_shift8(i32 %0) {
+; CHECK-LABEL: zext_u16_from_shift8:
+; CHECK:       @ %bb.0:
+; CHECK-NEXT:    uxth r0, r0, ror #8
+; CHECK-NEXT:    bx lr
+  %2 = lshr i32 %0, 8
+  %3 = and i32 %2, 65535
+  ret i32 %3
+}
+
+define i32 @sext_i16_from_shift8(i32 %0) {
+; CHECK-LABEL: sext_i16_from_shift8:
+; CHECK:       @ %bb.0:
+; CHECK-NEXT:    sxth r0, r0, ror #8
+; CHECK-NEXT:    bx lr
+  %2 = shl i32 %0, 8
+  %3 = ashr i32 %2, 16
+  ret i32 %3
+}

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 13, 2026

✅ With the latest revision this PR passed the C/C++ code formatter.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 13, 2026

🐧 Linux x64 Test Results

  • 174396 tests passed
  • 3347 tests skipped
  • 1 test failed

Failed Tests

(click on a test name to see its output)

LLVM

LLVM.CodeGen/RISCV/short-forward-branch-opt.ll
Exit Code: 1

Command Output (stdout):
--
# RUN: at line 2
/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/llc -mtriple=riscv64 -mattr=+c,+zbb -verify-machineinstrs < /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/test/CodeGen/RISCV/short-forward-branch-opt.ll    | /home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/FileCheck -check-prefix=NOSFB /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/test/CodeGen/RISCV/short-forward-branch-opt.ll
# executed command: /home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/llc -mtriple=riscv64 -mattr=+c,+zbb -verify-machineinstrs
# note: command had no output on stdout or stderr
# executed command: /home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/FileCheck -check-prefix=NOSFB /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/test/CodeGen/RISCV/short-forward-branch-opt.ll
# note: command had no output on stdout or stderr
# RUN: at line 4
/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/llc -mtriple=riscv64 -mcpu=sifive-u74 -mattr=+zbb -verify-machineinstrs < /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/test/CodeGen/RISCV/short-forward-branch-opt.ll    | /home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/FileCheck -check-prefixes=RV64SFB,RV64SFBSIFIVEU74 /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/test/CodeGen/RISCV/short-forward-branch-opt.ll
# executed command: /home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/llc -mtriple=riscv64 -mcpu=sifive-u74 -mattr=+zbb -verify-machineinstrs
# note: command had no output on stdout or stderr
# executed command: /home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/FileCheck -check-prefixes=RV64SFB,RV64SFBSIFIVEU74 /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/test/CodeGen/RISCV/short-forward-branch-opt.ll
# note: command had no output on stdout or stderr
# RUN: at line 6
/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/llc -mtriple=riscv64 -mcpu=andes-ax45 -mattr=+zbb -verify-machineinstrs < /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/test/CodeGen/RISCV/short-forward-branch-opt.ll    | /home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/FileCheck -check-prefixes=RV64SFB,RV64SFBANDESAX45 /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/test/CodeGen/RISCV/short-forward-branch-opt.ll
# executed command: /home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/llc -mtriple=riscv64 -mcpu=andes-ax45 -mattr=+zbb -verify-machineinstrs
# note: command had no output on stdout or stderr
# executed command: /home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/FileCheck -check-prefixes=RV64SFB,RV64SFBANDESAX45 /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/test/CodeGen/RISCV/short-forward-branch-opt.ll
# .---command stderr------------
# | /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/test/CodeGen/RISCV/short-forward-branch-opt.ll:1989:26: error: RV64SFBANDESAX45-NEXT: expected string not found in input
# | ; RV64SFBANDESAX45-NEXT: sraiw a1, a0, 31
# |                          ^
# | <stdin>:559:18: note: scanning from here
# | # %bb.1: # %entry
# |                  ^
# | <stdin>:560:5: note: possible intended match here
# |  nds.bfos a1, a0, 31, 31
# |     ^
# | 
# | Input file: <stdin>
# | Check file: /home/gha/actions-runner/_work/llvm-project/llvm-project/llvm/test/CodeGen/RISCV/short-forward-branch-opt.ll
# | 
# | -dump-input=help explains the following input dump.
# | 
# | Input was:
# | <<<<<<
# |              .
# |              .
# |              .
# |            554:  .type select_sraiw,@function 
# |            555: select_sraiw: # @select_sraiw 
# |            556:  .cfi_startproc 
# |            557: # %bb.0: # %entry 
# |            558:  nds.bnec a2, 0, .LBB33_2 
# |            559: # %bb.1: # %entry 
# | next:1989'0                      X error: no match found
# |            560:  nds.bfos a1, a0, 31, 31 
# | next:1989'0     ~~~~~~~~~~~~~~~~~~~~~~~~~
# | next:1989'1         ?                     possible intended match
# |            561: .LBB33_2: # %entry 
# | next:1989'0     ~~~~~~~~~~~~~~~~~~~
# |            562:  mv a0, a1 
# | next:1989'0     ~~~~~~~~~~~
# |            563:  ret 
# | next:1989'0     ~~~~~
# |            564: .Lfunc_end33: 
# | next:1989'0     ~~~~~~~~~~~~~~
# |            565:  .size select_sraiw, .Lfunc_end33-select_sraiw 
# | next:1989'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# |              .
# |              .
# |              .
# | >>>>>>
# `-----------------------------
# error: command failed with exit status: 1

--

If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the infrastructure label.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 13, 2026

🪟 Windows x64 Test Results

  • 134822 tests passed
  • 3285 tests skipped
  • 1 test failed

Failed Tests

(click on a test name to see its output)

LLVM

LLVM.CodeGen/RISCV/short-forward-branch-opt.ll
Exit Code: 1

Command Output (stdout):
--
# RUN: at line 2
c:\_work\llvm-project\llvm-project\build\bin\llc.exe -mtriple=riscv64 -mattr=+c,+zbb -verify-machineinstrs < C:\_work\llvm-project\llvm-project\llvm\test\CodeGen\RISCV\short-forward-branch-opt.ll    | c:\_work\llvm-project\llvm-project\build\bin\filecheck.exe -check-prefix=NOSFB C:\_work\llvm-project\llvm-project\llvm\test\CodeGen\RISCV\short-forward-branch-opt.ll
# executed command: 'c:\_work\llvm-project\llvm-project\build\bin\llc.exe' -mtriple=riscv64 -mattr=+c,+zbb -verify-machineinstrs
# note: command had no output on stdout or stderr
# executed command: 'c:\_work\llvm-project\llvm-project\build\bin\filecheck.exe' -check-prefix=NOSFB 'C:\_work\llvm-project\llvm-project\llvm\test\CodeGen\RISCV\short-forward-branch-opt.ll'
# note: command had no output on stdout or stderr
# RUN: at line 4
c:\_work\llvm-project\llvm-project\build\bin\llc.exe -mtriple=riscv64 -mcpu=sifive-u74 -mattr=+zbb -verify-machineinstrs < C:\_work\llvm-project\llvm-project\llvm\test\CodeGen\RISCV\short-forward-branch-opt.ll    | c:\_work\llvm-project\llvm-project\build\bin\filecheck.exe -check-prefixes=RV64SFB,RV64SFBSIFIVEU74 C:\_work\llvm-project\llvm-project\llvm\test\CodeGen\RISCV\short-forward-branch-opt.ll
# executed command: 'c:\_work\llvm-project\llvm-project\build\bin\llc.exe' -mtriple=riscv64 -mcpu=sifive-u74 -mattr=+zbb -verify-machineinstrs
# note: command had no output on stdout or stderr
# executed command: 'c:\_work\llvm-project\llvm-project\build\bin\filecheck.exe' -check-prefixes=RV64SFB,RV64SFBSIFIVEU74 'C:\_work\llvm-project\llvm-project\llvm\test\CodeGen\RISCV\short-forward-branch-opt.ll'
# note: command had no output on stdout or stderr
# RUN: at line 6
c:\_work\llvm-project\llvm-project\build\bin\llc.exe -mtriple=riscv64 -mcpu=andes-ax45 -mattr=+zbb -verify-machineinstrs < C:\_work\llvm-project\llvm-project\llvm\test\CodeGen\RISCV\short-forward-branch-opt.ll    | c:\_work\llvm-project\llvm-project\build\bin\filecheck.exe -check-prefixes=RV64SFB,RV64SFBANDESAX45 C:\_work\llvm-project\llvm-project\llvm\test\CodeGen\RISCV\short-forward-branch-opt.ll
# executed command: 'c:\_work\llvm-project\llvm-project\build\bin\llc.exe' -mtriple=riscv64 -mcpu=andes-ax45 -mattr=+zbb -verify-machineinstrs
# note: command had no output on stdout or stderr
# executed command: 'c:\_work\llvm-project\llvm-project\build\bin\filecheck.exe' -check-prefixes=RV64SFB,RV64SFBANDESAX45 'C:\_work\llvm-project\llvm-project\llvm\test\CodeGen\RISCV\short-forward-branch-opt.ll'
# .---command stderr------------
# | C:\_work\llvm-project\llvm-project\llvm\test\CodeGen\RISCV\short-forward-branch-opt.ll:1989:26: error: RV64SFBANDESAX45-NEXT: expected string not found in input
# | ; RV64SFBANDESAX45-NEXT: sraiw a1, a0, 31
# |                          ^
# | <stdin>:559:18: note: scanning from here
# | # %bb.1: # %entry
# |                  ^
# | <stdin>:560:5: note: possible intended match here
# |  nds.bfos a1, a0, 31, 31
# |     ^
# | 
# | Input file: <stdin>
# | Check file: C:\_work\llvm-project\llvm-project\llvm\test\CodeGen\RISCV\short-forward-branch-opt.ll
# | 
# | -dump-input=help explains the following input dump.
# | 
# | Input was:
# | <<<<<<
# |              .
# |              .
# |              .
# |            554:  .type select_sraiw,@function 
# |            555: select_sraiw: # @select_sraiw 
# |            556:  .cfi_startproc 
# |            557: # %bb.0: # %entry 
# |            558:  nds.bnec a2, 0, .LBB33_2 
# |            559: # %bb.1: # %entry 
# | next:1989'0                      X error: no match found
# |            560:  nds.bfos a1, a0, 31, 31 
# | next:1989'0     ~~~~~~~~~~~~~~~~~~~~~~~~~
# | next:1989'1         ?                     possible intended match
# |            561: .LBB33_2: # %entry 
# | next:1989'0     ~~~~~~~~~~~~~~~~~~~
# |            562:  mv a0, a1 
# | next:1989'0     ~~~~~~~~~~~
# |            563:  ret 
# | next:1989'0     ~~~~~
# |            564: .Lfunc_end33: 
# | next:1989'0     ~~~~~~~~~~~~~~
# |            565:  .size select_sraiw, .Lfunc_end33-select_sraiw 
# | next:1989'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# |              .
# |              .
# |              .
# | >>>>>>
# `-----------------------------
# error: command failed with exit status: 1

--

If these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the infrastructure label.

@@ -0,0 +1,62 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
; RUN: llc -mtriple=armv6-none-eabi -O3 %s -o - | FileCheck %s
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
; RUN: llc -mtriple=armv6-none-eabi -O3 %s -o - | FileCheck %s
; RUN: llc -mtriple=armv6-none-eabi < %s | FileCheck %s

; CHECK: @ %bb.0:
; CHECK-NEXT: sxtb r0, r0, ror #16
; CHECK-NEXT: bx lr
%2 = shl i32 %0, 8
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use named values in tests

Comment on lines +11354 to +11356
if ((ShiftAmt > 0) &&
TLI.getOperationAction(ISD::SIGN_EXTEND_INREG, TruncVT) ==
TargetLowering::Legal) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if ((ShiftAmt > 0) &&
TLI.getOperationAction(ISD::SIGN_EXTEND_INREG, TruncVT) ==
TargetLowering::Legal) {
if (ShiftAmt > 0 &&
TLI.isOperationLegal(ISD::SIGN_EXTEND_INREG, TruncVT)) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does not do the same thing. Checks if type is legal, not just operation.

@mike-goutokuji mike-goutokuji force-pushed the thumb- branch 5 times, most recently from a5c5246 to 5c7cb38 Compare May 16, 2026 13:48
@mike-goutokuji mike-goutokuji requested a review from arsenm May 16, 2026 13:49
@mike-goutokuji mike-goutokuji force-pushed the thumb- branch 3 times, most recently from 6ab3f67 to cd2ab13 Compare May 16, 2026 14:02
@mike-goutokuji mike-goutokuji force-pushed the thumb- branch 2 times, most recently from c251778 to 15110be Compare May 16, 2026 15:05
@mike-goutokuji
Copy link
Copy Markdown
Contributor Author

I know this in theory can be in seldag but because it's only having a benefit in ARM and causing issues elsewhere, I'm probably going to have to move this to arm backend for now...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants