tinycc-devel
[Top][All Lists]
Advanced

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

[Tinycc-devel] [PATCH 1/9] arm-asm: Add lsl, lsr, asr, ror, rrx


From: Danny Milosavljevic
Subject: [Tinycc-devel] [PATCH 1/9] arm-asm: Add lsl, lsr, asr, ror, rrx
Date: Mon, 28 Dec 2020 02:44:05 +0100

---
 arm-asm.c | 162 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 arm-tok.h |  11 ++++
 2 files changed, 173 insertions(+)

diff --git a/arm-asm.c b/arm-asm.c
index ce3ac80..6dc24c0 100644
--- a/arm-asm.c
+++ b/arm-asm.c
@@ -248,6 +248,14 @@ static void asm_binary_opcode(TCCState *s1, int token)
    Note: For single data transfer instructions, "0" means immediate. */
 #define ENCODE_IMMEDIATE_FLAG (1 << 25)
 
+#define ENCODE_BARREL_SHIFTER_SHIFT_BY_REGISTER (1 << 4)
+#define ENCODE_BARREL_SHIFTER_MODE_LSL (0 << 5)
+#define ENCODE_BARREL_SHIFTER_MODE_LSR (1 << 5)
+#define ENCODE_BARREL_SHIFTER_MODE_ASR (2 << 5)
+#define ENCODE_BARREL_SHIFTER_MODE_ROR (3 << 5)
+#define ENCODE_BARREL_SHIFTER_REGISTER(register_index) ((register_index) << 8)
+#define ENCODE_BARREL_SHIFTER_IMMEDIATE(value) ((value) << 7)
+
 static void asm_block_data_transfer_opcode(TCCState *s1, int token)
 {
     uint32_t opcode;
@@ -355,6 +363,52 @@ static void asm_block_data_transfer_opcode(TCCState *s1, 
int token)
     }
 }
 
+static uint32_t asm_encode_rotation(Operand* rotation)
+{
+    uint64_t amount;
+    switch (rotation->type) {
+    case OP_REG32:
+        tcc_error("cannot rotate immediate value by register");
+        return 0;
+    case OP_IM8:
+        amount = rotation->e.v;
+        if (amount >= 0 && amount < 32 && (amount & 1) == 0)
+            return (amount >> 1) << 8;
+        else
+            tcc_error("rotating is only possible by a multiple of 2");
+        break;
+    default:
+        tcc_error("unknown rotation amount");
+        return 0;
+    }
+}
+
+static uint32_t asm_encode_shift(Operand* shift)
+{
+    uint64_t amount;
+    uint32_t operands = 0;
+    switch (shift->type) {
+    case OP_REG32:
+        if (shift->reg == 15)
+            tcc_error("r15 cannot be used as a shift count");
+        else {
+            operands = ENCODE_BARREL_SHIFTER_SHIFT_BY_REGISTER;
+            operands |= ENCODE_BARREL_SHIFTER_REGISTER(shift->reg);
+        }
+        break;
+    case OP_IM8:
+        amount = shift->e.v;
+        if (amount > 0 && amount < 32)
+            operands = ENCODE_BARREL_SHIFTER_IMMEDIATE(amount);
+        else
+            tcc_error("shift count out of range");
+        break;
+    default:
+        tcc_error("unknown shift amount");
+    }
+    return operands;
+}
+
 static void asm_data_processing_opcode(TCCState *s1, int token)
 {
     Operand ops[3];
@@ -486,6 +540,102 @@ static void asm_data_processing_opcode(TCCState *s1, int 
token)
     }
 }
 
