[PATCH 0/3] Improvements to ARM inline assembler

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

[PATCH 0/3] Improvements to ARM inline assembler

Danny Milosavljevic
This patchset adds some more improvements to the ARM inline assembler.

1. Bugfix for branch instruction so it can actually branch to (past) labels.
2. Add ldrex, strex instructions.
3. Allow implicit offset 0, for example: ldr r1, [r2]

Danny Milosavljevic (3):
  arm-asm: Implement branch to label
  arm-asm: Add ldrex, ldrexb, strex, strexb
  arm-asm: Allow implicit offset 0 in input of
    asm_single_data_transfer_opcode

 arm-asm.c | 119 +++++++++++++++++++++++++++++++++++++++++++-----------
 arm-tok.h |   4 ++
 2 files changed, 99 insertions(+), 24 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/3] arm-asm: Implement branch to label

Danny Milosavljevic
---
 arm-asm.c | 34 +++++++++++++++++++---------------
 1 file changed, 19 insertions(+), 15 deletions(-)

diff --git a/arm-asm.c b/arm-asm.c
index fc92898..27f396b 100644
--- a/arm-asm.c
+++ b/arm-asm.c
@@ -1058,9 +1058,9 @@ static uint32_t encbranchoffset(int pos, int addr, int fail)
 {
   addr-=pos+8;
   addr/=4;
-  if(addr>=0x1000000 || addr<-0x1000000) { // FIXME: Is that correct?
+  if(addr>=0x7fffff || addr<-0x800000) {
     if(fail)
-      tcc_error("function bigger than 32MB");
+      tcc_error("branch offset is too far");
     return 0;
   }
   return /*not 0x0A000000|*/(addr&0xffffff);
@@ -1070,26 +1070,30 @@ static void asm_branch_opcode(TCCState *s1, int token)
 {
     int jmp_disp = 0;
     Operand op;
-    parse_operand(s1, &op);
-    if (op.type == OP_IM32 || op.type == OP_IM8 || op.type == OP_IM8N) {
-        jmp_disp = encbranchoffset(ind, op.e.v, 0);
-        if (jmp_disp < -0x800000 || jmp_disp > 0x7fffff) {
-            tcc_error("branch is too far");
+    ExprValue e;
+    ElfSym *esym;
+
+    switch (ARM_INSTRUCTION_GROUP(token)) {
+    case TOK_ASM_beq:
+    case TOK_ASM_bleq:
+        asm_expr(s1, &e);
+        esym = elfsym(e.sym);
+        if (!esym || esym->st_shndx != cur_text_section->sh_num) {
+            tcc_error("invalid branch target");
             return;
         }
+        jmp_disp = encbranchoffset(ind, e.v + esym->st_value, 1);
+        break;
+    default:
+        parse_operand(s1, &op);
+        break;
     }
     switch (ARM_INSTRUCTION_GROUP(token)) {
     case TOK_ASM_beq:
-        if (op.type == OP_IM32 || op.type == OP_IM8 || op.type == OP_IM8N)
-            asm_emit_opcode(token, (0xa << 24) | (jmp_disp & 0xffffff));
-        else
-            expect("branch target");
+        asm_emit_opcode(token, (0xa << 24) | (jmp_disp & 0xffffff));
         break;
     case TOK_ASM_bleq:
-        if (op.type == OP_IM32 || op.type == OP_IM8 || op.type == OP_IM8N)
-            asm_emit_opcode(token, (0xb << 24) | (jmp_disp & 0xffffff));
-        else
-            expect("branch target");
+        asm_emit_opcode(token, (0xb << 24) | (jmp_disp & 0xffffff));
         break;
     case TOK_ASM_bxeq:
         if (op.type != OP_REG32)

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

[PATCH 2/3] arm-asm: Add ldrex, ldrexb, strex, strexb

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

diff --git a/arm-asm.c b/arm-asm.c
index 27f396b..5b64fa6 100644
--- a/arm-asm.c
+++ b/arm-asm.c
@@ -939,10 +939,11 @@ static void asm_long_multiplication_opcode(TCCState *s1, int token)
 static void asm_single_data_transfer_opcode(TCCState *s1, int token)
 {
     Operand ops[3];
+    Operand strex_operand;
     int exclam = 0;
     int closed_bracket = 0;
     int op2_minus = 0;
-    uint32_t opcode = 1 << 26;
+    uint32_t opcode = 0;
     // Note: ldr r0, [r4, #4]  ; simple offset: r0 = *(int*)(r4+4); r4 unchanged
     // Note: ldr r0, [r4, #4]! ; pre-indexed:   r0 = *(int*)(r4+4); r4 = r4+4
     // Note: ldr r0, [r4], #4  ; post-indexed:  r0 = *(int*)(r4+0); r4 = r4+4
@@ -955,9 +956,25 @@ static void asm_single_data_transfer_opcode(TCCState *s1, int token)
         return;
     }
     if (tok != ',')
-        expect("two arguments");
+        expect("at least two arguments");
     else
         next(); // skip ','
+
+    switch (ARM_INSTRUCTION_GROUP(token)) {
+    case TOK_ASM_strexbeq:
+    case TOK_ASM_strexeq:
+        parse_operand(s1, &strex_operand);
+        if (strex_operand.type != OP_REG32) {
+            expect("register");
+            return;
+        }
+        if (tok != ',')
+            expect("at least three arguments");
+        else
+            next(); // skip ','
+        break;
+    }
+
     if (tok != '[')
         expect("'['");
     else
@@ -1039,6 +1056,7 @@ static void asm_single_data_transfer_opcode(TCCState *s1, int token)
         opcode |= 1 << 22; // B
         /* fallthrough */
     case TOK_ASM_streq:
+        opcode |= 1 << 26; // Load/Store
         asm_emit_opcode(token, opcode);
         break;
     case TOK_ASM_ldrbeq:
@@ -1046,6 +1064,47 @@ static void asm_single_data_transfer_opcode(TCCState *s1, int token)
         /* fallthrough */
     case TOK_ASM_ldreq:
         opcode |= 1 << 20; // L
+        opcode |= 1 << 26; // Load/Store
+        asm_emit_opcode(token, opcode);
+        break;
+    case TOK_ASM_strexbeq:
+        opcode |= 1 << 22; // B
+        /* fallthrough */
+    case TOK_ASM_strexeq:
+        if (opcode & 0xFFF) {
+            tcc_error("offset not allowed with 'strex'");
+            return;
+        } else if (opcode & ENCODE_IMMEDIATE_FLAG) { // if set, it means it's NOT immediate
+            tcc_error("offset not allowed with 'strex'");
+            return;
+        }
+        if ((opcode & (1 << 24)) == 0) { // add offset after transfer
+            tcc_error("adding offset after transfer not allowed with 'strex'");
+            return;
+        }
+
+        opcode |= 0xf90;
+        opcode |= strex_operand.reg;
+        asm_emit_opcode(token, opcode);
+        break;
+    case TOK_ASM_ldrexbeq:
+        opcode |= 1 << 22; // B
+        /* fallthrough */
+    case TOK_ASM_ldrexeq:
+        if (opcode & 0xFFF) {
+            tcc_error("offset not allowed with 'ldrex'");
+            return;
+        } else if (opcode & ENCODE_IMMEDIATE_FLAG) { // if set, it means it's NOT immediate
+            tcc_error("offset not allowed with 'ldrex'");
+            return;
+        }
+        if ((opcode & (1 << 24)) == 0) { // add offset after transfer
+            tcc_error("adding offset after transfer not allowed with 'ldrex'");
+            return;
+        }
+        opcode |= 1 << 20; // L
+        opcode |= 0x00f;
+        opcode |= 0xf90;
         asm_emit_opcode(token, opcode);
         break;
     default:
@@ -1163,6 +1222,10 @@ ST_FUNC void asm_opcode(TCCState *s1, int token)
     case TOK_ASM_ldrbeq:
     case TOK_ASM_streq:
     case TOK_ASM_strbeq:
+    case TOK_ASM_ldrexeq:
+    case TOK_ASM_ldrexbeq:
+    case TOK_ASM_strexeq:
+    case TOK_ASM_strexbeq:
         return asm_single_data_transfer_opcode(s1, token);
 
     case TOK_ASM_andeq:
diff --git a/arm-tok.h b/arm-tok.h
index 7c1a202..be927cc 100644
--- a/arm-tok.h
+++ b/arm-tok.h
@@ -93,6 +93,10 @@
  DEF_ASM_CONDED(ldrb)
  DEF_ASM_CONDED(str)
  DEF_ASM_CONDED(strb)
+ DEF_ASM_CONDED(ldrex)
+ DEF_ASM_CONDED(ldrexb)
+ DEF_ASM_CONDED(strex)
+ DEF_ASM_CONDED(strexb)
 
  DEF_ASM_CONDED(stmda)
  DEF_ASM_CONDED(ldmda)

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

[PATCH 3/3] arm-asm: Allow implicit offset 0 in input of asm_single_data_transfer_opcode

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

diff --git a/arm-asm.c b/arm-asm.c
index 5b64fa6..0f7340c 100644
--- a/arm-asm.c
+++ b/arm-asm.c
@@ -992,15 +992,19 @@ static void asm_single_data_transfer_opcode(TCCState *s1, int token)
         closed_bracket = 1;
         // exclam = 1; // implicit in hardware; don't do it in software
     }
-    if (tok != ',')
-        expect("','");
-    else
+    if (tok == ',') {
         next(); // skip ','
-    if (tok == '-') {
-        op2_minus = 1;
-        next();
+        if (tok == '-') {
+            op2_minus = 1;
+            next();
+        }
+        parse_operand(s1, &ops[2]);
+    } else {
+        // end of input expression in brackets--assume 0 offset
+        ops[2].type = OP_IM8;
+        ops[2].e.v = 0;
+        opcode |= 1 << 24; // add offset before transfer
     }
-    parse_operand(s1, &ops[2]);
     if (!closed_bracket) {
         if (tok != ']')
             expect("']'");

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

Re: [PATCH 1/3] arm-asm: Implement branch to label

Danny Milosavljevic
In reply to this post by Danny Milosavljevic
Some tests which cannot be automatically generated:

1.

__asm__(".a:\n\t"
        "mov r0, #1\n\t"
        "bne .a");

2.

__asm__("mov r0, #1\n\t"
        "bne L0\n\t"
        "L0:\n\t");

3.

__asm__("mov r1, #2\n\t"
        ".L0:\n\t"
        "mov r0, #1\n\t"
        "bne .L0");

So maybe we should have a directory with manual assembly tests, probably at
least one for arm and one for x86.

What do you think?

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

attachment0 (499 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 1/3] arm-asm: Implement branch to label

Michael Matz-4
Hello,

On Tue, 5 Jan 2021, Danny Milosavljevic wrote:

> Some tests which cannot be automatically generated:
>
> 1.
>
> __asm__(".a:\n\t"
>        "mov r0, #1\n\t"
>        "bne .a");
>
> 2.
>
> __asm__("mov r0, #1\n\t"
>        "bne L0\n\t"
>        "L0:\n\t");
>
> 3.
>
> __asm__("mov r1, #2\n\t"
>        ".L0:\n\t"
>        "mov r0, #1\n\t"
>        "bne .L0");
>
> So maybe we should have a directory with manual assembly tests, probably
> at least one for arm and one for x86.
>
> What do you think?

Don't overcomplicate :)  Make it one file and add it as tests/asm-arm.c
(or .s or .S).


Ciao,
Michael.

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