[llvm] [X86] Fold an LEA into a following memory operand's addressing mode (PR #221863)

Simon Pilgrim via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 9 03:23:38 PDT 2026


================
@@ -0,0 +1,143 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -verify-machineinstrs | FileCheck %s
+
+; An address computed in one block and dereferenced in another is brought
+; adjacent (lea then memory op) only after tail duplication, past the point
+; where SelectionDAG folds an address into a memory operand. These check that
+; the late peephole rejoins the pair: the lea disappears into the load/store's
+; addressing mode.
+
+; base + index*4 load
+define i32 @fold_idx4(ptr %a, ptr %b, i64 %i, i1 %c) {
+; CHECK-LABEL: fold_idx4:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    testb $1, %cl
+; CHECK-NEXT:    je .LBB0_2
+; CHECK-NEXT:  # %bb.1: # %la
+; CHECK-NEXT:    movl (%rdi,%rdx,4), %eax
+; CHECK-NEXT:    retq
+; CHECK-NEXT:  .LBB0_2: # %lb
+; CHECK-NEXT:    movl (%rsi,%rdx,4), %eax
+; CHECK-NEXT:    retq
+  br i1 %c, label %la, label %lb
+la:
+  %qa = getelementptr i32, ptr %a, i64 %i
+  br label %join
+lb:
+  %qb = getelementptr i32, ptr %b, i64 %i
+  br label %join
+join:
+  %q = phi ptr [ %qa, %la ], [ %qb, %lb ]
+  %v = load i32, ptr %q
+  ret i32 %v
+}
+
+; base + index*8 load; the load also fully rewrites the base register
+define i64 @fold_idx8(ptr %a, ptr %b, i64 %i, i1 %c) {
+; CHECK-LABEL: fold_idx8:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    testb $1, %cl
+; CHECK-NEXT:    je .LBB1_2
+; CHECK-NEXT:  # %bb.1: # %la
+; CHECK-NEXT:    movq (%rdi,%rdx,8), %rax
+; CHECK-NEXT:    retq
+; CHECK-NEXT:  .LBB1_2: # %lb
+; CHECK-NEXT:    movq (%rsi,%rdx,8), %rax
+; CHECK-NEXT:    retq
+  br i1 %c, label %la, label %lb
+la:
+  %qa = getelementptr i64, ptr %a, i64 %i
+  br label %join
+lb:
+  %qb = getelementptr i64, ptr %b, i64 %i
+  br label %join
+join:
+  %q = phi ptr [ %qa, %la ], [ %qb, %lb ]
+  %v = load i64, ptr %q
+  ret i64 %v
+}
+
+; store consumer
+define void @fold_store_idx4(ptr %a, ptr %b, i64 %i, i32 %x, i1 %c) {
+; CHECK-LABEL: fold_store_idx4:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    testb $1, %r8b
+; CHECK-NEXT:    je .LBB2_2
+; CHECK-NEXT:  # %bb.1: # %la
+; CHECK-NEXT:    movl %ecx, (%rdi,%rdx,4)
+; CHECK-NEXT:    retq
+; CHECK-NEXT:  .LBB2_2: # %lb
+; CHECK-NEXT:    movl %ecx, (%rsi,%rdx,4)
+; CHECK-NEXT:    retq
+  br i1 %c, label %la, label %lb
+la:
+  %qa = getelementptr i32, ptr %a, i64 %i
+  br label %join
+lb:
+  %qb = getelementptr i32, ptr %b, i64 %i
+  br label %join
+join:
+  %q = phi ptr [ %qa, %la ], [ %qb, %lb ]
+  store i32 %x, ptr %q
+  ret void
+}
+
+; load-op consumer (add reg, mem): the folded address feeds the add's memory
+; operand
+define i32 @fold_addrm(ptr %a, ptr %b, i64 %i, i32 %x, i1 %c) {
+; CHECK-LABEL: fold_addrm:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %ecx, %eax
+; CHECK-NEXT:    testb $1, %r8b
+; CHECK-NEXT:    je .LBB3_2
+; CHECK-NEXT:  # %bb.1: # %la
+; CHECK-NEXT:    addl (%rdi,%rdx,4), %eax
+; CHECK-NEXT:    retq
+; CHECK-NEXT:  .LBB3_2: # %lb
+; CHECK-NEXT:    addl (%rsi,%rdx,4), %eax
+; CHECK-NEXT:    retq
+  br i1 %c, label %la, label %lb
+la:
+  %qa = getelementptr i32, ptr %a, i64 %i
+  br label %join
+lb:
+  %qb = getelementptr i32, ptr %b, i64 %i
+  br label %join
+join:
+  %q = phi ptr [ %qa, %la ], [ %qb, %lb ]
+  %v = load i32, ptr %q
+  %s = add i32 %v, %x
+  ret i32 %s
+}
----------------
RKSimon wrote:

RMW test coverage might be interesting - as would a vector load / store case.

https://github.com/llvm/llvm-project/pull/221863


More information about the llvm-commits mailing list