changeset 505:59b8c8b15bd4

Add integer shifts and fix code template errors for mul/div/mod One needs to remove stuff from the stack after putting it there. Actually do that in the code output for multiplication, division, and modulus. Add integer shifting code output which is optimized for constant shift counts but calls a routine for non-constant shift counts. Shifting by a negative amount is a no-op. Shifting by more than the size of an integer results in 0 (for left shifts) or -1 (for right shifts). Both negative shift counts and shift counts larger than the base type are undefined in the C standard so this behaviour is allowed.
author William Astle <lost@l-w.ca>
date Sat, 26 Oct 2019 22:01:55 -0600
parents 16bd8effb2f6
children 7e8298f7bc0a
files lwcc/cc-gencode.c
diffstat 1 files changed, 72 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/lwcc/cc-gencode.c	Thu Oct 24 22:41:04 2019 -0600
+++ b/lwcc/cc-gencode.c	Sat Oct 26 22:01:55 2019 -0600
@@ -20,6 +20,7 @@
 */
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 
 #include <lw_alloc.h>
@@ -36,6 +37,65 @@
     return lw_strdup(buf);
 }
 
+void generate_code(node_t *n, FILE *output);
+
+void generate_code_shift(node_t *n, FILE *output, int dir)
+{
+    generate_code(n -> children, output);
+    if (n -> children -> next_child -> type == NODE_CONST_INT)
+    {
+        long ival;
+        int i;
+        ival = strtol(n -> children -> next_child -> strval, NULL, 0);
+        if (ival <= 0)
+            return;
+        if (ival >= 16)
+        {
+            fprintf(output, "\tldd #%d\n", dir == 1 ? 0 : -1);
+            return;
+        }
+        if (ival >= 8)
+        {
+            if (dir == 1)
+            {
+                fprintf(output, "\ttfr b,a\n\tclrb\n");
+                for (i = ival - 8; i > 0; i--)
+                {
+                    fprintf(output, "\tlsla\n");
+                }
+            }
+            else
+            {
+                fprintf(output, "\ttfr a,b\n\tsex\n");
+                for (i = ival - 8; i > 0; i--)
+                {
+                    fprintf(output, "\tasrb\n");
+                }
+            }
+            return;
+        }
+        for (i = ival; i > 0; i--)
+        {
+            if (dir == 1)
+            {
+                fprintf(output, "\taslb\n\trola\n");
+            }
+            else
+            {
+                fprintf(output, "\tasra\n\trorb\n");
+            }
+        }
+        return;
+    }
+    else
+    {
+        fprintf(output, "\tpshs d\n");
+        generate_code(n -> children -> next_child, output);
+        fprintf(output, "\tjsr ___%ssh16\n\tpuls d\n", dir == 1 ? "l" : "r");
+    }
+}
+
+
 void generate_code(node_t *n, FILE *output)
 {
     node_t *nn;
@@ -45,7 +105,7 @@
     {
     // function definition - output prologue, then statements, then epilogue
     case NODE_FUNDEF:
-        fprintf(output, "_%s\n", n->children->next_child->strval);
+        fprintf(output, "\tsection .text\n\texport _%s\n_%s\n", n->children->next_child->strval, n->children->next_child->strval);
         generate_code(n->children->next_child->next_child->next_child, output);
         fprintf(output, "\trts\n");
         break;
@@ -72,21 +132,29 @@
         generate_code(n -> children, output);
         fprintf(output, "\tpshs d\n");
         generate_code(n->children->next_child, output);
-        fprintf(output, "\tjsr ___mul16i\n");
+        fprintf(output, "\tjsr ___mul16i\n\tpuls d\n");
         break;
 
     case NODE_OPER_DIVIDE:
         generate_code(n -> children, output);
         fprintf(output, "\tpshs d\n");
         generate_code(n->children->next_child, output);
-        fprintf(output, "\tjsr ___div16i\n");
+        fprintf(output, "\tjsr ___div16i\n\tpuls d\n");
         break;
     
     case NODE_OPER_MOD:
         generate_code(n -> children, output);
         fprintf(output, "\tpshs d\n");
         generate_code(n -> children -> next_child, output);
-        fprintf(output, "\tjsr ___mod16i\n");
+        fprintf(output, "\tjsr ___mod16i\n\tpuls d\n");
+        break;
+
+    case NODE_OPER_LSH:
+        generate_code_shift(n, output, 1);
+        break;
+
+    case NODE_OPER_RSH:
+        generate_code_shift(n, output, 0);
         break;
 
     case NODE_OPER_COND: