tinycc-devel
[Top][All Lists]
Advanced

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

[Tinycc-devel] [PATCH 11/16] arm-asm: Add mul, mla, smull, umull, smlal,


From: Danny Milosavljevic
Subject: [Tinycc-devel] [PATCH 11/16] arm-asm: Add mul, mla, smull, umull, smlal, umlal
Date: Sat, 26 Dec 2020 22:58:12 +0100

---
 arm-asm.c | 175 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 arm-tok.h |  15 +++++
 2 files changed, 190 insertions(+)

diff --git a/arm-asm.c b/arm-asm.c
index c2598a8..792b914 100644
--- a/arm-asm.c
+++ b/arm-asm.c
@@ -286,6 +286,165 @@ static void asm_block_data_transfer_opcode(TCCState *s1, 
int token)
     }
 }
 
+static void asm_multiplication_opcode(TCCState *s1, int token)
+{
+    Operand ops[4];
+    int nb_ops = 0;
+    uint32_t opcode = 0x90;
+
+    for (nb_ops = 0; nb_ops < sizeof(ops)/sizeof(ops[0]); ++nb_ops) {
+        parse_operand(s1, &ops[nb_ops]);
+        if (tok != ',') {
+            ++nb_ops;
+            break;
+        }
+        next(); // skip ','
+    }
+    if (nb_ops < 2)
+        expect("at least two operands");
+    else if (nb_ops == 2) {
+        switch (ARM_INSTRUCTION_GROUP(token)) {
+        case TOK_ASM_mulseq:
+        case TOK_ASM_muleq:
+            memcpy(&ops[2], &ops[0], sizeof(ops[1])); // ARM is actually like 
this!
+            break;
+        default:
+            memcpy(&ops[2], &ops[1], sizeof(ops[1])); // move ops[2]
+            memcpy(&ops[1], &ops[0], sizeof(ops[0])); // ops[1] was implicit
+        }
+        nb_ops = 3;
+    }
+
+    // multiply (special case):
+    // operands:
+    //   Rd: bits 19...16
+    //   Rm: bits 3...0
+    //   Rs: bits 11...8
+    //   Rn: bits 15...12
+
+    if (ops[0].type == OP_REG32)
+        opcode |= ops[0].reg << 16;
+    else
+        expect("(destination operand) register");
+    if (ops[1].type == OP_REG32)
+        opcode |= ops[1].reg;
+    else
+        expect("(first source operand) register");
+    if (ops[2].type == OP_REG32)
+        opcode |= ops[2].reg << 8;
+    else
+        expect("(second source operand) register");
+    if (nb_ops > 3) {
+        if (ops[3].type == OP_REG32)
+            opcode |= ops[3].reg << 12;
+        else
+            expect("(third source operand) register");
+    }
+
+    switch (ARM_INSTRUCTION_GROUP(token)) {
+    case TOK_ASM_mulseq:
+        opcode |= 1 << 20; // Status
+        /* fallthrough */
+    case TOK_ASM_muleq:
+        if (nb_ops != 3)
+            expect("three operands");
+        else {
+            asm_emit_opcode(token, opcode);
+        }
+        break;
+    case TOK_ASM_mlaseq:
+        opcode |= 1 << 20; // Status
+        /* fallthrough */
+    case TOK_ASM_mlaeq:
+        if (nb_ops != 4)
+            expect("four operands");
+        else {
+            opcode |= 1 << 21; // Accumulate
+            asm_emit_opcode(token, opcode);
+        }
+        break;
+    default:
+        expect("known multiplication instruction");
+    }
+}
+
+static void asm_long_multiplication_opcode(TCCState *s1, int token)
+{
+    Operand ops[4];
+    int nb_ops = 0;
+    uint32_t opcode = 0x90 | (1 << 23);
+
+    for (nb_ops = 0; nb_ops < sizeof(ops)/sizeof(ops[0]); ++nb_ops) {
+        parse_operand(s1, &ops[nb_ops]);
+        if (tok != ',') {
+            ++nb_ops;
+            break;
+        }
+        next(); // skip ','
+    }
+    if (nb_ops != 4) {
+        expect("four operands");
+        return;
+    }
+
+    // long multiply (special case):
+    // operands:
+    //   RdLo: bits 15...12
+    //   RdHi: bits 19...16
+    //   Rs: bits 11...8
+    //   Rm: bits 3...0
+
+    if (ops[0].type == OP_REG32)
+        opcode |= ops[0].reg << 12;
+    else
+        expect("(destination lo accumulator) register");
+    if (ops[1].type == OP_REG32)
+        opcode |= ops[1].reg << 16;
+    else
+        expect("(destination hi accumulator) register");
+    if (ops[2].type == OP_REG32)
+        opcode |= ops[2].reg;
+    else
+        expect("(first source operand) register");
+    if (ops[3].type == OP_REG32)
+        opcode |= ops[3].reg << 8;
+    else
+        expect("(second source operand) register");
+
+    switch (ARM_INSTRUCTION_GROUP(token)) {
+    case TOK_ASM_smullseq:
+        opcode |= 1 << 20; // Status
+        /* fallthrough */
+    case TOK_ASM_smulleq:
+        opcode |= 1 << 22; // signed
+        asm_emit_opcode(token, opcode);
+        break;
+    case TOK_ASM_umullseq:
+        opcode |= 1 << 20; // Status
+        /* fallthrough */
+    case TOK_ASM_umulleq:
+        asm_emit_opcode(token, opcode);
+        break;
+    case TOK_ASM_smlalseq:
+        opcode |= 1 << 20; // Status
+        /* fallthrough */
+    case TOK_ASM_smlaleq:
+        opcode |= 1 << 22; // signed
+        opcode |= 1 << 21; // Accumulate
+        asm_emit_opcode(token, opcode);
+        break;
+    case TOK_ASM_umlalseq:
+        opcode |= 1 << 20; // Status
+        /* fallthrough */
+    case TOK_ASM_umlaleq:
+        opcode |= 1 << 21; // Accumulate
+        asm_emit_opcode(token, opcode);
+        break;
+    default:
+        expect("known long multiplication instruction");
+    }
+}
+
 ST_FUNC void asm_opcode(TCCState *s1, int token)
 {
     while (token == TOK_LINEFEED) {
@@ -315,6 +474,22 @@ ST_FUNC void asm_opcode(TCCState *s1, int token)
     case TOK_ASM_uxtbeq:
     case TOK_ASM_uxtheq:
         return asm_binary_opcode(s1, token);
+
+    case TOK_ASM_muleq:
+    case TOK_ASM_mulseq:
+    case TOK_ASM_mlaeq:
+    case TOK_ASM_mlaseq:
+        return asm_multiplication_opcode(s1, token);
+
+    case TOK_ASM_smulleq:
+    case TOK_ASM_smullseq:
+    case TOK_ASM_umulleq:
+    case TOK_ASM_umullseq:
+    case TOK_ASM_smlaleq:
+    case TOK_ASM_smlalseq:
+    case TOK_ASM_umlaleq:
+    case TOK_ASM_umlalseq:
+        return asm_long_multiplication_opcode(s1, token);
     default:
         expect("known instruction");
     }
diff --git a/arm-tok.h b/arm-tok.h
index 06cee7a..5106250 100644
--- a/arm-tok.h
+++ b/arm-tok.h
@@ -66,6 +66,21 @@
  DEF_ASM_CONDED(uxtb)
  DEF_ASM_CONDED(uxth)
 
+ /* multiplication */
+
+ DEF_ASM_CONDED(mul)
+ DEF_ASM_CONDED(muls)
+ DEF_ASM_CONDED(mla)
+ DEF_ASM_CONDED(mlas)
+ DEF_ASM_CONDED(smull)
+ DEF_ASM_CONDED(smulls)
+ DEF_ASM_CONDED(umull)
+ DEF_ASM_CONDED(umulls)
+ DEF_ASM_CONDED(smlal)
+ DEF_ASM_CONDED(smlals)
+ DEF_ASM_CONDED(umlal)
+ DEF_ASM_CONDED(umlals)
+
  /* instruction macros */
 
  DEF_ASM_CONDED(push)



reply via email to

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