Commit 82e6d899d9 for qemu.org

commit 82e6d899d9c1d1500b5b6dc0c533c239eccb0e74
Author: Richard Henderson <richard.henderson@linaro.org>
Date:   Fri Aug 28 04:59:37 2026 -0700

    tcg: Add tcg_gen_lea_{i32,i64,tl}

    Reviewed-by: Matt Turner <mattst88@gmail.com>
    Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

diff --git a/include/tcg/tcg-op-def.h.inc b/include/tcg/tcg-op-def.h.inc
index e694f0e38c..c9caab2138 100644
--- a/include/tcg/tcg-op-def.h.inc
+++ b/include/tcg/tcg-op-def.h.inc
@@ -37,6 +37,7 @@ DEF3(ld8s, TCGV, TCGv_ptr, tcg_target_long)
 DEF3(ld8u, TCGV, TCGv_ptr, tcg_target_long)
 DEF3(ld16s, TCGV, TCGv_ptr, tcg_target_long)
 DEF3(ld16u, TCGV, TCGv_ptr, tcg_target_long)
+DEF5(lea, TCGV, TCGV, TCGV, unsigned, TINT)
 DEF2(mov, TCGV, TCGV)
 DEF2(movi, TCGV, TINT)
 DEF6(movcond, TCGCond, TCGV, TCGV, TCGV, TCGV, TCGV)
diff --git a/include/tcg/tcg-op.h b/include/tcg/tcg-op.h
index 3721164236..a7d001c959 100644
--- a/include/tcg/tcg-op.h
+++ b/include/tcg/tcg-op.h
@@ -83,6 +83,7 @@ typedef TCGv_i64 TCGv;
 #define tcg_gen_shri_tl tcg_gen_shri_i64
 #define tcg_gen_sar_tl tcg_gen_sar_i64
 #define tcg_gen_sari_tl tcg_gen_sari_i64
+#define tcg_gen_lea_tl tcg_gen_lea_i64
 #define tcg_gen_brcond_tl tcg_gen_brcond_i64
 #define tcg_gen_brcondi_tl tcg_gen_brcondi_i64
 #define tcg_gen_setcond_tl tcg_gen_setcond_i64
@@ -209,6 +210,7 @@ typedef TCGv_i64 TCGv;
 #define tcg_gen_shri_tl tcg_gen_shri_i32
 #define tcg_gen_sar_tl tcg_gen_sar_i32
 #define tcg_gen_sari_tl tcg_gen_sari_i32
+#define tcg_gen_lea_tl tcg_gen_lea_i32
 #define tcg_gen_brcond_tl tcg_gen_brcond_i32
 #define tcg_gen_brcondi_tl tcg_gen_brcondi_i32
 #define tcg_gen_setcond_tl tcg_gen_setcond_i32
diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c
index 4814a493c0..fced3811c2 100644
--- a/tcg/tcg-op.c
+++ b/tcg/tcg-op.c
@@ -820,6 +820,49 @@ void tcg_gen_ld16u(TCGType type, TCGTemp *dst,
     tcg_gen_op_tti(INDEX_op_ld16u, type, dst, base, ofs);
 }

+void tcg_gen_lea(TCGType type, TCGTemp *dst, TCGTemp *base,
+                 TCGTemp *index, unsigned sh, int64_t imm)
+{
+    g_autoptr(TCGTemp) t = tcg_temp_new_ebb(type);
+
+    if (imm != 0) {
+        if (TCG_TARGET_lea_imm_valid(type, imm)) {
+            /*
+             * The immediate is non-zero and valid.
+             * If the shift is out of range, perform the shift first
+             * so that we can still emit (base + t + imm) as one insn.
+             */
+            if (!TCG_TARGET_lea_sh_valid(type, sh)) {
+                tcg_gen_shli(type, t, index, sh);
+                index = t;
+                sh = 0;
+            }
+            tcg_gen_op_tttii(INDEX_op_lea, type, dst, base, index, sh, imm);
+            return;
+        }
+
+        /*
+         * If we can make the immediate smaller by folding it
+         * into index before the shift, do so.
+         */
+        if (sh != 0 && imm == (imm >> sh) << sh) {
+            tcg_gen_addi(type, t, index, imm >> sh);
+            index = t;
+            imm = 0;
+        }
+    }
+
+    if (sh == 0) {
+        tcg_gen_add(type, dst, base, index);
+    } else if (TCG_TARGET_lea_sh_valid(type, sh)) {
+        tcg_gen_op_tttii(INDEX_op_lea, type, dst, base, index, sh, 0);
+    } else {
+        tcg_gen_shli(type, t, index, sh);
+        tcg_gen_add(type, dst, base, t);
+    }
+    tcg_gen_addi(type, dst, dst, imm);
+}
+
 void tcg_gen_mov(TCGType type, TCGTemp *dst, TCGTemp *src)
 {
     if (src != dst) {