[PATCH 0/9] Improve ARM inline assembler

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|

[PATCH 0/9] Improve ARM inline assembler

Danny Milosavljevic
This patchset improves the ARM inline assembler I posted earlier.

(Please apply it on top of the patchset I posted earlier--it does
not replace it)

First, I add support for the barrel shifter--supporting specifying both
modifiers for the old ARM instructions and also the new ARM shift
instructions.

I add ROR support for sxtb, sxth, uxtb, uxth.

I add some warnings and errors for some cases that are not supported by
ARM hardware.

Danny Milosavljevic (9):
  arm-asm: Add lsl, lsr, asr, ror, rrx
  arm-asm: For data processing instructions, support shifts and
    rotations.
  arm-asm: Support rotation for sxtb, sxth, uxtb, uxth
  arm-asm: Warn if regset registers are not specified in ascending order
  arm-asm: Add error case in asm_multiplication_opcode
  arm-asm: Raise an error if asm_binary_opcode is used with PC as
    operand
  arm-asm: Print a warning if asm_binary_opcode is used with SP as
    operand
  arm-asm: Raise error if more than two operands are specified on mov,
    mvn, cmp, cmn, tst, teq
  arm-asm: Raise error if asm_data_processing_opcode and
    asm_shift_opcode try to use PC for register-controlled shifts

 arm-asm.c | 322 +++++++++++++++++++++++++++++++++++++++++++++++++-----
 arm-tok.h |  15 +++
 2 files changed, 312 insertions(+), 25 deletions(-)


_______________________________________________
Tinycc-devel mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/tinycc-devel
Reply | Threaded
Open this post in threaded view
|

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

Danny Milosavljevic
---
 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)

_______________________________________________
Tinycc-devel mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/tinycc-devel
Reply | Threaded
Open this post in threaded view
|

[PATCH 2/9] arm-asm: For data processing instructions, support shifts and rotations.

Danny Milosavljevic
In reply to this post by Danny Milosavljevic
---
 arm-asm.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++--------
 arm-tok.h |  4 ++++
 2 files changed, 52 insertions(+), 8 deletions(-)

diff --git a/arm-asm.c b/arm-asm.c
index 6dc24c0..ef75091 100644
--- a/arm-asm.c
+++ b/arm-asm.c
@@ -413,18 +413,55 @@ static void asm_data_processing_opcode(TCCState *s1, int token)
 {
     Operand ops[3];
     int nb_ops;
+    Operand shift = {};
+    int nb_shift = 0;
+    uint32_t operands = 0;
 
     /* 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) {
+    for (nb_ops = 0; nb_ops < sizeof(ops)/sizeof(ops[0]); ) {
+        if (tok == TOK_ASM_asl || tok == TOK_ASM_lsl || tok == TOK_ASM_lsr || tok == TOK_ASM_asr || tok == TOK_ASM_ror || tok == TOK_ASM_rrx)
+            break;
         parse_operand(s1, &ops[nb_ops]);
-        if (tok != ',') {
-            ++nb_ops;
+        ++nb_ops;
+        if (tok != ',')
             break;
-        }
         next(); // skip ','
     }
+    if (tok == ',')
+        next();
+    switch (tok) {
+    case TOK_ASM_asl:
+    case TOK_ASM_lsl:
+    case TOK_ASM_asr:
+    case TOK_ASM_lsr:
+    case TOK_ASM_ror:
+        switch (tok) {
+        case TOK_ASM_asl:
+            /* fallthrough */
+        case TOK_ASM_lsl:
+            operands |= ENCODE_BARREL_SHIFTER_MODE_LSL;
+            break;
+        case TOK_ASM_asr:
+            operands |= ENCODE_BARREL_SHIFTER_MODE_ASR;
+            break;
+        case TOK_ASM_lsr:
+            operands |= ENCODE_BARREL_SHIFTER_MODE_LSR;
+            break;
+        case TOK_ASM_ror:
+            operands |= ENCODE_BARREL_SHIFTER_MODE_ROR;
+            break;
+        }
+        next();
+        parse_operand(s1, &shift);
+        nb_shift = 1;
+        break;
+    case TOK_ASM_rrx:
+        next();
+        operands |= ENCODE_BARREL_SHIFTER_MODE_ROR;
+        break;
+    }
     if (nb_ops < 2)
         expect("at least two operands");
     else if (nb_ops == 2) {
@@ -437,7 +474,6 @@ static void asm_data_processing_opcode(TCCState *s1, int token)
         return;
     } else {
         uint32_t opcode = 0;
-        uint32_t operands = 0;
 
         // data processing (general case):
         // operands:
@@ -461,16 +497,13 @@ static void asm_data_processing_opcode(TCCState *s1, int token)
             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
@@ -534,6 +567,13 @@ static void asm_data_processing_opcode(TCCState *s1, int token)
             expect("(second source operand) register or immediate value");
         }
 
