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) {