Reviewed-by: Matt Turner <[email protected]>
Signed-off-by: Richard Henderson <[email protected]>
---
include/tcg/tcg-op.h | 2 ++
include/tcg/tcg-op-def.h.inc | 1 +
tcg/tcg-op.c | 43 ++++++++++++++++++++++++++++++++++++
3 files changed, 46 insertions(+)
diff --git a/include/tcg/tcg-op.h b/include/tcg/tcg-op.h
index 37211642365..a7d001c959c 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/include/tcg/tcg-op-def.h.inc b/include/tcg/tcg-op-def.h.inc
index 4d121470bec..b60edca6e42 100644
--- a/include/tcg/tcg-op-def.h.inc
+++ b/include/tcg/tcg-op-def.h.inc
@@ -36,6 +36,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/tcg/tcg-op.c b/tcg/tcg-op.c
index 855a81c886f..d271d83a7d2 100644
--- a/tcg/tcg-op.c
+++ b/tcg/tcg-op.c
@@ -930,6 +930,49 @@ static void gen_ld16u(TCGType type, TCGTemp *dst,
gen_op_tti(INDEX_op_ld16u, type, dst, base, ofs);
}
+static void 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)) {
+ gen_shli(type, t, index, sh);
+ index = t;
+ sh = 0;
+ }
+ 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) {
+ gen_addi(type, t, index, imm >> sh);
+ index = t;
+ imm = 0;
+ }
+ }
+
+ if (sh == 0) {
+ gen_add(type, dst, base, index);
+ } else if (TCG_TARGET_lea_sh_valid(TCG_TYPE_I32, sh)) {
+ gen_op_tttii(INDEX_op_lea, type, dst, base, index, sh, 0);
+ } else {
+ gen_shli(type, t, index, sh);
+ gen_add(type, dst, base, t);
+ }
+ gen_addi(type, dst, dst, imm);
+}
+
static void gen_mov(TCGType type, TCGTemp *dst, TCGTemp *src)
{
if (src != dst) {
--
2.53.0