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


Reply via email to