tinycc-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Tinycc-devel] [PATCH 7/8] arm-asm: Add vmla, vmls, vnmls, vnmla, vmul,


From: Danny Milosavljevic
Subject: [Tinycc-devel] [PATCH 7/8] arm-asm: Add vmla, vmls, vnmls, vnmla, vmul, vnmul, vadd, vsub, vdiv
Date: Thu, 14 Jan 2021 23:22:26 +0100

---
 arm-asm.c                  | 170 ++++++++++++++++++++++++++++++++++++-
 arm-tok.h                  |  10 +++
 tests/arm-asm-testsuite.sh |   6 +-
 3 files changed, 184 insertions(+), 2 deletions(-)

diff --git a/arm-asm.c b/arm-asm.c
index 7e59ad7..c12e3a5 100644
--- a/arm-asm.c
+++ b/arm-asm.c
@@ -1462,7 +1462,6 @@ static int asm_parse_vfp_regvar(int t, int 
double_precision)
     return -1;
 }
 
-
 static void asm_floating_point_single_data_transfer_opcode(TCCState *s1, int 
token)
 {
     Operand ops[3];
@@ -1532,6 +1531,164 @@ static void 
asm_floating_point_single_data_transfer_opcode(TCCState *s1, int tok
         expect("floating point data transfer instruction");
     }
 }
+
+static void asm_floating_point_data_processing_opcode(TCCState *s1, int token) 
{
+    uint8_t coprocessor = 0;
+    uint8_t opcode1 = 0;
+    uint8_t opcode2 = 0; // (0 || 2) | register selection
+    uint8_t registers[3];
+    uint8_t nb_registers = 0;
+    int has_register_1 = 1;
+    int reg;
+
+/* TODO:
+   Instruction    opcode opcode2  Reason
+   =============================================================
+   -              1?00   ?1?      Undefined
+   VFNMS          1?01   ?0?      Must be unconditional
+   VFNMA          1?01   ?1?      Must be unconditional
+   VFMA           1?10   ?0?      Must be unconditional
+   VFMS           1?10   ?1?      Must be unconditional
+   VMOV Fd, const 1?11   ?0?      Needs fixed-point arithmetic
+
+   VABS           Nope            Completely different encoding
+   VSQRT          Nope            Completely different encoding
+
+   VCMP{E}
+   >VCMP with 0
+
+   VCVT*
+
+   VMOV Fd, Fm
+   VMOV Sn, Rd
+   VMOV Rd, Sn
+   VMOV Sn, Sm, Rd, Rn
+   VMOV Rd, Rn, Sn, Sm
+   VMOV Dm, Rd, Rn
+   VMOV Rd, Rn, Dm
+   VMOV Dn[0], Rd
+   VMOV Rd, Dn[0]
+   VMOV Dn[1], Rd
+   VMOV Rd, Dn[1]
+
+   VMSR <sysreg>, Rd
+   VMRS Rd, <sysreg>
+   VMRS APSR_nzcv, FPSCR
+
+   VLDR Fd, <label>
+   VSTR Fd, <label>
+
+   VPUSH <regs>
+   VLDM Rn{!}, <regs>
+   VLDMDB Rn!, <regs>
+   VSTM Rn{!}, <regs>
+   VSTMDB Rn!, <regs>
+   VPOP <regs>
+*/
+
+    for (nb_registers = 0; nb_registers < 3; ) {
+        if (coprocessor == CP_SINGLE_PRECISION_FLOAT) {
+            if ((reg = asm_parse_vfp_regvar(tok, 0)) != -1) {
+                registers[nb_registers] = reg;
+                next();
+            } else {
+                expect("'s<number>'");
+                return;
+            }
+        } else if (coprocessor == CP_DOUBLE_PRECISION_FLOAT) {
+            if ((reg = asm_parse_vfp_regvar(tok, 1)) != -1) {
+                registers[nb_registers] = reg;
+                next();
+            } else {
+                expect("'d<number>'");
+                return;
+            }
+        } else if ((reg = asm_parse_vfp_regvar(tok, 0)) != -1) {
+            coprocessor = CP_SINGLE_PRECISION_FLOAT;
+            registers[nb_registers] = reg;
+            next();
+        } else if ((reg = asm_parse_vfp_regvar(tok, 1)) != -1) {
+            coprocessor = CP_DOUBLE_PRECISION_FLOAT;
+            registers[nb_registers] = reg;
+            next();
+        } else
+            tcc_internal_error("unknown coprocessor");
+       ++nb_registers;
+        if (tok == ',')
+            next();
+        else
+            break;
+    }
+    if (nb_registers == 2) { // implicit
+        registers[2] = registers[1];
+        registers[1] = registers[0];
+        nb_registers = 3;
+    }
+    if (nb_registers < 3) {
+        tcc_error("Not enough operands for '%s' (%u)", get_tok_str(token, 
NULL), nb_registers);
+        return;
+    }
+
+    switch (ARM_INSTRUCTION_GROUP(token)) {
+    case TOK_ASM_vmlaeq:
+        opcode1 = 0;
+        opcode2 = 0;
+        break;
+    case TOK_ASM_vmlseq:
+        opcode1 = 0;
+        opcode2 = 2;
+        break;
+    case TOK_ASM_vnmlseq:
+        opcode1 = 1;
+        opcode2 = 0;
+        break;
+    case TOK_ASM_vnmlaeq:
+        opcode1 = 1;
+        opcode2 = 2;
+        break;
+    case TOK_ASM_vmuleq:
+        opcode1 = 2;
+        opcode2 = 0;
+        break;
+    case TOK_ASM_vnmuleq:
+        opcode1 = 2;
+        opcode2 = 2;
+        break;
+    case TOK_ASM_vaddeq:
+        opcode1 = 3;
+        opcode2 = 0;
+        break;
+    case TOK_ASM_vsubeq:
+        opcode1 = 3;
+        opcode2 = 2;
+        break;
+    case TOK_ASM_vdiveq:
+        opcode1 = 8;
+        opcode2 = 0;
+        break;
+    default:
+        expect("known floating point instruction");
+        return;
+    }
+
+    if (coprocessor == CP_SINGLE_PRECISION_FLOAT) {
+        if (registers[2] & 1)
+            opcode2 |= 1;
+        registers[2] >>= 1;
+
+        if (has_register_1) {
+            if (registers[1] & 1)
+                opcode2 |= 4;
+            registers[1] >>= 1;
+        }
+
+        if (registers[0] & 1)
+            opcode1 |= 4;
+        registers[0] >>= 1;
+    }
+
+    asm_emit_coprocessor_opcode(condition_code_of_token(token), coprocessor, 
opcode1, registers[0], registers[1], registers[2], opcode2, 0);
+}
 #endif
 
 static void asm_misc_single_data_transfer_opcode(TCCState *s1, int token)
