tinycc-devel
[Top][All Lists]
Advanced

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

[Tinycc-devel] [PATCH 14/16] arm-asm: Add and, eor, sub, rsb, add, adc,


From: Danny Milosavljevic
Subject: [Tinycc-devel] [PATCH 14/16] arm-asm: Add and, eor, sub, rsb, add, adc, sbc, rsc, tst, teq, cmp, cmn, orr, mov, bic, mvn
Date: Sat, 26 Dec 2020 22:58:15 +0100

---
 arm-asm.c | 165 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 arm-tok.h |  35 ++++++++++++
 2 files changed, 200 insertions(+)

diff --git a/arm-asm.c b/arm-asm.c
index 9e9fb93..58853f6 100644
--- a/arm-asm.c
+++ b/arm-asm.c
@@ -347,6 +347,137 @@ static void asm_block_data_transfer_opcode(TCCState *s1, 
int token)
     }
 }
 
+static void asm_data_processing_opcode(TCCState *s1, int token)
+{
+    Operand ops[3];
+    int nb_ops;
+
+    /* 16 entries per instruction for the different condition codes */
+    uint32_t opcode_idx = (ARM_INSTRUCTION_GROUP(token) - TOK_ASM_andeq) >> 4;
+
+    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) {
+        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;
+    }
+    if (nb_ops != 3) {
+        expect("two or three operands");
+        return;
+    } else {
+        uint32_t opcode = 0;
+        uint32_t operands = 0;
+
+        // data processing (general case):
+        // operands:
+        //   Rn: bits 19...16 (first operand)
+        //   Rd: bits 15...12 (destination)
+        //   Operand2: bits 11...0 (second operand);  depending on I that's 
either a register or an immediate
+        // operator:
+        //   bits 24...21: "OpCode"--see below
+
+        /* operations in the token list are ordered by opcode */
+        opcode = (opcode_idx >> 1) << 21; // drop "s"
+        if (ops[0].type != OP_REG32)
+            expect("(destination operand) register");
+        else if (opcode == 0xa << 21 || opcode == 0xb << 21 || opcode == 0x8 
<< 21 || opcode == 0x9 << 21 ) // cmp, cmn, tst, teq
+            operands |= ENCODE_SET_CONDITION_CODES; // force S set, otherwise 
it's a completely different instruction.
+        else
+            operands |= ENCODE_RD(ops[0].reg);
+        if (ops[1].type != OP_REG32)
+            expect("(first source operand) register");
+        else if (!(opcode == 0xd << 21 || opcode == 0xf << 21)) // not: mov, 
mvn (those have only one source operand)
+            operands |= ENCODE_RN(ops[1].reg);
+        switch (ops[2].type) {
+        case OP_REG32:
+            // TODO: Parse and encode shift.
+            operands |= ops[2].reg;
+            break;
+        case OP_IM8:
+            // TODO: Parse and encode rotation.
+            operands |= ENCODE_IMMEDIATE_FLAG;
+            operands |= ops[2].e.v;
+            break;
+        case OP_IM8N: // immediate negative value
+            // TODO: Parse and encode rotation.
+            operands |= ENCODE_IMMEDIATE_FLAG;
+            /* Instruction swapping:
+               0001 = EOR - Rd:= Op1 EOR Op2     -> difficult
+               0011 = RSB - Rd:= Op2 - Op1       -> difficult
+               0111 = RSC - Rd:= Op2 - Op1 + C   -> difficult
+               1000 = TST - CC on: Op1 AND Op2   -> difficult
+               1001 = TEQ - CC on: Op1 EOR Op2   -> difficult
+               1100 = ORR - Rd:= Op1 OR Op2      -> difficult
+            */
+            switch (opcode_idx >> 1) { // "OpCode" in ARM docs
+#if 1
+            case 0x0: // AND - Rd:= Op1 AND Op2
+                opcode = 0xe << 21; // BIC
+                operands |= (ops[2].e.v ^ 0xFF) & 0xFF;
+                break;
+            case 0x2: // SUB - Rd:= Op1 - Op2
+                opcode = 0x4 << 21; // ADD
+                operands |= (-ops[2].e.v) & 0xFF;
+                break;
+            case 0x4: // ADD - Rd:= Op1 + Op2
+                opcode = 0x2 << 21; // SUB
+                operands |= (-ops[2].e.v) & 0xFF;
+                break;
+            case 0x5: // ADC - Rd:= Op1 + Op2 + C
+                opcode = 0x6 << 21; // SBC
+                operands |= (ops[2].e.v ^ 0xFF) & 0xFF;
+                break;
+            case 0x6: // SBC - Rd:= Op1 - Op2 + C
+                opcode = 0x5 << 21; // ADC
+                operands |= (ops[2].e.v ^ 0xFF) & 0xFF;
+                break;
+#endif
+            case 0xa: // CMP - CC on: Op1 - Op2
+                opcode = 0xb << 21; // CMN
+                operands |= (-ops[2].e.v) & 0xFF;
+                break;
+            case 0xb: // CMN - CC on: Op1 + Op2
+                opcode = 0xa << 21; // CMP
+                operands |= (-ops[2].e.v) & 0xFF;
+                break;
+            // moveq r1, r3: 0x01a01003; mov Rd, Op2
+            case 0xd: // MOV - Rd:= Op2
+                opcode = 0xf << 21; // MVN
+                operands |= (ops[2].e.v ^ 0xFF) & 0xFF;
+                break;
+#if 1
+            case 0xe: // BIC - Rd:= Op1 AND NOT Op2
+                opcode = 0x0 << 21; // AND
+                operands |= (ops[2].e.v ^ 0xFF) & 0xFF;
+                break;
+#endif
+            case 0xf: // MVN - Rd:= NOT Op2
+                opcode = 0xd << 21; // MOV
+                operands |= (ops[2].e.v ^ 0xFF) & 0xFF;
+                break;
+            default:
+                tcc_error("cannot use '%s' with a negative immediate value", 
get_tok_str(token, NULL));
+            }
+            break;
+        default:
+            expect("(second source operand) register or immediate value");
+        }
+
+        /* S=0 and S=1 entries alternate one after another, in that order */
+        opcode |= (opcode_idx & 1) ? ENCODE_SET_CONDITION_CODES : 0;
+        asm_emit_opcode(token, opcode | operands);
+    }
+}
+
 static void asm_multiplication_opcode(TCCState *s1, int token)
 {
     Operand ops[4];
@@ -669,6 +800,40 @@ ST_FUNC void asm_opcode(TCCState *s1, int token)
     case TOK_ASM_strbeq:
         return asm_single_data_transfer_opcode(s1, token);
 
+    case TOK_ASM_andeq:
+    case TOK_ASM_eoreq:
+    case TOK_ASM_subeq:
+    case TOK_ASM_rsbeq:
+    case TOK_ASM_addeq:
+    case TOK_ASM_adceq:
+    case TOK_ASM_sbceq:
+    case TOK_ASM_rsceq:
+    case TOK_ASM_tsteq:
+    case TOK_ASM_teqeq:
+    case TOK_ASM_cmpeq:
+    case TOK_ASM_cmneq:
+    case TOK_ASM_orreq:
+    case TOK_ASM_moveq:
+    case TOK_ASM_biceq:
+    case TOK_ASM_mvneq:
+    case TOK_ASM_andseq:
+    case TOK_ASM_eorseq:
+    case TOK_ASM_subseq:
+    case TOK_ASM_rsbseq:
+    case TOK_ASM_addseq:
+    case TOK_ASM_adcseq:
+    case TOK_ASM_sbcseq:
+    case TOK_ASM_rscseq:
+//  case TOK_ASM_tstseq:
+//  case TOK_ASM_teqseq:
+//  case TOK_ASM_cmpseq:
+//  case TOK_ASM_cmnseq:
+    case TOK_ASM_orrseq:
+    case TOK_ASM_movseq:
+    case TOK_ASM_bicseq:
+    case TOK_ASM_mvnseq:
+        return asm_data_processing_opcode(s1, token);
+
     case TOK_ASM_muleq:
     case TOK_ASM_mulseq:
     case TOK_ASM_mlaeq:
diff --git a/arm-tok.h b/arm-tok.h
index a2a2f70..023b01a 100644
--- a/arm-tok.h
+++ b/arm-tok.h
@@ -103,3 +103,38 @@
 
  DEF_ASM_CONDED(push)
  DEF_ASM_CONDED(pop)
+
+ /* data processing instructions; order is important */
+
+ DEF_ASM_CONDED(and)
+ DEF_ASM_CONDED(ands)
+ DEF_ASM_CONDED(eor)
+ DEF_ASM_CONDED(eors)
+ DEF_ASM_CONDED(sub)
+ DEF_ASM_CONDED(subs)
+ DEF_ASM_CONDED(rsb)
+ DEF_ASM_CONDED(rsbs)
+ DEF_ASM_CONDED(add)
+ DEF_ASM_CONDED(adds)
+ DEF_ASM_CONDED(adc)
+ DEF_ASM_CONDED(adcs)
+ DEF_ASM_CONDED(sbc)
+ DEF_ASM_CONDED(sbcs)
+ DEF_ASM_CONDED(rsc)
+ DEF_ASM_CONDED(rscs)
+ DEF_ASM_CONDED(tst)
+ DEF_ASM_CONDED(tsts) // necessary here--but not useful to the user
+ DEF_ASM_CONDED(teq)
+ DEF_ASM_CONDED(teqs) // necessary here--but not useful to the user
+ DEF_ASM_CONDED(cmp)
+ DEF_ASM_CONDED(cmps) // necessary here--but not useful to the user
+ DEF_ASM_CONDED(cmn)
+ DEF_ASM_CONDED(cmns) // necessary here--but not useful to the user
+ DEF_ASM_CONDED(orr)
+ DEF_ASM_CONDED(orrs)
+ DEF_ASM_CONDED(mov)
+ DEF_ASM_CONDED(movs)
+ DEF_ASM_CONDED(bic)
+ DEF_ASM_CONDED(bics)
+ DEF_ASM_CONDED(mvn)
+ DEF_ASM_CONDED(mvns)



reply via email to

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