diff mbox series

[RFC,v2,23/24] WIP: Add missing instructions

Message ID 46fe7e6cef5c03c2165feaf400cca797ee1b10f9.1543352682.git.alistair.francis@wdc.com
State New
Headers show
Series Add RISC-V TCG backend support | expand

Commit Message

Alistair Francis Nov. 27, 2018, 9:10 p.m. UTC
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
---
 tcg/riscv/tcg-target.inc.c | 77 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 77 insertions(+)

Comments

Richard Henderson Nov. 28, 2018, 8:30 p.m. UTC | #1
On 11/27/18 1:10 PM, Alistair Francis wrote:
> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
> ---
>  tcg/riscv/tcg-target.inc.c | 77 ++++++++++++++++++++++++++++++++++++++
>  1 file changed, 77 insertions(+)
> 
> diff --git a/tcg/riscv/tcg-target.inc.c b/tcg/riscv/tcg-target.inc.c
> index 13756f6d0d..b8e9c0e126 100644
> --- a/tcg/riscv/tcg-target.inc.c
> +++ b/tcg/riscv/tcg-target.inc.c
> @@ -606,6 +606,57 @@ static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
>      return false;
>  }
>  
> +static void tcg_out_addsub2(TCGContext *s,
> +                            TCGReg rl, TCGReg rh,
> +                            TCGReg al, TCGReg ah,
> +                            TCGReg bl, TCGReg bh,
> +                            bool cbl, bool cbh, bool is_sub)
> +{
> +    /* FIXME: This is just copied from MIPS */
> +    TCGReg th = TCG_REG_TMP1;
> +
> +    /* If we have a negative constant such that negating it would
> +       make the high part zero, we can (usually) eliminate one insn.  */
> +    if (cbl && cbh && bh == -1 && bl != 0) {
> +        bl = -bl;
> +        bh = 0;
> +        is_sub = !is_sub;
> +    }
> +
> +    /* By operating on the high part first, we get to use the final
> +       carry operation to move back from the temporary.  */
> +    if (!cbh) {
> +        tcg_out_opc_reg(s, (is_sub ? OPC_SUB : OPC_ADDI), th, ah, bh);
> +    } else if (bh != 0 || ah == rl) {
> +        tcg_out_opc_imm(s, OPC_ADDI, th, ah, (is_sub ? -bh : bh));
> +    } else {
> +        th = ah;
> +    }
> +
> +    if (is_sub) {
> +        if (cbl) {
> +            tcg_out_opc_imm(s, OPC_SLLI, TCG_REG_TMP0, al, bl);

s/SLLI/SLTIU/

> +            tcg_out_opc_imm(s, OPC_ADDI, rl, al, -bl);
> +        } else {
> +            tcg_out_opc_reg(s, OPC_SLLI, TCG_REG_TMP0, al, bl);

s/SLLI/SLTU/

> +            tcg_out_opc_reg(s, OPC_SUB, rl, al, bl);
> +        }
> +        tcg_out_opc_reg(s, OPC_SUB, rh, th, TCG_REG_TMP0);
> +    } else {
> +        if (cbl) {
> +            tcg_out_opc_imm(s, OPC_ADDI, rl, al, bl);
> +            tcg_out_opc_imm(s, OPC_SLLI, TCG_REG_TMP0, rl, bl);

SLTIU

> +        } else if (rl == al && rl == bl) {
> +            tcg_out_opc_imm(s, OPC_SRLI, TCG_REG_TMP0, al, 31);

s/31/TCG_TARGET_REG_BITS - 1/
or somesuch.  I think that's an existing mips bug too...

> +            tcg_out_opc_reg(s, OPC_ADDI, rl, al, bl);

ADD, not ADDI.

> +        } else {
> +            tcg_out_opc_reg(s, OPC_ADDI, rl, al, bl);
> +            tcg_out_opc_reg(s, OPC_SLLI, TCG_REG_TMP0, rl, (rl == bl ? al : bl));

Similarly.

> +        }
> +        tcg_out_opc_reg(s, OPC_ADDI, rh, th, TCG_REG_TMP0);

ADD.

> @@ -1537,6 +1604,8 @@ static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op)
>      case INDEX_op_ext16s_i32:
>      case INDEX_op_ext16s_i64:
>      case INDEX_op_ext32s_i64:
> +    case INDEX_op_extrl_i64_i32:
> +    case INDEX_op_extrh_i64_i32:

This belongs in a previous patch.


> +    case INDEX_op_add2_i32:
> +    case INDEX_op_add2_i64:
> +        return &rZ_rZ_rZ_rZ_rZ_rZ;
> +
> +    case INDEX_op_sub2_i32:
> +    case INDEX_op_sub2_i64:
> +        return &rZ_rZ_rZ_rZ_rZ_rZ;

Adding 0 with TCG_REG_ZERO is sorta pointless.  You want the I and N
constraints.  Note that MIPS uses a modified symmetric N that can always be
negated [-32767, 32767] instead of [-32767, 32768].  Otherwise that first if
statement doesn't work.


r~
diff mbox series

Patch

diff --git a/tcg/riscv/tcg-target.inc.c b/tcg/riscv/tcg-target.inc.c
index 13756f6d0d..b8e9c0e126 100644
--- a/tcg/riscv/tcg-target.inc.c
+++ b/tcg/riscv/tcg-target.inc.c
@@ -606,6 +606,57 @@  static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
     return false;
 }
 