@@ -1879,6 +2036,17 @@ ST_FUNC void asm_opcode(TCCState *s1, int token)
     case TOK_ASM_vldreq:
     case TOK_ASM_vstreq:
         return asm_floating_point_single_data_transfer_opcode(s1, token);
+
+    case TOK_ASM_vmlaeq:
+    case TOK_ASM_vmlseq:
+    case TOK_ASM_vnmlseq:
+    case TOK_ASM_vnmlaeq:
+    case TOK_ASM_vmuleq:
+    case TOK_ASM_vnmuleq:
+    case TOK_ASM_vaddeq:
+    case TOK_ASM_vsubeq:
+    case TOK_ASM_vdiveq:
+        return asm_floating_point_data_processing_opcode(s1, token);
 #endif
 
     default:
diff --git a/arm-tok.h b/arm-tok.h
index 3dc3ea0..6adbc68 100644
--- a/arm-tok.h
+++ b/arm-tok.h
@@ -284,3 +284,13 @@
 
  DEF_ASM_CONDED(vldr)
  DEF_ASM_CONDED(vstr)
+
+ DEF_ASM_CONDED(vmla)
+ DEF_ASM_CONDED(vmls)
+ DEF_ASM_CONDED(vnmls)
+ DEF_ASM_CONDED(vnmla)
+ DEF_ASM_CONDED(vmul)
+ DEF_ASM_CONDED(vnmul)
+ DEF_ASM_CONDED(vadd)
+ DEF_ASM_CONDED(vsub)
+ DEF_ASM_CONDED(vdiv)
diff --git a/tests/arm-asm-testsuite.sh b/tests/arm-asm-testsuite.sh
index 1a76a2d..b19c80b 100755
--- a/tests/arm-asm-testsuite.sh
+++ b/tests/arm-asm-testsuite.sh
@@ -103,6 +103,10 @@ do
                     "s2, [r3, #-4]" \
                     "s2, [r3, #0x45]" \
                     "s2, [r3, #-0x45]" \
+                    "s2, s3, s4" \
+                    "s2, s3" \
+                    "d2, d3, d4" \
+                    "d2, d3" \
                    ""
        do
                #echo ".syntax unified" > a.s
@@ -111,7 +115,7 @@ do
                tcc_object="${state}/tcc-$s $args.o"
                expected="${state}/expected-$s $args"
                got="${state}/got-$s $args"
-               if echo "$s $args" | "${CROSS_COMPILE}as" -mlittle-endian -o 
"${as_object}" - 2>"${err}"
+               if echo "$s $args" | "${CROSS_COMPILE}as" -mlittle-endian 
-mfpu=vfp -o "${as_object}" - 2>"${err}" || echo "$s.f32 $args" | 
"${CROSS_COMPILE}as" -mlittle-endian -mfpu=vfp -o "${as_object}" - 2>"${err}" 
|| echo "$s.f64 $args" | "${CROSS_COMPILE}as" -mlittle-endian -mfpu=vfp -o 
"${as_object}" - 2>"${err}"
                then
                        cat "${err}"
                        rm -f "${err}"



reply via email to

[Prev in Thread] Current Thread [Next in Thread]