From 155fdc74d5864266441887d6c88111159f401a62 Mon Sep 17 00:00:00 2001
From: Damien George <damien.p.george@gmail.com>
Date: Fri, 9 Dec 2016 22:50:58 +1100
Subject: [PATCH] py/asm: Remove need for dummy_data when doing initial
 assembler passes.

For all but the last pass the assembler only needs to count how much space
is needed for the machine code, it doesn't actually need to emit anything.
The dummy_data just uses unnecessary RAM and without it the code is not
any more complex (and code size does not increase for Thumb and Xtensa
archs).
---
 py/asmarm.c    |  5 ++++-
 py/asmbase.c   | 18 ++++++++----------
 py/asmbase.h   |  3 ---
 py/asmthumb.c  | 20 ++++++++++++--------
 py/asmx64.c    | 46 ++++++++++++++++++++++++++++------------------
 py/asmx64.h    |  1 -
 py/asmx86.c    | 36 ++++++++++++++++++++++--------------
 py/asmx86.h    |  1 -
 py/asmxtensa.c | 16 ++++++++++------
 9 files changed, 84 insertions(+), 62 deletions(-)

diff --git a/py/asmarm.c b/py/asmarm.c
index 663f86156..63963d2c0 100644
--- a/py/asmarm.c
+++ b/py/asmarm.c
@@ -55,7 +55,10 @@ void asm_arm_end_pass(asm_arm_t *as) {
 
 // Insert word into instruction flow
 STATIC void emit(asm_arm_t *as, uint op) {
-    *(uint*)asm_arm_get_cur_to_write_bytes(as, 4) = op;
+    uint8_t *c = mp_asm_base_get_cur_to_write_bytes(&as->base, 4);
+    if (c != NULL) {
+        *(uint32_t*)c = op;
+    }
 }
 
 // Insert word into instruction flow, add "ALWAYS" condition code
diff --git a/py/asmbase.c b/py/asmbase.c
index 848730593..c941e917b 100644
--- a/py/asmbase.c
+++ b/py/asmbase.c
@@ -59,17 +59,16 @@ void mp_asm_base_start_pass(mp_asm_base_t *as, int pass) {
 }
 
 // all functions must go through this one to emit bytes
-// if as->pass < MP_ASM_PASS_EMIT, then this function returns dummy_data
+// if as->pass < MP_ASM_PASS_EMIT, then this function just counts the number
+// of bytes needed and returns NULL, and callers should not store any data
 uint8_t *mp_asm_base_get_cur_to_write_bytes(mp_asm_base_t *as, size_t num_bytes_to_write) {
-    if (as->pass < MP_ASM_PASS_EMIT) {
-        as->code_offset += num_bytes_to_write;
-        return as->dummy_data;
-    } else {
+    uint8_t *c = NULL;
+    if (as->pass == MP_ASM_PASS_EMIT) {
         assert(as->code_offset + num_bytes_to_write <= as->code_size);
-        uint8_t *c = as->code_base + as->code_offset;
-        as->code_offset += num_bytes_to_write;
-        return c;
+        c = as->code_base + as->code_offset;
     }
+    as->code_offset += num_bytes_to_write;
+    return c;
 }
 
 void mp_asm_base_label_assign(mp_asm_base_t *as, size_t label) {
@@ -92,8 +91,7 @@ void mp_asm_base_align(mp_asm_base_t* as, unsigned int align) {
 // this function assumes a little endian machine
 void mp_asm_base_data(mp_asm_base_t* as, unsigned int bytesize, uintptr_t val) {
     uint8_t *c = mp_asm_base_get_cur_to_write_bytes(as, bytesize);
-    // only write to the buffer in the emit pass (otherwise we may overflow dummy_data)
-    if (as->pass == MP_ASM_PASS_EMIT) {
+    if (c != NULL) {
         for (unsigned int i = 0; i < bytesize; i++) {
             *c++ = val;
             val >>= 8;
diff --git a/py/asmbase.h b/py/asmbase.h
index 06fdd4b90..d2b403893 100644
--- a/py/asmbase.h
+++ b/py/asmbase.h
@@ -40,9 +40,6 @@ typedef struct _mp_asm_base_t {
 
     size_t max_num_labels;
     size_t *label_offsets;
-
-    // must be last in struct
-    uint8_t dummy_data[4];
 } mp_asm_base_t;
 
 void mp_asm_base_init(mp_asm_base_t *as, size_t max_num_labels);
diff --git a/py/asmthumb.c b/py/asmthumb.c
index 82a226b62..749c1e405 100644
--- a/py/asmthumb.c
+++ b/py/asmthumb.c
@@ -162,18 +162,22 @@ STATIC mp_uint_t get_label_dest(asm_thumb_t *as, uint label) {
 
 void asm_thumb_op16(asm_thumb_t *as, uint op) {
     byte *c = asm_thumb_get_cur_to_write_bytes(as, 2);
-    // little endian
-    c[0] = op;
-    c[1] = op >> 8;
+    if (c != NULL) {
+        // little endian
+        c[0] = op;
+        c[1] = op >> 8;
+    }
 }
 
 void asm_thumb_op32(asm_thumb_t *as, uint op1, uint op2) {
     byte *c = asm_thumb_get_cur_to_write_bytes(as, 4);
-    // little endian, op1 then op2
-    c[0] = op1;
-    c[1] = op1 >> 8;
-    c[2] = op2;
-    c[3] = op2 >> 8;
+    if (c != NULL) {
+        // little endian, op1 then op2
+        c[0] = op1;
+        c[1] = op1 >> 8;
+        c[2] = op2;
+        c[3] = op2 >> 8;
+    }
 }
 
 #define OP_FORMAT_4(op, rlo_dest, rlo_src) ((op) | ((rlo_src) << 3) | (rlo_dest))
diff --git a/py/asmx64.c b/py/asmx64.c
index c9dad2a66..cf1a86b3f 100644
--- a/py/asmx64.c
+++ b/py/asmx64.c
@@ -122,40 +122,50 @@ static inline byte *asm_x64_get_cur_to_write_bytes(asm_x64_t *as, int n) {
 
 STATIC void asm_x64_write_byte_1(asm_x64_t *as, byte b1) {
     byte* c = asm_x64_get_cur_to_write_bytes(as, 1);
-    c[0] = b1;
+    if (c != NULL) {
+        c[0] = b1;
+    }
 }
 
 STATIC void asm_x64_write_byte_2(asm_x64_t *as, byte b1, byte b2) {
     byte* c = asm_x64_get_cur_to_write_bytes(as, 2);
-    c[0] = b1;
-    c[1] = b2;
+    if (c != NULL) {
+        c[0] = b1;
+        c[1] = b2;
+    }
 }
 
 STATIC void asm_x64_write_byte_3(asm_x64_t *as, byte b1, byte b2, byte b3) {
     byte* c = asm_x64_get_cur_to_write_bytes(as, 3);
-    c[0] = b1;
-    c[1] = b2;
-    c[2] = b3;
+    if (c != NULL) {
+        c[0] = b1;
+        c[1] = b2;
+        c[2] = b3;
+    }
 }
 
 STATIC void asm_x64_write_word32(asm_x64_t *as, int w32) {
     byte* c = asm_x64_get_cur_to_write_bytes(as, 4);
-    c[0] = IMM32_L0(w32);
-    c[1] = IMM32_L1(w32);
-    c[2] = IMM32_L2(w32);
-    c[3] = IMM32_L3(w32);
+    if (c != NULL) {
+        c[0] = IMM32_L0(w32);
+        c[1] = IMM32_L1(w32);
+        c[2] = IMM32_L2(w32);
+        c[3] = IMM32_L3(w32);
+    }
 }
 
 STATIC void asm_x64_write_word64(asm_x64_t *as, int64_t w64) {
     byte* c = asm_x64_get_cur_to_write_bytes(as, 8);
-    c[0] = IMM32_L0(w64);
-    c[1] = IMM32_L1(w64);
-    c[2] = IMM32_L2(w64);
-    c[3] = IMM32_L3(w64);
-    c[4] = IMM64_L4(w64);
-    c[5] = IMM64_L5(w64);
-    c[6] = IMM64_L6(w64);
-    c[7] = IMM64_L7(w64);
+    if (c != NULL) {
+        c[0] = IMM32_L0(w64);
+        c[1] = IMM32_L1(w64);
+        c[2] = IMM32_L2(w64);
+        c[3] = IMM32_L3(w64);
+        c[4] = IMM64_L4(w64);
+        c[5] = IMM64_L5(w64);
+        c[6] = IMM64_L6(w64);
+        c[7] = IMM64_L7(w64);
+    }
 }
 
 /* unused
diff --git a/py/asmx64.h b/py/asmx64.h
index f80c8da8b..4499c53c3 100644
--- a/py/asmx64.h
+++ b/py/asmx64.h
@@ -72,7 +72,6 @@
 
 typedef struct _asm_x64_t {
     mp_asm_base_t base;
-    byte dummy_data[4]; // in addition to dummy_data in base
     int num_locals;
 } asm_x64_t;
 
diff --git a/py/asmx86.c b/py/asmx86.c
index cb9b30d40..ef315bf43 100644
--- a/py/asmx86.c
+++ b/py/asmx86.c
@@ -101,29 +101,37 @@
 #define SIGNED_FIT8(x) (((x) & 0xffffff80) == 0) || (((x) & 0xffffff80) == 0xffffff80)
 
 STATIC void asm_x86_write_byte_1(asm_x86_t *as, byte b1) {
-    byte* c = asm_x86_get_cur_to_write_bytes(as, 1);
-    c[0] = b1;
+    byte* c = mp_asm_base_get_cur_to_write_bytes(&as->base, 1);
+    if (c != NULL) {
+        c[0] = b1;
+    }
 }
 
 STATIC void asm_x86_write_byte_2(asm_x86_t *as, byte b1, byte b2) {
-    byte* c = asm_x86_get_cur_to_write_bytes(as, 2);
-    c[0] = b1;
-    c[1] = b2;
+    byte* c = mp_asm_base_get_cur_to_write_bytes(&as->base, 2);
+    if (c != NULL) {
+        c[0] = b1;
+        c[1] = b2;
+    }
 }
 
 STATIC void asm_x86_write_byte_3(asm_x86_t *as, byte b1, byte b2, byte b3) {
-    byte* c = asm_x86_get_cur_to_write_bytes(as, 3);
-    c[0] = b1;
-    c[1] = b2;
-    c[2] = b3;
+    byte* c = mp_asm_base_get_cur_to_write_bytes(&as->base, 3);
+    if (c != NULL) {
+        c[0] = b1;
+        c[1] = b2;
+        c[2] = b3;
+    }
 }
 
 STATIC void asm_x86_write_word32(asm_x86_t *as, int w32) {
-    byte* c = asm_x86_get_cur_to_write_bytes(as, 4);
-    c[0] = IMM32_L0(w32);
-    c[1] = IMM32_L1(w32);
-    c[2] = IMM32_L2(w32);
-    c[3] = IMM32_L3(w32);
+    byte* c = mp_asm_base_get_cur_to_write_bytes(&as->base, 4);
+    if (c != NULL) {
+        c[0] = IMM32_L0(w32);
+        c[1] = IMM32_L1(w32);
+        c[2] = IMM32_L2(w32);
+        c[3] = IMM32_L3(w32);
+    }
 }
 
 STATIC void asm_x86_write_r32_disp(asm_x86_t *as, int r32, int disp_r32, int disp_offset) {
diff --git a/py/asmx86.h b/py/asmx86.h
index ac4b2ecd0..0b44af663 100644
--- a/py/asmx86.h
+++ b/py/asmx86.h
@@ -75,7 +75,6 @@
 
 typedef struct _asm_x86_t {
     mp_asm_base_t base;
-    byte dummy_data[4]; // in addition to dummy_data in base
     int num_locals;
 } asm_x86_t;
 
diff --git a/py/asmxtensa.c b/py/asmxtensa.c
index 00df432ce..00448dfc5 100644
--- a/py/asmxtensa.c
+++ b/py/asmxtensa.c
@@ -97,15 +97,19 @@ STATIC uint32_t get_label_dest(asm_xtensa_t *as, uint label) {
 
 void asm_xtensa_op16(asm_xtensa_t *as, uint16_t op) {
     uint8_t *c = mp_asm_base_get_cur_to_write_bytes(&as->base, 2);
-    c[0] = op;
-    c[1] = op >> 8;
+    if (c != NULL) {
+        c[0] = op;
+        c[1] = op >> 8;
+    }
 }
 
 void asm_xtensa_op24(asm_xtensa_t *as, uint32_t op) {
     uint8_t *c = mp_asm_base_get_cur_to_write_bytes(&as->base, 3);
-    c[0] = op;
-    c[1] = op >> 8;
-    c[2] = op >> 16;
+    if (c != NULL) {
+        c[0] = op;
+        c[1] = op >> 8;
+        c[2] = op >> 16;
+    }
 }
 
 void asm_xtensa_j_label(asm_xtensa_t *as, uint label) {
@@ -147,7 +151,7 @@ void asm_xtensa_mov_reg_i32(asm_xtensa_t *as, uint reg_dest, uint32_t i32) {
         // load the constant
         asm_xtensa_op_l32r(as, reg_dest, as->base.code_offset, 4 + as->cur_const * WORD_SIZE);
         // store the constant in the table
-        if (as->base.pass == MP_ASM_PASS_EMIT) {
+        if (as->const_table != NULL) {
             as->const_table[as->cur_const] = i32;
         }
         ++as->cur_const;
-- 
GitLab