+static void tcg_out_addsub2(TCGContext *s,
+                            TCGReg rl, TCGReg rh,
+                            TCGReg al, TCGReg ah,
+                            TCGReg bl, TCGReg bh,
+                            bool cbl, bool cbh, bool is_sub)
+{
+    /* FIXME: This is just copied from MIPS */
+    TCGReg th = TCG_REG_TMP1;
+
+    /* If we have a negative constant such that negating it would
+       make the high part zero, we can (usually) eliminate one insn.  */
+    if (cbl && cbh && bh == -1 && bl != 0) {
+        bl = -bl;
+        bh = 0;
+        is_sub = !is_sub;
+    }
+
+    /* By operating on the high part first, we get to use the final
+       carry operation to move back from the temporary.  */
+    if (!cbh) {
+        tcg_out_opc_reg(s, (is_sub ? OPC_SUB : OPC_ADDI), th, ah, bh);
+    } else if (bh != 0 || ah == rl) {
+        tcg_out_opc_imm(s, OPC_ADDI, th, ah, (is_sub ? -bh : bh));
+    } else {
+        th = ah;
+    }
+
+    if (is_sub) {
+        if (cbl) {
+            tcg_out_opc_imm(s, OPC_SLLI, TCG_REG_TMP0, al, bl);
+            tcg_out_opc_imm(s, OPC_ADDI, rl, al, -bl);
+        } else {
+            tcg_out_opc_reg(s, OPC_SLLI, TCG_REG_TMP0, al, bl);
+            tcg_out_opc_reg(s, OPC_SUB, rl, al, bl);
+        }
+        tcg_out_opc_reg(s, OPC_SUB, rh, th, TCG_REG_TMP0);
+    } else {
+        if (cbl) {
+            tcg_out_opc_imm(s, OPC_ADDI, rl, al, bl);
+            tcg_out_opc_imm(s, OPC_SLLI, TCG_REG_TMP0, rl, bl);
+        } else if (rl == al && rl == bl) {
+            tcg_out_opc_imm(s, OPC_SRLI, TCG_REG_TMP0, al, 31);
+            tcg_out_opc_reg(s, OPC_ADDI, rl, al, bl);
+        } else {
+            tcg_out_opc_reg(s, OPC_ADDI, rl, al, bl);
+            tcg_out_opc_reg(s, OPC_SLLI, TCG_REG_TMP0, rl, (rl == bl ? al : bl));
+        }
+        tcg_out_opc_reg(s, OPC_ADDI, rh, th, TCG_REG_TMP0);
+    }
+}
+
 static const struct {
     RISCVInsn op;
     bool swap;
@@ -1384,6 +1435,18 @@  static void tcg_out_op(TCGContext *s, TCGOpcode opc,
         }
         break;
 
+    case INDEX_op_add2_i32:
+    case INDEX_op_add2_i64:
+        tcg_out_addsub2(s, a0, a1, a2, args[3], args[4], args[5],
+                        const_args[4], const_args[5], false);
+        break;
+
+    case INDEX_op_sub2_i32:
+    case INDEX_op_sub2_i64:
+        tcg_out_addsub2(s, a0, a1, a2, args[3], args[4], args[5],
+                        const_args[4], const_args[5], true);
+        break;
+
     case INDEX_op_brcond_i32:
     case INDEX_op_brcond_i64:
         tcg_out_brcond(s, a2, a0, a1, arg_label(args[3]));
@@ -1439,6 +1502,8 @@  static void tcg_out_op(TCGContext *s, TCGOpcode opc,
         break;
 
     case INDEX_op_ext32s_i64:
+    case INDEX_op_extrl_i64_i32:
+    case INDEX_op_extrh_i64_i32:
     case INDEX_op_ext_i32_i64:
         tcg_out_ext32s(s, a0, a1);
         break;
@@ -1505,6 +1570,8 @@  static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op)
         = { .args_ct_str = { "LZ", "LZ", "L" } };
     static const TCGTargetOpDef LZ_LZ_L_L
         = { .args_ct_str = { "LZ", "LZ", "L", "L" } };
+    static const TCGTargetOpDef rZ_rZ_rZ_rZ_rZ_rZ
+        = { .args_ct_str = { "rZ", "rZ", "rZ", "rZ", "rZ", "rZ" } };
 
     switch (op) {
     case INDEX_op_goto_ptr:
@@ -1537,6 +1604,8 @@  static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op)
     case INDEX_op_ext16s_i32:
     case INDEX_op_ext16s_i64:
     case INDEX_op_ext32s_i64:
+    case INDEX_op_extrl_i64_i32:
+    case INDEX_op_extrh_i64_i32:
     case INDEX_op_ext_i32_i64:
         return &r_r;
 
@@ -1593,6 +1662,14 @@  static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op)
     case INDEX_op_brcond_i64:
         return &rZ_rZ;
 
+    case INDEX_op_add2_i32:
+    case INDEX_op_add2_i64:
+        return &rZ_rZ_rZ_rZ_rZ_rZ;
+
+    case INDEX_op_sub2_i32:
+    case INDEX_op_sub2_i64:
+        return &rZ_rZ_rZ_rZ_rZ_rZ;
+
     case INDEX_op_brcond2_i32:
         return &rZ_rZ_rZ_rZ;