+        if (nb_shift) {
+            if (operands & ENCODE_IMMEDIATE_FLAG)
+                tcc_error("immediate rotation not implemented");
+            else
+                operands |= asm_encode_shift(&shift);
+        }
+
         /* 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);
diff --git a/arm-tok.h b/arm-tok.h
index a1fb158..6d2483b 100644
--- a/arm-tok.h
+++ b/arm-tok.h
@@ -28,6 +28,10 @@
  DEF_ASM(lr) /* alias for r14 */
  DEF_ASM(pc) /* alias for r15 */
 
+ /* data processing directives */
+
+ DEF_ASM(asl)
+
 #define ARM_INSTRUCTION_GROUP(tok) ((((tok) - TOK_ASM_nopeq) & 0xFFFFFFF0) + TOK_ASM_nopeq)
 
 /* Note: condition code is 4 bits */

_______________________________________________
Tinycc-devel mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/tinycc-devel
Reply | Threaded
Open this post in threaded view
|

[PATCH 3/9] arm-asm: Support rotation for sxtb, sxth, uxtb, uxth

Danny Milosavljevic
In reply to this post by Danny Milosavljevic
---
 arm-asm.c | 51 +++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 41 insertions(+), 10 deletions(-)

diff --git a/arm-asm.c b/arm-asm.c
index ef75091..f672301 100644
--- a/arm-asm.c
+++ b/arm-asm.c
@@ -201,6 +201,9 @@ static void asm_unary_opcode(TCCState *s1, int token)
 static void asm_binary_opcode(TCCState *s1, int token)
 {
     Operand ops[2];
+    Operand rotation;
+    uint32_t encoded_rotation = 0;
+    uint64_t amount;
     parse_operand(s1, &ops[0]);
     if (tok == ',')
         next();
@@ -212,27 +215,55 @@ static void asm_binary_opcode(TCCState *s1, int token)
         return;
     }
 
-    if (ops[1].type != OP_REG32)
+    if (ops[1].type != OP_REG32) {
         expect("(source operand) register");
-    else switch (ARM_INSTRUCTION_GROUP(token)) {
+        return;
+    }
+
+    if (tok == ',') {
+        next(); // skip ','
+        if (tok == TOK_ASM_ror) {
+            next(); // skip 'ror'
+            parse_operand(s1, &rotation);
+            if (rotation.type != OP_IM8) {
+                expect("immediate value for rotation");
+                return;
+            } else {
+                amount = rotation.e.v;
+                switch (amount) {
+                case 8:
+                    encoded_rotation = 1 << 10;
+                    break;
+                case 16:
+                    encoded_rotation = 2 << 10;
+                    break;
+                case 24:
+                    encoded_rotation = 3 << 10;
+                    break;
+                default:
+                    expect("'8' or '16' or '24'");
+                    return;
+                }
+            }
+        }
+    }
+    switch (ARM_INSTRUCTION_GROUP(token)) {
     case TOK_ASM_clzeq:
+        if (encoded_rotation)
+            tcc_error("clz does not support rotation");
         asm_emit_opcode(token, 0x16f0f10 | (ops[0].reg << 12) | ops[1].reg);
         break;
     case TOK_ASM_sxtbeq:
-        /* TODO: optional ROR (8|16|24) */
-        asm_emit_opcode(token, 0x6af0070 | (ops[0].reg << 12) | ops[1].reg);
+        asm_emit_opcode(token, 0x6af0070 | (ops[0].reg << 12) | ops[1].reg | encoded_rotation);
         break;
     case TOK_ASM_sxtheq:
-        /* TODO: optional ROR (8|16|24) */
-        asm_emit_opcode(token, 0x6bf0070 | (ops[0].reg << 12) | ops[1].reg);
+        asm_emit_opcode(token, 0x6bf0070 | (ops[0].reg << 12) | ops[1].reg | encoded_rotation);
         break;
     case TOK_ASM_uxtbeq:
-        /* TODO: optional ROR (8|16|24) */
-        asm_emit_opcode(token, 0x6ef0070 | (ops[0].reg << 12) | ops[1].reg);
+        asm_emit_opcode(token, 0x6ef0070 | (ops[0].reg << 12) | ops[1].reg | encoded_rotation);
         break;
     case TOK_ASM_uxtheq:
-        /* TODO: optional ROR (8|16|24) */
-        asm_emit_opcode(token, 0x6ff0070 | (ops[0].reg << 12) | ops[1].reg);
+        asm_emit_opcode(token, 0x6ff0070 | (ops[0].reg << 12) | ops[1].reg | encoded_rotation);
         break;
     default:
         expect("binary instruction");

_______________________________________________
Tinycc-devel mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/tinycc-devel
Reply | Threaded
Open this post in threaded view
|

[PATCH 4/9] arm-asm: Warn if regset registers are not specified in ascending order

Danny Milosavljevic
In reply to this post by Danny Milosavljevic
---
 arm-asm.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arm-asm.c b/arm-asm.c
index f672301..fd6275a 100644
--- a/arm-asm.c
+++ b/arm-asm.c
@@ -77,6 +77,8 @@ static void parse_operand(TCCState *s1, Operand *op)
             } else
                 next(); // skip register name
 
+            if ((1 << reg) < regset)
+                tcc_warning("registers will be processed in ascending order by hardware--but are not specified in ascending order here");
             regset |= 1 << reg;
             if (tok != ',')
                 break;

_______________________________________________
Tinycc-devel mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/tinycc-devel
Reply | Threaded
Open this post in threaded view
|

[PATCH 5/9] arm-asm: Add error case in asm_multiplication_opcode

Danny Milosavljevic
In reply to this post by Danny Milosavljevic
---
 arm-asm.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arm-asm.c b/arm-asm.c
index fd6275a..847a4f3 100644
--- a/arm-asm.c
+++ b/arm-asm.c
@@ -732,8 +732,8 @@ static void asm_multiplication_opcode(TCCState *s1, int token)
             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
+            expect("at least three operands");
+            return;
         }
         nb_ops = 3;
     }

