]> git.xonotic.org Git - xonotic/gmqcc.git/commitdiff
More assembler code (less allocations too)
authorDale Weiler <killfieldengine@gmail.com>
Thu, 3 May 2012 20:54:34 +0000 (16:54 -0400)
committerDale Weiler <killfieldengine@gmail.com>
Thu, 3 May 2012 20:54:34 +0000 (16:54 -0400)
Makefile
asm.c
code.c
data/test.qs
gmqcc.h
util.c

index ea2a27f2cf7b1b4936c9d11f8b2d721a6b947d6b..7c332105fe06e7ca708a981af3f930834cf11ac7 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -20,17 +20,17 @@ default: gmqcc
 
 # test targets
 test_ast: $(OBJ_A) $(OBJ)
-       $(CC) -o $@ $^ $(CFLAGS)        
+       $(CC) -o $@ $^ $(CFLAGS)
 test_ir:  $(OBJ_I) $(OBJ)
        $(CC) -o $@ $^ $(CFLAGS)
 test: test_ast test_ir
 
-# compiler target      
+# compiler target
 gmqcc: $(OBJ_C) $(OBJ)
        $(CC) -o $@ $^ $(CFLAGS)
 
 #all target is test and all
 all: test gmqcc
-       
+
 clean:
        rm -f *.o gmqcc test_ast test_ir test/*.o
diff --git a/asm.c b/asm.c
index 65199c9b84e11a4e135633c926fab7abbca29d2f..64a9492e99360889228ff5799589fbf86297b8c3 100644 (file)
--- a/asm.c
+++ b/asm.c
@@ -102,11 +102,11 @@ void asm_dumps() {
  * are locals.
  */
 static GMQCC_INLINE bool asm_parse_type(const char *skip, size_t line, asm_state *state) {
-    if (!(strstr(skip, "FLOAT:")  == &skip[0]) &&
-         (strstr(skip, "VECTOR:") == &skip[0]) &&
-         (strstr(skip, "ENTITY:") == &skip[0]) &&
-         (strstr(skip, "FIELD:")  == &skip[0]) &&
-         (strstr(skip, "STRING:") == &skip[0])) return false;
+    if ((strstr(skip, "FLOAT:")  != &skip[0]) &&
+        (strstr(skip, "VECTOR:") != &skip[0]) &&
+        (strstr(skip, "ENTITY:") != &skip[0]) &&
+        (strstr(skip, "FIELD:")  != &skip[0]) &&
+        (strstr(skip, "STRING:") != &skip[0])) return false;
 
     /* TODO: determine if constant, global, or local */
     switch (*skip) {
@@ -194,8 +194,16 @@ static GMQCC_INLINE bool asm_parse_func(const char *skip, size_t line, asm_state
         return false;
 
     if (strstr(skip, "FUNCTION:") == &skip[0]) {
-        char  *copy = util_strsws(skip+10);
-        char  *name = util_strchp(copy, strchr(copy, '\0'));
+        char  *look = util_strdup(skip+10);
+        char  *copy = look;
+        char  *name = NULL;
+        while(*copy == ' ' || *copy == '\t') copy++;
+
+        /*
+         * Chop the function name out of the string, this allocates
+         * a new string.
+         */
+        name = util_strchp(copy, strchr(copy, '\0'));
 
         /* TODO: failure system, missing name */
         if (!name) {
@@ -380,7 +388,7 @@ static GMQCC_INLINE bool asm_parse_func(const char *skip, size_t line, asm_state
              * We got valid function structure information now. Lets add
              * the function to the code writer function table.
              */
-            function.entry      = code_statements_elements-1;
+            function.entry      = code_statements_elements;
             function.firstlocal = 0;
             function.locals     = 0;
             function.profile    = 0;
@@ -391,7 +399,7 @@ static GMQCC_INLINE bool asm_parse_func(const char *skip, size_t line, asm_state
             def.offset          = code_globals_elements;
             def.name            = code_chars_elements;
             code_functions_add(function);
-            code_globals_add(code_statements_elements);
+            code_globals_add  (code_statements_elements);
             code_chars_put    (name, strlen(name));
             code_chars_add    ('\0');
 
@@ -418,9 +426,18 @@ static GMQCC_INLINE bool asm_parse_stmt(const char *skip, size_t line, asm_state
      * CALL* is used (depending on the amount of arguments the function
      * is expected to take)
      */
-    char                  *c = (char*)skip;
+    enum {
+        EXPECT_FUNCTION = 1,
+        EXPECT_VARIABLE = 2,
+        EXPECT_VALUE    = 3
+    };
+    
+    char                  *c      = (char*)skip;
+    size_t                 i      = 0;
+    char                   expect = 0;
     prog_section_statement s;
-    size_t                 i = 0;
+
+    memset(&s, 0, sizeof(s));
 
     /*
      * statements are only allowed when inside a function body
@@ -444,7 +461,36 @@ static GMQCC_INLINE bool asm_parse_stmt(const char *skip, size_t line, asm_state
          * instruction.
          */
         if (!strncmp(skip, asm_instr[i].m, asm_instr[i].l)) {
-            printf("found statement %s\n", asm_instr[i].m);
+
+            /*
+             * We hit the end of a function scope, retarget the state
+             * and add a DONE statement to the statment table.
+             */
+            if (i == AINSTR_END) {
+                s.opcode = i;
+                code_statements_add(s);
+                *state = ASM_NULL;
+                return true;
+            }
+
+            /*
+             * Check the instruction type to see what sort of data
+             * it's expected to have.
+             */
+            if (i >= INSTR_CALL0 && i <= INSTR_CALL8)
+                expect = EXPECT_FUNCTION;
+            else
+                expect = EXPECT_VARIABLE;
+            
+            util_debug(
+                "ASM",
+                "found statement %s expecting: `%s` (%ld operands)\n",
+                asm_instr[i].m,
+                (expect == EXPECT_FUNCTION)?"function name":(
+                (expect == EXPECT_VARIABLE)?"variable name":(
+                (expect == EXPECT_VALUE    ?"value"        : "unknown"))),
+                asm_instr[i].o
+            );
             /*
              * Parse the operands for `i` (the instruction). The order
              * of asm_instr is in the order of the menomic encoding so
@@ -485,26 +531,44 @@ static GMQCC_INLINE bool asm_parse_stmt(const char *skip, size_t line, asm_state
                        *c  = '\0';                                     \
                         c  = (char*)skip;                              \
                     } while (0)
-
-                case 3: {
-                    const char *data; OPFILL(data);
-                    printf("OP3: %s\n", data);
-                    s.o3.s1 = 0;
-                }
-                case 2: {
-                    const char *data; OPFILL(data);
-                    printf("OP2: %s\n", data);
-                    s.o2.s1 = 0;
-                }
+                #define OPEATS(X,Y) X##Y
+                #define OPCCAT(X,Y) OPEATS(X,Y)
+                #define OPLOAD(X,Y)                                                                \
+                    do {                                                                           \
+                        util_debug("ASM", "loading operand data ...\n");                           \
+                        if (expect == EXPECT_VARIABLE) {                                           \
+                            size_t f=0;                                                            \
+                            for (; f<assembly_constants_elements; f++) {                           \
+                                if (!strncmp(assembly_constants_data[f].name, (Y), strlen((Y)))) { \
+                                    (X)=assembly_constants_data[f].offset;                         \
+                                    goto OPCCAT(found, __LINE__);                                  \
+                                }                                                                  \
+                            }                                                                      \
+                            printf("no variable named %s\n", (Y));                                 \
+                            OPCCAT(found,__LINE__) :                                               \
+                            printf("operand loaded for %s\n", (Y));                                \
+                            break;                                                                 \
+                        } else if (expect == EXPECT_FUNCTION) {                                    \
+                            /*                                                                     \
+                             * It's a function call not a variable association with an instruction \
+                             * these are harder to handle.                                         \
+                             */                                                                    \
+                             printf("function calls not implemented, calling `68` for now\n");     \
+                             (X)=68;                                                               \
+                        }                                                                          \
+                    } while (0)
+                case 3: { OPLOAD(s.o3.s1,c); break; }
+                case 2: { OPLOAD(s.o2.s1,c); break; }
                 case 1: {
                     while (*c == ' ' || *c == '\t') c++;
                     c += asm_instr[i].l;
                     while (*c == ' ' || *c == '\t') c++;
-
-                    printf("OP1: %s\n", c);
-                    s.o1.s1 = 0;
+                    OPLOAD(s.o1.s1, c);
+                    break;
                 }
                 #undef OPFILL
+                #undef OPLOAD
+                #undef OPCCAT
             }
             /* add the statement now */
             code_statements_add(s);
@@ -515,7 +579,6 @@ static GMQCC_INLINE bool asm_parse_stmt(const char *skip, size_t line, asm_state
 
 void asm_parse(FILE *fp) {
     char     *data  = NULL;
-    char     *skip  = NULL;
     long      line  = 1; /* current line */
     size_t    size  = 0; /* size of line */
     asm_state state = ASM_NULL;
@@ -523,22 +586,21 @@ void asm_parse(FILE *fp) {
     #define asm_end(x)            \
         do {                      \
             mem_d(data);          \
-            mem_d(copy);          \
-            line++;               \
+            line ++;              \
             util_debug("ASM", x); \
         } while (0); continue
 
     while ((data = asm_getline (&size, fp)) != NULL) {
-        char *copy = util_strsws(data); /* skip   whitespace */
-              skip = util_strrnl(copy); /* delete newline    */
-
-        /* TODO: statement END check */
-        if (state == ASM_FUNCTION)
-            state =  ASM_NULL;
-
-        if (asm_parse_type(skip, line, &state)){ asm_end("asm_parse_type\n"); }
-        if (asm_parse_func(skip, line, &state)){ asm_end("asm_parse_func\n"); }
-        if (asm_parse_stmt(skip, line, &state)){ asm_end("asm_parse_stmt\n"); }
+        char   *copy = data;
+        char   *skip = copy;
+        while (*copy == ' ' || *copy == '\t') copy++;
+        while (*skip != '\n')                 skip++;
+        *skip='\0';
+              
+        if (asm_parse_type(copy, line, &state)){ asm_end("asm_parse_type\n"); }
+        if (asm_parse_func(copy, line, &state)){ asm_end("asm_parse_func\n"); }
+        if (asm_parse_stmt(copy, line, &state)){ asm_end("asm_parse_stmt\n"); }
+        asm_end("asm_parse_white\n");
     }
     #undef asm_end
     asm_dumps();
diff --git a/code.c b/code.c
index 89d7c8cd0d72761c16e5d7975d319e6c6bb25c5f..64b6260d172b946e15aafa227eb6dd00d40a48ae 100644 (file)
--- a/code.c
+++ b/code.c
@@ -147,7 +147,7 @@ void code_test() {
 void code_write() {
     prog_header  code_header;
     FILE        *fp           = NULL;
-    size_t       it           = 1;
+    size_t       it           = 2;
 
     /* see proposal.txt */
     if (opts_omit_nullcode) {}
@@ -231,15 +231,17 @@ void code_write() {
         if (code_functions_data[it].entry >= 0) {
             util_debug("GEN", "    CODE:\n");
             for (;;) {
-                if (code_statements_data[j].opcode != INSTR_DONE &&
-                    code_statements_data[j].opcode != INSTR_RETURN)
-                    util_debug("GEN", "        %s {0x%05d,0x%05d,0x%05d}\n",
+                if (code_statements_data[j].opcode != AINSTR_END)
+                    util_debug("GEN", "        %s {0x%05x,0x%05x,0x%05x}\n",
                         asm_instr[code_statements_data[j].opcode].m,
                         code_statements_data[j].o1.s1,
                         code_statements_data[j].o2.s1,
                         code_statements_data[j].o3.s1
                     );
-                else break;
+                else {
+                    util_debug("GEN", "        DONE  {0x00000,0x00000,0x00000}\n");
+                    break;
+                }
                 j++;
             }
         }
index 0852b5015f50711b8e22afd711de27cf5784432c..f3f0506310fe6fd95a7889c51f550ce607ba3940 100644 (file)
@@ -89,13 +89,22 @@ FUNCTION: checkextension, $99
 ;code_chars_put("m_toggle",      0x8);
 ;code_chars_put("m_shutdown",    0xA);
 
-FUNCTION: m_init     #3VVV    
-       DONE
-FUNCTION: m_keydown  #1S
-       DONE
-FUNCTION: m_draw     #1S
-       DONE
+FUNCTION: m_init     #0
+       CALL0 dprint
+END
+
+FUNCTION: m_keydown  #0
+       CALL0 dprint 
+END
+
+FUNCTION: m_draw     #3VVV
+       CALL0 dprint 
+END
+
 FUNCTION: m_toggle   #1S
-       DONE
-FUNCTION: m_shutdown #1S
+       CALL0 dprint 
+END
 
+FUNCTION: m_shutdown #1S
+       CALL0 dprint 
+END
diff --git a/gmqcc.h b/gmqcc.h
index 032566a07e26018d4b90ebc650495409d07f0afc..f8bb93e2cee725a86ee204e5af6a201474f6f73b 100644 (file)
--- a/gmqcc.h
+++ b/gmqcc.h
@@ -492,7 +492,15 @@ enum {
     INSTR_BITAND,
     INSTR_BITOR,
 
-    /* Virtual instructions used by the IR
+    /*
+     * Virtual instructions used by the assembler
+     * keep at the end but before virtual instructions
+     * for the IR below.
+     */
+    AINSTR_END,
+
+    /*
+     * Virtual instructions used by the IR
      * Keep at the end!
      */
     VINSTR_PHI,
@@ -585,21 +593,22 @@ static const struct {
     { "NOT_FNC"   , 0, 7 },
     { "IF"        , 0, 2 },
     { "IFNOT"     , 0, 5 },
-    { "CALL0"     , 0, 5 },
-    { "CALL1"     , 0, 5 },
-    { "CALL2"     , 0, 5 },
-    { "CALL3"     , 0, 5 },
-    { "CALL4"     , 0, 5 },
-    { "CALL5"     , 0, 5 },
-    { "CALL6"     , 0, 5 },
-    { "CALL7"     , 0, 5 },
-    { "CALL8"     , 0, 5 },
+    { "CALL0"     , 1, 5 },
+    { "CALL1"     , 2, 5 },
+    { "CALL2"     , 3, 5 },
+    { "CALL3"     , 4, 5 },
+    { "CALL4"     , 5, 5 },
+    { "CALL5"     , 6, 5 },
+    { "CALL6"     , 7, 5 },
+    { "CALL7"     , 8, 5 },
+    { "CALL8"     , 9, 5 },
     { "STATE"     , 0, 5 },
     { "GOTO"      , 0, 4 },
     { "AND"       , 0, 3 },
     { "OR"        , 0, 2 },
     { "BITAND"    , 0, 6 },
-    { "BITOR"     , 0, 5 }
+    { "BITOR"     , 0, 5 },
+    { "END"       , 0, 3 } /* virtual assembler instruction */
 };
 
 void asm_init (const char *, FILE **);
diff --git a/util.c b/util.c
index 7735a52457dba0e8a12b45ab1bf2013273b7f1f9..123974cdf2aacea9824e5da7af8d45d3e76b8835 100644 (file)
--- a/util.c
+++ b/util.c
@@ -137,39 +137,6 @@ char *util_strchp(const char *s, const char *e) {
     return util_strdup(s);
 }
 
-/*
- * Remove newline from a string (if it exists).  This is
- * done pointer wise instead of strlen(), and an array
- * access.
- */
-char *util_strrnl(const char *src) {
-    char   *cpy = NULL;
-
-    if (src) {
-        cpy = (char*)src;
-        while (*cpy && *cpy != '\n')
-            cpy++;
-
-        *cpy = '\0';
-    }
-    return (char*)src;
-}
-
-/*
- * Removes any whitespace prefixed on a string by moving
- * skipping past it, and stroing the skip distance, so
- * the string can later be freed (if it was allocated)
- */
-char *util_strsws(const char *skip) {
-    size_t size = 0;
-    if (!skip)
-        return NULL;
-
-    while (*skip == ' ' || *skip == '\t')
-        skip++,size++;
-    return util_strdup(skip-size);
-}
-
 /*
  * Returns true if string is all uppercase, otherwise
  * it returns false.