+static void asm_shift_opcode(TCCState *s1, int token)
+{
+    Operand ops[3];
+    int nb_ops;
+    uint32_t opcode = 0xd << 21; // MOV
+    uint32_t operands = 0;
+
+    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");
+        return;
+    }
+
+    if (ops[0].type != OP_REG32)
+        expect("(destination operand) register");
+    else
+        operands |= ENCODE_RD(ops[0].reg);
+
+    if (nb_ops == 2) {
+        switch (ARM_INSTRUCTION_GROUP(token)) {
+        case TOK_ASM_rrxseq:
+            opcode |= ENCODE_SET_CONDITION_CODES;
+            /* fallthrough */
+        case TOK_ASM_rrxeq:
+            if (ops[1].type == OP_REG32) {
+                operands |= ops[1].reg;
+                operands |= ENCODE_BARREL_SHIFTER_MODE_ROR;
+                asm_emit_opcode(token, opcode | operands);
+            } else
+                tcc_error("(first source operand) register");
+            return;
+        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;
+        }
+    }
+    if (nb_ops != 3) {
+        expect("two or three operands");
+        return;
+    }
+
+    switch (ops[1].type) {
+    case OP_REG32:
+        operands |= ops[1].reg;
+        break;
+    case OP_IM8:
+        operands |= ENCODE_IMMEDIATE_FLAG;
+        operands |= ops[1].e.v;
+        break;
+    }
+
+    if (operands & ENCODE_IMMEDIATE_FLAG)
+        operands |= asm_encode_rotation(&ops[2]);
+    else
+        operands |= asm_encode_shift(&ops[2]);
+
+    switch (ARM_INSTRUCTION_GROUP(token)) {
+    case TOK_ASM_lslseq:
+        opcode |= ENCODE_SET_CONDITION_CODES;
+        /* fallthrough */
+    case TOK_ASM_lsleq:
+        operands |= ENCODE_BARREL_SHIFTER_MODE_LSL;
+        break;
+    case TOK_ASM_lsrseq:
+        opcode |= ENCODE_SET_CONDITION_CODES;
+        /* fallthrough */
+    case TOK_ASM_lsreq:
+        operands |= ENCODE_BARREL_SHIFTER_MODE_LSR;
+        break;
+    case TOK_ASM_asrseq:
+        opcode |= ENCODE_SET_CONDITION_CODES;
+        /* fallthrough */
+    case TOK_ASM_asreq:
+        operands |= ENCODE_BARREL_SHIFTER_MODE_ASR;
+        break;
+    case TOK_ASM_rorseq:
+        opcode |= ENCODE_SET_CONDITION_CODES;
+        /* fallthrough */
+    case TOK_ASM_roreq:
+        operands |= ENCODE_BARREL_SHIFTER_MODE_ROR;
+        break;
+    default:
+        expect("shift instruction");
+        return;
+    }
+    asm_emit_opcode(token, opcode | operands);
+}
+
 static void asm_multiplication_opcode(TCCState *s1, int token)
 {
     Operand ops[4];
@@ -902,6 +1052,18 @@ ST_FUNC void asm_opcode(TCCState *s1, int token)
     case TOK_ASM_mvnseq:
         return asm_data_processing_opcode(s1, token);
 
+    case TOK_ASM_lsleq:
+    case TOK_ASM_lslseq:
+    case TOK_ASM_lsreq:
+    case TOK_ASM_lsrseq:
+    case TOK_ASM_asreq:
+    case TOK_ASM_asrseq:
+    case TOK_ASM_roreq:
+    case TOK_ASM_rorseq:
+    case TOK_ASM_rrxseq:
+    case TOK_ASM_rrxeq:
+        return asm_shift_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 2f1798b..a1fb158 100644
--- a/arm-tok.h
+++ b/arm-tok.h
@@ -145,3 +145,14 @@
  DEF_ASM_CONDED(bics)
  DEF_ASM_CONDED(mvn)
  DEF_ASM_CONDED(mvns)
+
+ DEF_ASM_CONDED(lsl)
+ DEF_ASM_CONDED(lsls)
+ DEF_ASM_CONDED(lsr)
+ DEF_ASM_CONDED(lsrs)
+ DEF_ASM_CONDED(asr)
+ DEF_ASM_CONDED(asrs)
+ DEF_ASM_CONDED(ror)
+ DEF_ASM_CONDED(rors)
+ DEF_ASM_CONDED(rrx)
+ DEF_ASM_CONDED(rrxs)



reply via email to

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