_______________________________________________
Tinycc-devel mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/tinycc-devel
Reply | Threaded
Open this post in threaded view
|

[PATCH 6/9] arm-asm: Raise an error if asm_binary_opcode is used with PC as operand

Danny Milosavljevic
In reply to this post by Danny Milosavljevic
---
 arm-asm.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arm-asm.c b/arm-asm.c
index 847a4f3..d6adc20 100644
--- a/arm-asm.c
+++ b/arm-asm.c
@@ -217,11 +217,21 @@ static void asm_binary_opcode(TCCState *s1, int token)
         return;
     }
 
+    if (ops[0].reg == 15) {
+        tcc_error("'%s' does not support 'pc' as operand", get_tok_str(token, NULL));
+        return;
+    }
+
     if (ops[1].type != OP_REG32) {
         expect("(source operand) register");
         return;
     }
 
+    if (ops[1].reg == 15) {
+        tcc_error("'%s' does not support 'pc' as operand", get_tok_str(token, NULL));
+        return;
+    }
+
     if (tok == ',') {
         next(); // skip ','
         if (tok == TOK_ASM_ror) {

_______________________________________________
Tinycc-devel mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/tinycc-devel
Reply | Threaded
Open this post in threaded view
|

[PATCH 7/9] arm-asm: Print a warning if asm_binary_opcode is used with SP as operand

Danny Milosavljevic
In reply to this post by Danny Milosavljevic
---
 arm-asm.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arm-asm.c b/arm-asm.c
index d6adc20..028f30c 100644
--- a/arm-asm.c
+++ b/arm-asm.c
@@ -222,6 +222,9 @@ static void asm_binary_opcode(TCCState *s1, int token)
         return;
     }
 
+    if (ops[0].reg == 13)
+        tcc_warning("Using 'sp' as operand with '%s' is deprecated by ARM", get_tok_str(token, NULL));
+
     if (ops[1].type != OP_REG32) {
         expect("(source operand) register");
         return;
@@ -232,6 +235,9 @@ static void asm_binary_opcode(TCCState *s1, int token)
         return;
     }
 
+    if (ops[1].reg == 13)
+        tcc_warning("Using 'sp' as operand with '%s' is deprecated by ARM", get_tok_str(token, NULL));
+
     if (tok == ',') {
         next(); // skip ','
         if (tok == TOK_ASM_ror) {

_______________________________________________
Tinycc-devel mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/tinycc-devel
Reply | Threaded
Open this post in threaded view
|

[PATCH 8/9] arm-asm: Raise error if more than two operands are specified on mov, mvn, cmp, cmn, tst, teq

Danny Milosavljevic
In reply to this post by Danny Milosavljevic
---
 arm-asm.c | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/arm-asm.c b/arm-asm.c
index 028f30c..b565127 100644
--- a/arm-asm.c
+++ b/arm-asm.c
@@ -466,8 +466,9 @@ static void asm_data_processing_opcode(TCCState *s1, int token)
     int nb_shift = 0;
     uint32_t operands = 0;
 
-    /* 16 entries per instruction for the different condition codes */
+    /* modulo 16 entries per instruction for the different condition codes */
     uint32_t opcode_idx = (ARM_INSTRUCTION_GROUP(token) - TOK_ASM_andeq) >> 4;
+    uint32_t opcode_nos = opcode_idx >> 1; // without "s"; "OpCode" in ARM docs
 
     for (nb_ops = 0; nb_ops < sizeof(ops)/sizeof(ops[0]); ) {
         if (tok == TOK_ASM_asl || tok == TOK_ASM_lsl || tok == TOK_ASM_lsr || tok == TOK_ASM_asr || tok == TOK_ASM_ror || tok == TOK_ASM_rrx)
@@ -517,6 +518,11 @@ static void asm_data_processing_opcode(TCCState *s1, int token)
         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;
+    } else if (nb_ops == 3) {
+        if (opcode_nos == 0xd || opcode_nos == 0xf || opcode_nos == 0xa || opcode_nos == 0xb || opcode_nos == 0x8 || opcode_nos == 0x9) { // mov, mvn, cmp, cmn, tst, teq
+            tcc_error("'%s' cannot be used with three operands", get_tok_str(token, NULL));
+            return;
+        }
     }
     if (nb_ops != 3) {
         expect("two or three operands");
@@ -533,16 +539,16 @@ static void asm_data_processing_opcode(TCCState *s1, int token)
         //   bits 24...21: "OpCode"--see below
 
         /* operations in the token list are ordered by opcode */
-        opcode = (opcode_idx >> 1) << 21; // drop "s"
+        opcode = opcode_nos << 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
+        else if (opcode_nos == 0xa || opcode_nos == 0xb || opcode_nos == 0x8 || opcode_nos == 0x9) // 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)
+        else if (!(opcode_nos == 0xd || opcode_nos == 0xf)) // not: mov, mvn (those have only one source operand)
             operands |= ENCODE_RN(ops[1].reg);
         switch (ops[2].type) {
         case OP_REG32:
@@ -562,7 +568,7 @@ static void asm_data_processing_opcode(TCCState *s1, int token)
                1001 = TEQ - CC on: Op1 EOR Op2   -> difficult
                1100 = ORR - Rd:= Op1 OR Op2      -> difficult
             */
-            switch (opcode_idx >> 1) { // "OpCode" in ARM docs
+            switch (opcode_nos) {
 #if 0
             case 0x0: // AND - Rd:= Op1 AND Op2
                 opcode = 0xe << 21; // BIC

_______________________________________________
Tinycc-devel mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/tinycc-devel
Reply | Threaded
Open this post in threaded view
|

[PATCH 9/9] arm-asm: Raise error if asm_data_processing_opcode and asm_shift_opcode try to use PC for register-controlled shifts

Danny Milosavljevic
In reply to this post by Danny Milosavljevic
---
 arm-asm.c | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/arm-asm.c b/arm-asm.c
index b565127..6eb680a 100644
--- a/arm-asm.c
+++ b/arm-asm.c
@@ -529,6 +529,13 @@ static void asm_data_processing_opcode(TCCState *s1, int token)
         return;
     } else {
         uint32_t opcode = 0;
+        if (nb_shift && shift.type == OP_REG32) {
+            if ((ops[0].type == OP_REG32 && ops[0].reg == 15) ||
+                (ops[1].type == OP_REG32 && ops[1].reg == 15)) {
+                tcc_error("Using the 'pc' register in data processing instructions that have a register-controlled shift is not implemented by ARM");
+                return;
+            }
+        }
 
         // data processing (general case):
         // operands:
@@ -655,9 +662,10 @@ static void asm_shift_opcode(TCCState *s1, int token)
         return;
     }
 
-    if (ops[0].type != OP_REG32)
+    if (ops[0].type != OP_REG32) {
         expect("(destination operand) register");
-    else
+        return;
+    } else
         operands |= ENCODE_RD(ops[0].reg);
 
     if (nb_ops == 2) {
@@ -694,6 +702,13 @@ static void asm_shift_opcode(TCCState *s1, int token)
         break;
     }
 
+    if (ops[2].type == OP_REG32) {
+        if ((ops[0].type == OP_REG32 && ops[0].reg == 15) ||
+            (ops[1].type == OP_REG32 && ops[1].reg == 15)) {
+            tcc_error("Using the 'pc' register in data processing instructions that have a register-controlled shift is not implemented by ARM");
+        }
+    }
+
     if (operands & ENCODE_IMMEDIATE_FLAG)
         operands |= asm_encode_rotation(&ops[2]);
     else

_______________________________________________
Tinycc-devel mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/tinycc-devel
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 0/9] Improve ARM inline assembler

Danny Milosavljevic
In reply to this post by Danny Milosavljevic
Improved unit tester:

#!/bin/sh

set -e
cd ~/src/tinycc-upstream/tinycc

cat arm-tok.h |grep DEF_ASM_CONDED |grep -v '#define' |grep -v '/[*]' |sed -e 's;DEF_ASM_CONDED.\(.*\).$;\1;'| grep -v 'not useful' >L
total_count=0

# Note: "{r3}" is definitely done differently on tcc than on as--but would complicate the tcc assembler to do it the same way.

for s in $(cat L)
do
        ok=0
        for args in "r3, r4, r5, r6" \
                    "r3, r4, r5" \
                    "r3, r4, r5, asl #7" \
                    "r3, r4, r5, lsl #7" \
                    "r3, r4, r5, asr #7" \
                    "r3, r4, r5, lsr #7" \
                    "r3, r4, r5, ror #7" \
                    "r3, r4, r5, rrx" \
                    "r3, r4, r5, asl r6" \
                    "r3, r4, r5, lsl r6" \
                    "r3, r4, r5, asr r6" \
                    "r3, r4, r5, lsr r6" \
                    "r3, r4, r5, ror r6" \
                    "r3, r4, #5, asl #7" \
                    "r3, r4, #5, lsl #7" \
                    "r3, r4, #5, asr #7" \
                    "r3, r4, #5, lsr #7" \
                    "r3, r4, #5, ror #7" \
                    "r3, r4, #5, rrx" \
                    "r3, #5, r4" \
                    "r3, #4, #8" \
                    "r3, r4, asl #5" \
                    "r3, r4, lsl #5" \
                    "r3, r4, asr #5" \
                    "r3, r4, lsr #5" \
                    "r3, r4, ror #5" \
                    "r3, r4, ror #8" \
                    "r3, r4, asl r5" \
                    "r3, r4, lsl r5" \
                    "r3, r4, asr r5" \
                    "r3, r4, lsr r5" \
                    "r3, r4, ror r5" \
                    "r3, r4, ror #8" \
                    "r3, r4, ror #16" \
                    "r3, r4, ror #24" \
                    "r3, r4, rrx" \
                    "r3, #4, asl #5" \
                    "r3, #4, lsl #5" \
                    "r3, #4, asr #5" \
                    "r3, #4, lsr #5" \
                    "r3, #4, ror #5" \
                    "r3, r4, rrx" \
                    "r3, r4" \
                    "r3" \
                    "{r3,r4,r5}" \
                    "{r3,r5,r4}" \
                    "r2!, {r3,r4,r5}" \
                    "r2!, {r3,r5,r4}" \
                    "r2, [r3, r4]" \
                    "r2, [r3, r4]!" \
                    "r2, [r3, -r4]" \
                    "r2, [r3, -r4]!" \
                    "r2, [r3], r4" \
                    "r2, [r3, #4]" \
                    "r2, [r3, #-4]" \
                    "r2, r3, #4" \
                    "r2, r3, #-4" \
                    "r2, #4" \
                    "r2, #-4" \
                    "#4" \
                    "#-4" \
                    ""
        do
                echo "$s $args" > a.s
                #cat a.s
                if as -o a.o a.s 2>err
                then
                        cat err
                        total_count=`expr $total_count + 1`
                        objdump -S a.o |grep "^[ ]*0:" >a.expected

                        echo '__asm__("'"$s ${args}"'");' > a.c
                        if ./tcc -o a.o -c a.c
                        then
                                objdump -S a.o |grep "^[ ]*0:" >a.got
                                diff -u a.got a.expected || {
                                        echo "warning: $s $args did not work in tcc (see above)">&2
                                }
                        else
                                echo "warning: $s $args did not work in tcc">&2
                        fi
                        ok=1
                fi
        done
        if [ "${ok}" -eq "0" ]
        then
                echo "warning: $s could not be used.">&2
                continue
        fi
done
echo "total count: ${total_count}">&2

_______________________________________________
Tinycc-devel mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/tinycc-devel

attachment0 (499 bytes) Download Attachment