Commit a075f67f45 for qemu.org
commit a075f67f458734820e4681a803e90ac1157d350c
Author: Richard Henderson <richard.henderson@linaro.org>
Date: Thu Aug 27 20:08:38 2026 -0700
tcg: Add INDEX_op_lea
Add an opcode for compound address formation.
Reviewed-by: Matt Turner <mattst88@gmail.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst
index 88d48a1f99..51fa183e91 100644
--- a/docs/devel/tcg-ops.rst
+++ b/docs/devel/tcg-ops.rst
@@ -524,6 +524,10 @@ Misc
- | Reverse the 64 bits of input *t1* with output in *dest*.
+ * - lea *dest*, *t1*, *t2*, *sh*, *imm*
+
+ - | *dest* = *t1* + (*t2* << *sh*) + *imm*.
+
Conditional moves
-----------------
diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h
index f3a81d5d7f..884345afe5 100644
--- a/include/tcg/tcg-opc.h
+++ b/include/tcg/tcg-opc.h
@@ -64,6 +64,7 @@ DEF(ld16s, 1, 1, 1, TCG_OPF_INT)
DEF(ld32u, 1, 1, 1, TCG_OPF_INT)
DEF(ld32s, 1, 1, 1, TCG_OPF_INT)
DEF(ld, 1, 1, 1, TCG_OPF_INT)
+DEF(lea, 1, 2, 2, TCG_OPF_INT)
DEF(movcond, 1, 4, 1, TCG_OPF_INT)
DEF(mul, 1, 2, 0, TCG_OPF_INT)
DEF(muls2, 2, 2, 0, TCG_OPF_INT)
diff --git a/tcg/aarch64/tcg-target-has.h b/tcg/aarch64/tcg-target-has.h
index 69e83efb69..86672b2eab 100644
--- a/tcg/aarch64/tcg-target-has.h
+++ b/tcg/aarch64/tcg-target-has.h
@@ -57,4 +57,7 @@
#define TCG_TARGET_sextract_valid(type, ofs, len) 1
#define TCG_TARGET_deposit_valid(type, ofs, len) 1
+#define TCG_TARGET_lea_sh_valid(type, sh) 0
+#define TCG_TARGET_lea_imm_valid(type, imm) 0
+
#endif
diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc
index 273462ca61..b601b19c7f 100644
--- a/tcg/aarch64/tcg-target.c.inc
+++ b/tcg/aarch64/tcg-target.c.inc
@@ -3081,6 +3081,10 @@ static const TCGOutOpStore outop_st = {
.out_r = tcg_out_st,
};
+static const TCGOutOpLea outop_lea = {
+ .base.static_constraint = C_NotImplemented,
+};
+
static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
unsigned vecl, unsigned vece,
const TCGArg args[TCG_MAX_OP_ARGS],
diff --git a/tcg/loongarch64/tcg-target-has.h b/tcg/loongarch64/tcg-target-has.h
index 32abc6f457..31e6ea9632 100644
--- a/tcg/loongarch64/tcg-target-has.h
+++ b/tcg/loongarch64/tcg-target-has.h
@@ -54,4 +54,7 @@ tcg_target_sextract_valid(TCGType type, unsigned ofs, unsigned len)
}
#define TCG_TARGET_sextract_valid tcg_target_sextract_valid
+#define TCG_TARGET_lea_sh_valid(type, sh) 0
+#define TCG_TARGET_lea_imm_valid(type, imm) 0
+
#endif
diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc
index 69e76807d6..17784d8bbe 100644
--- a/tcg/loongarch64/tcg-target.c.inc
+++ b/tcg/loongarch64/tcg-target.c.inc
@@ -2098,6 +2098,10 @@ static const TCGOutOpStore outop_st = {
.out_r = tcg_out_st,
};
+static const TCGOutOpLea outop_lea = {
+ .base.static_constraint = C_NotImplemented,
+};
+
static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
TCGReg rd, TCGReg rs)
{
diff --git a/tcg/ppc64/tcg-target-has.h b/tcg/ppc64/tcg-target-has.h
index a3711feeae..d11d82f184 100644
--- a/tcg/ppc64/tcg-target-has.h
+++ b/tcg/ppc64/tcg-target-has.h
@@ -66,4 +66,7 @@ tcg_target_sextract_valid(TCGType type, unsigned ofs, unsigned len)
}
#define TCG_TARGET_sextract_valid tcg_target_sextract_valid
+#define TCG_TARGET_lea_sh_valid(type, sh) 0
+#define TCG_TARGET_lea_imm_valid(type, imm) 0
+
#endif
diff --git a/tcg/ppc64/tcg-target.c.inc b/tcg/ppc64/tcg-target.c.inc
index cd1c234367..99f4469f4b 100644
--- a/tcg/ppc64/tcg-target.c.inc
+++ b/tcg/ppc64/tcg-target.c.inc
@@ -3633,6 +3633,9 @@ static const TCGOutOpStore outop_st = {
.out_r = tcg_out_st,
};
+static const TCGOutOpLea outop_lea = {
+ .base.static_constraint = C_NotImplemented,
+};
int tcg_can_emit_vec_op(TCGOpcode opc, TCGType type, unsigned vece)
{
diff --git a/tcg/riscv64/tcg-target-has.h b/tcg/riscv64/tcg-target-has.h
index aef10c2d9d..93f8baad09 100644
--- a/tcg/riscv64/tcg-target-has.h
+++ b/tcg/riscv64/tcg-target-has.h
@@ -69,4 +69,7 @@ tcg_target_sextract_valid(TCGType type, unsigned ofs, unsigned len)
#define TCG_TARGET_deposit_valid(type, ofs, len) 0
+#define TCG_TARGET_lea_sh_valid(type, sh) 0
+#define TCG_TARGET_lea_imm_valid(type, imm) 0
+
#endif
diff --git a/tcg/riscv64/tcg-target.c.inc b/tcg/riscv64/tcg-target.c.inc
index 03f32c5819..ec0c8e1af0 100644
--- a/tcg/riscv64/tcg-target.c.inc
+++ b/tcg/riscv64/tcg-target.c.inc
@@ -2740,6 +2740,9 @@ static const TCGOutOpStore outop_st = {
.out_r = tcg_out_st,
};
+static const TCGOutOpLea outop_lea = {
+ .base.static_constraint = C_NotImplemented,
+};
static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
unsigned vecl, unsigned vece,
diff --git a/tcg/s390x/tcg-target-has.h b/tcg/s390x/tcg-target-has.h
index 0aeb5ba01a..58e3afe526 100644
--- a/tcg/s390x/tcg-target-has.h
+++ b/tcg/s390x/tcg-target-has.h
@@ -77,4 +77,7 @@ tcg_target_sextract_valid(TCGType type, unsigned ofs, unsigned len)
}
#define TCG_TARGET_sextract_valid tcg_target_sextract_valid
+#define TCG_TARGET_lea_sh_valid(type, sh) 0
+#define TCG_TARGET_lea_imm_valid(type, imm) 0
+
#endif
diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc
index 4d1a779c47..2fd7012d04 100644
--- a/tcg/s390x/tcg-target.c.inc
+++ b/tcg/s390x/tcg-target.c.inc
@@ -3187,6 +3187,9 @@ static const TCGOutOpStore outop_st = {
.out_r = tcg_out_st,
};
+static const TCGOutOpLea outop_lea = {
+ .base.static_constraint = C_NotImplemented,
+};
static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
TCGReg dst, TCGReg src)
diff --git a/tcg/sparc64/tcg-target-has.h b/tcg/sparc64/tcg-target-has.h
index b29fd177f6..4182a7c1aa 100644
--- a/tcg/sparc64/tcg-target-has.h
+++ b/tcg/sparc64/tcg-target-has.h
@@ -19,4 +19,7 @@
#define TCG_TARGET_deposit_valid(type, ofs, len) 0
+#define TCG_TARGET_lea_sh_valid(type, sh) 0
+#define TCG_TARGET_lea_imm_valid(type, imm) 0
+
#endif
diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc
index 35cd14a5b6..cb457453ff 100644
--- a/tcg/sparc64/tcg-target.c.inc
+++ b/tcg/sparc64/tcg-target.c.inc
@@ -2120,6 +2120,9 @@ static const TCGOutOpStore outop_st = {
.out_r = tcg_out_st,
};
+static const TCGOutOpLea outop_lea = {
+ .base.static_constraint = C_NotImplemented,
+};
static TCGConstraintSetIndex
tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags)
diff --git a/tcg/tcg.c b/tcg/tcg.c
index 1cd6d41d31..d19c3fb857 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -1095,6 +1095,12 @@ typedef struct TCGOutOpSubtract {
TCGReg a0, tcg_target_long a1, TCGReg a2);
} TCGOutOpSubtract;
+typedef struct TCGOutOpLea {
+ TCGOutOp base;
+ void (*out)(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1,
+ TCGReg a2, unsigned sh, tcg_target_long imm);
+} TCGOutOpLea;
+
#include "tcg-target.c.inc"
#ifndef CONFIG_TCG_INTERPRETER
@@ -1191,6 +1197,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = {
OUTOP(INDEX_op_ld16u, TCGOutOpLoad, outop_ld16u),
OUTOP(INDEX_op_ld32s, TCGOutOpLoad, outop_ld32s),
OUTOP(INDEX_op_ld32u, TCGOutOpLoad, outop_ld32u),
+ OUTOP(INDEX_op_lea, TCGOutOpLea, outop_lea),
OUTOP(INDEX_op_movcond, TCGOutOpMovcond, outop_movcond),
OUTOP(INDEX_op_mul, TCGOutOpBinary, outop_mul),
OUTOP(INDEX_op_muls2, TCGOutOpMul2, outop_muls2),
@@ -5796,6 +5803,21 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op)
}
break;
+ case INDEX_op_lea:
+ {
+ const TCGOutOpLea *out = &outop_lea;
+ int sh = new_args[3];
+ tcg_target_long imm = new_args[4];
+
+ tcg_debug_assert(!const_args[1]);
+ tcg_debug_assert(!const_args[2]);
+ tcg_debug_assert(TCG_TARGET_lea_sh_valid(type, sh));
+ tcg_debug_assert(TCG_TARGET_lea_imm_valid(type, imm));
+
+ out->out(s, type, new_args[0], new_args[1], new_args[2], sh, imm);
+ }
+ break;
+
case INDEX_op_goto_ptr:
tcg_debug_assert(!const_args[0]);
tcg_out_goto_ptr(s, new_args[0]);
diff --git a/tcg/tci/tcg-target-has.h b/tcg/tci/tcg-target-has.h
index 64742cf0b7..f4f9ddf595 100644
--- a/tcg/tci/tcg-target-has.h
+++ b/tcg/tci/tcg-target-has.h
@@ -17,4 +17,7 @@
#define TCG_TARGET_sextract_valid(type, ofs, len) 1
#define TCG_TARGET_deposit_valid(type, ofs, len) 1
+#define TCG_TARGET_lea_sh_valid(type, sh) 0
+#define TCG_TARGET_lea_imm_valid(type, imm) 0
+
#endif
diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc
index 4cd1c1431c..6942fdbb4e 100644
--- a/tcg/tci/tcg-target.c.inc
+++ b/tcg/tci/tcg-target.c.inc
@@ -1220,6 +1220,10 @@ static inline bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
return false;
}
+static const TCGOutOpLea outop_lea = {
+ .base.static_constraint = C_NotImplemented,
+};
+
/* Test if a constant matches the constraint. */
static bool tcg_target_const_match(int64_t val, int ct,
TCGType type, TCGCond cond, int vece)
diff --git a/tcg/x86_64/tcg-target-has.h b/tcg/x86_64/tcg-target-has.h
index d249c1b3e7..6ffae51f92 100644
--- a/tcg/x86_64/tcg-target-has.h
+++ b/tcg/x86_64/tcg-target-has.h
@@ -105,4 +105,7 @@ tcg_target_extract_valid(TCGType type, unsigned ofs, unsigned len)
}
#define TCG_TARGET_extract_valid tcg_target_extract_valid
+#define TCG_TARGET_lea_sh_valid(type, sh) 0
+#define TCG_TARGET_lea_imm_valid(type, imm) 0
+
#endif
diff --git a/tcg/x86_64/tcg-target.c.inc b/tcg/x86_64/tcg-target.c.inc
index 590c9c2402..46efee87e6 100644
--- a/tcg/x86_64/tcg-target.c.inc
+++ b/tcg/x86_64/tcg-target.c.inc
@@ -3357,6 +3357,10 @@ static const TCGOutOpStore outop_st = {
.out_i = tgen_st_i,
};
+static const TCGOutOpLea outop_lea = {
+ .base.static_constraint = C_NotImplemented,
+};
+
static int const umin_insn[4] = {
OPC_PMINUB, OPC_PMINUW, OPC_PMINUD, OPC_VPMINUQ
};