]> git.unchartedbackwaters.co.uk Git - francis/libjit.git/commitdiff
Get basic compilation working in Dynamic Pascal.
authorRhys Weatherley <rweather@southern-storm.com.au>
Thu, 6 May 2004 11:09:37 +0000 (11:09 +0000)
committerRhys Weatherley <rweather@southern-storm.com.au>
Thu, 6 May 2004 11:09:37 +0000 (11:09 +0000)
27 files changed:
ChangeLog
dpas/Makefile.am
dpas/dpas-builtin.c [new file with mode: 0644]
dpas/dpas-function.c
dpas/dpas-internal.h
dpas/dpas-main.c
dpas/dpas-parser.y
dpas/dpas-scope.c
dpas/dpas-scope.h
dpas/dpas-semantics.h
dpas/dpas-types.c
dpas/dpas-types.h
include/jit/jit-block.h
include/jit/jit-insn.h
include/jit/jit-plus.h
jit/jit-block.c
jit/jit-dump.c
jit/jit-function.c
jit/jit-insn.c
jit/jit-interp.cpp
jit/jit-opcode.c
jit/jit-rules-arm.c
jit/jit-rules-interp.c
jit/jit-rules-x86.c
jit/jit-type.c
jit/jit-value.c
jitplus/jit-plus-function.cpp

index 4d1035fd3eae81dfe0340b42be4544b833867acc..723c49589511cec784fb60e9fc73c5951309ef1d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,17 @@
 
+2004-05-06  Rhys Weatherley  <rweather@southern-storm.com.au>
+
+       * dpas/Makefile.am, dpas/dpas-builtin.c, dpas/dpas-function.c,
+       dpas/dpas-internal.h, dpas/dpas-main.c, dpas/dpas-parser.y,
+       dpas/dpas-scope.c, dpas/dpas-scope.h, dpas/dpas-semantics.h,
+       dpas/dpas-types.c, dpas/dpas-types.h, include/jit/jit-block.h,
+       include/jit/jit-insn.h, include/jit/jit-plus.h, jit/jit-block.c,
+       jit/jit-dump.c, jit/jit-function.c, jit/jit-insn.c, jit/jit-interp.cpp,
+       jit/jit-opcode.c, jit/jit-rules-arm.c, jit/jit-rules-interp.c,
+       jit/jit-rules-x86.c, jit/jit-type.c, jit/jit-value.c,
+       jitplus/jit-plus-function.cpp: get basic compilation working
+       in Dynamic Pascal.
+
 2004-05-03  Rhys Weatherley  <rweather@southern-storm.com.au>
 
        * tools/gen-apply.c: improve the maintainability of the apply macros.
index c405af3caae67ed0cdb6feac25a6c32c71dcb99e..a379b4198afdd6df537306a0af6b66e12c21a921 100644 (file)
@@ -4,6 +4,7 @@ noinst_PROGRAMS = dpas
 dpas_SOURCES = \
        dpas-internal.h \
        dpas-main.c \
+       dpas-builtin.c \
        dpas-function.c \
        dpas-parser.y \
        dpas-scanner.l \
diff --git a/dpas/dpas-builtin.c b/dpas/dpas-builtin.c
new file mode 100644 (file)
index 0000000..0af678b
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * dpas-builtin.c - Handling for Dynamic Pascal builtins.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "dpas-internal.h"
+#include <stdio.h>
+
+/*
+ * Functions for writing values to stdout.
+ */
+static void dpas_write_ln(void)
+{
+       putc('\n', stdout);
+}
+static void dpas_write_int(jit_int value)
+{
+       printf("%ld", (long)value);
+}
+static void dpas_write_uint(jit_uint value)
+{
+       printf("%lu", (unsigned long)value);
+}
+static void dpas_write_long(jit_long value)
+{
+       jit_constant_t val;
+       char *name;
+       val.type = jit_type_long;
+       val.un.long_value = value;
+       name = dpas_constant_name(&val);
+       fputs(name, stdout);
+       jit_free(name);
+}
+static void dpas_write_ulong(jit_ulong value)
+{
+       jit_constant_t val;
+       char *name;
+       val.type = jit_type_ulong;
+       val.un.ulong_value = value;
+       name = dpas_constant_name(&val);
+       fputs(name, stdout);
+       jit_free(name);
+}
+static void dpas_write_nfloat(jit_nfloat value)
+{
+       printf("%g", (double)value);
+}
+static void dpas_write_string(char *value)
+{
+       if(value)
+       {
+               fputs(value, stdout);
+       }
+       else
+       {
+               fputs("(null)", stdout);
+       }
+}
+
+/*
+ * Call a native "write" function.
+ */
+static void call_write(jit_function_t func, const char *name,
+                                          void *native_func, jit_type_t arg_type,
+                                          jit_value_t value)
+{
+       jit_type_t signature;
+       jit_value_t args[1];
+       int num_args = 0;
+       if(arg_type)
+       {
+               args[0] = jit_insn_convert(func, value, arg_type, 0);
+               if(!(args[0]))
+               {
+                       dpas_out_of_memory();
+               }
+               num_args = 1;
+               signature = jit_type_create_signature
+                       (jit_abi_cdecl, jit_type_void, &arg_type, 1, 1);
+       }
+       else
+       {
+               num_args = 0;
+               signature = jit_type_create_signature
+                       (jit_abi_cdecl, jit_type_void, 0, 0, 1);
+       }
+       if(!signature)
+       {
+               dpas_out_of_memory();
+       }
+       if(!jit_insn_call_native(func, name, native_func, signature,
+                                                        args, num_args, JIT_CALL_NOTHROW))
+       {
+               dpas_out_of_memory();
+       }
+       jit_type_free(signature);
+}
+
+/*
+ * Write values to "stdout".
+ */
+static dpas_semvalue dpas_write_inner
+       (dpas_semvalue *args, int num_args, int newline)
+{
+       jit_function_t func = dpas_current_function();
+       dpas_semvalue result;
+       jit_type_t type;
+       const char *name;
+       void *native_func;
+       int index;
+       for(index = 0; index < num_args; ++index)
+       {
+               result = dpas_lvalue_to_rvalue(args[index]);
+               if(!dpas_sem_is_rvalue(result))
+               {
+                       dpas_error("invalid value for parameter %d", index + 1);
+               }
+               else
+               {
+                       type = jit_type_normalize(dpas_sem_get_type(result));
+                       if(type == jit_type_sbyte ||
+                          type == jit_type_ubyte ||
+                          type == jit_type_short ||
+                          type == jit_type_ushort ||
+                          type == jit_type_int)
+                       {
+                               type = jit_type_int;
+                               name = "dpas_write_int";
+                               native_func = (void *)dpas_write_int;
+                       }
+                       else if(type == jit_type_uint)
+                       {
+                               type = jit_type_uint;
+                               name = "dpas_write_uint";
+                               native_func = (void *)dpas_write_uint;
+                       }
+                       else if(type == jit_type_long)
+                       {
+                               type = jit_type_long;
+                               name = "dpas_write_long";
+                               native_func = (void *)dpas_write_long;
+                       }
+                       else if(type == jit_type_ulong)
+                       {
+                               type = jit_type_ulong;
+                               name = "dpas_write_ulong";
+                               native_func = (void *)dpas_write_ulong;
+                       }
+                       else if(type == jit_type_float32 ||
+                                       type == jit_type_float64 ||
+                                       type == jit_type_nfloat)
+                       {
+                               type = jit_type_nfloat;
+                               name = "dpas_write_nfloat";
+                               native_func = (void *)dpas_write_nfloat;
+                       }
+                       else if(jit_type_is_pointer(type) &&
+                                       jit_type_get_ref(type) == dpas_type_char)
+                       {
+                               type = jit_type_void_ptr;
+                               name = "dpas_write_string";
+                               native_func = (void *)dpas_write_string;
+                       }
+                       else
+                       {
+                               dpas_error("unprintable value for parameter %d", index + 1);
+                               continue;
+                       }
+                       call_write(func, name, native_func, type,
+                                          dpas_sem_get_value(result));
+               }
+       }
+       if(newline)
+       {
+               call_write(func, "dpas_write_nl", (void *)dpas_write_ln, 0, 0);
+       }
+       dpas_sem_set_void(result);
+       return result;
+}
+static dpas_semvalue dpas_write(dpas_semvalue *args, int num_args)
+{
+       return dpas_write_inner(args, num_args, 0);
+}
+
+/*
+ * Write values to "stdout", followed by a newline.
+ */
+static dpas_semvalue dpas_writeln(dpas_semvalue *args, int num_args)
+{
+       return dpas_write_inner(args, num_args, 1);
+}
+
+/*
+ * Builtins that we currently recognize.
+ */
+#define        DPAS_BUILTIN_WRITE                      1
+#define        DPAS_BUILTIN_WRITELN            2
+
+/*
+ * Table that defines the builtins.
+ */
+typedef struct
+{
+       const char         *name;
+       int                             identifier;
+       dpas_semvalue   (*func)(dpas_semvalue *args, int num_args);
+       int                             num_args;       /* -1 for a vararg function */
+
+} dpas_builtin;
+static dpas_builtin const builtins[] = {
+       {"Write",               DPAS_BUILTIN_WRITE,             dpas_write,             -1},
+       {"WriteLn",             DPAS_BUILTIN_WRITELN,   dpas_writeln,   -1},
+};
+#define        num_builtins    (sizeof(builtins) / sizeof(dpas_builtin))
+
+int dpas_is_builtin(const char *name)
+{
+       int index;
+       for(index = 0; index < num_builtins; ++index)
+       {
+               if(!jit_stricmp(name, builtins[index].name))
+               {
+                       return builtins[index].identifier;
+               }
+       }
+       return 0;
+}
+
+dpas_semvalue dpas_expand_builtin
+       (int identifier, dpas_semvalue *args, int num_args)
+{
+       int index;
+       dpas_semvalue value;
+       for(index = 0; index < num_builtins; ++index)
+       {
+               if(builtins[index].identifier == identifier)
+               {
+                       if(builtins[index].num_args != -1 &&
+                          builtins[index].num_args != num_args)
+                       {
+                               dpas_error("incorrect number of arguments to `%s' builtin",
+                                                  builtins[index].name);
+                               dpas_sem_set_error(value);
+                               return value;
+                       }
+                       return (*(builtins[index].func))(args, num_args);
+               }
+       }
+       dpas_sem_set_error(value);
+       return value;
+}
index 98511d3ce34d4af82de3c65278482a5a9d4fc70e..73f35772eb010c977e23b665d544e1e72e2ee537 100644 (file)
@@ -86,3 +86,20 @@ int dpas_function_is_nested(void)
 {
        return (function_stack_size > 1);
 }
+
+dpas_semvalue dpas_lvalue_to_rvalue(dpas_semvalue value)
+{
+       if(dpas_sem_is_lvalue_ea(value))
+       {
+               jit_type_t type = dpas_sem_get_type(value);
+               jit_value_t rvalue = dpas_sem_get_value(value);
+               rvalue = jit_insn_load_relative
+                       (dpas_current_function(), rvalue, 0, type);
+               if(!rvalue)
+               {
+                       dpas_out_of_memory();
+               }
+               dpas_sem_set_rvalue(value, type, rvalue);
+       }
+       return value;
+}
index db7bc1b8d9d32f156f050b28504055daac0dcfcc..c2e4757caafeed4fd73a02b3b80ec54a340b822e 100644 (file)
@@ -38,6 +38,11 @@ extern       "C" {
 extern char *dpas_filename;
 extern long dpas_linenum;
 
+/*
+ * Flag that indicates that functions should be dumped as they are compiled.
+ */
+extern int dpas_dump_functions;
+
 /*
  * Information about a parameter list (also used for record fields).
  */
@@ -114,6 +119,18 @@ void dpas_pop_function(void);
  */
 int dpas_function_is_nested(void);
 
+/*
+ * Determine if a name corresponds to a builtin function,
+ * and get its builtin identifier.  Returns zero if not a builtin.
+ */
+int dpas_is_builtin(const char *name);
+
+/*
+ * Expand a builtin function reference.
+ */
+dpas_semvalue dpas_expand_builtin
+       (int identifier, dpas_semvalue *args, int num_args);
+
 #ifdef __cplusplus
 };
 #endif
index b0d8c2f33dd1446d5ae36c3c9c32e19e1c2dc93e..f10f495bcb3f43a093108506149aaa205ff17c84 100644 (file)
@@ -73,6 +73,14 @@ int main(int argc, char **argv)
                {
                        version();
                }
+               else if(!jit_strcmp(argv[1], "-d"))
+               {
+                       dpas_dump_functions = 1;
+               }
+               else if(!jit_strcmp(argv[1], "-D"))
+               {
+                       dpas_dump_functions = 2;
+               }
                else
                {
                        usage();
index 2b3c5131ccfd9db13c2b217af117bcd933dcc5e9..98837b2debf54ee2ade2c648eb43e007d39b263f 100644 (file)
@@ -46,6 +46,11 @@ extern char yytext[];
  */
 int dpas_error_reported = 0;
 
+/*
+ * Function dumping flag.
+ */
+int dpas_dump_functions = 0;
+
 /*
  * Report error messages from the parser.
  */
@@ -443,6 +448,149 @@ static void parameter_list_merge(dpas_params *list1, dpas_params *list2)
        jit_free(list2->types);
 }
 
+/*
+ * Add an item to an expression list.
+ */
+static void expression_list_add
+       (dpas_semvalue **list, int *len, dpas_semvalue value)
+{
+       dpas_semvalue *new_list = (dpas_semvalue *)
+               jit_realloc(*list, sizeof(dpas_semvalue) * (*len + 1));
+       if(!new_list)
+       {
+               dpas_out_of_memory();
+       }
+       new_list[*len] = value;
+       ++(*len);
+       *list = new_list;
+}
+
+/*
+ * Free an expression list.
+ */
+static void expression_list_free(dpas_semvalue *list, int len)
+{
+       jit_free(list);
+}
+
+/*
+ * Invoke a procedure or function.
+ */
+static dpas_semvalue invoke_procedure
+       (jit_function_t func_value, const char *name, jit_type_t signature,
+        jit_value_t indirect_value, dpas_semvalue *args, int num_args)
+{
+       jit_function_t func = dpas_current_function();
+       dpas_semvalue rvalue;
+       jit_type_t type;
+       jit_value_t return_value;
+       jit_value_t *value_args;
+       jit_type_t param_type;
+       jit_type_t var_type;
+       unsigned int param;
+       int error;
+
+       /* Validate the parameters (TODO: vararg function calls) */
+       if(num_args != (int)jit_type_num_params(signature))
+       {
+               dpas_error("incorrect number of parameters to procedure or function");
+               dpas_sem_set_error(rvalue);
+               return rvalue;
+       }
+       error = 0;
+       if(num_args > 0)
+       {
+               value_args = (jit_value_t *)jit_malloc(sizeof(jit_value_t) * num_args);
+               if(!value_args)
+               {
+                       dpas_out_of_memory();
+               }
+               for(param = 0; param < (unsigned int)num_args; ++param)
+               {
+                       param_type = jit_type_get_param(signature, param);
+                       var_type = dpas_type_is_var(param_type);
+                       if(var_type)
+                       {
+                               /* TODO: type checking */
+                               if(dpas_sem_is_lvalue_ea(args[param]))
+                               {
+                                       value_args[param] = dpas_sem_get_value(args[param]);
+                               }
+                               else if(dpas_sem_is_lvalue(args[param]))
+                               {
+                                       value_args[param] = jit_insn_address_of
+                                               (func, dpas_sem_get_value(args[param]));
+                                       if(!(value_args[param]))
+                                       {
+                                               dpas_out_of_memory();
+                                       }
+                               }
+                               else
+                               {
+                                       dpas_error("invalid value for parameter %d",
+                                                          (int)(param + 1));
+                                       error = 1;
+                               }
+                       }
+                       else
+                       {
+                               /* TODO: type checking and EA l-values */
+                               if(dpas_sem_is_rvalue(args[param]))
+                               {
+                                       value_args[param] = dpas_sem_get_value(args[param]);
+                               }
+                               else
+                               {
+                                       dpas_error("invalid value for parameter %d",
+                                                          (int)(param + 1));
+                                       error = 1;
+                               }
+                       }
+               }
+       }
+       else
+       {
+               value_args = 0;
+       }
+       if(error)
+       {
+               jit_free(value_args);
+               dpas_sem_set_error(rvalue);
+               return rvalue;
+       }
+
+       /* Call the specified procedure or function */
+       if(func_value)
+       {
+               return_value = jit_insn_call
+                       (func, name, func_value, signature,
+                        value_args, (unsigned int)num_args, 0);
+       }
+       else
+       {
+               return_value = jit_insn_call_indirect
+                       (func, indirect_value, signature,
+                        value_args, (unsigned int)num_args, 0);
+       }
+       if(!return_value)
+       {
+               dpas_out_of_memory();
+       }
+       jit_free(value_args);
+
+       /* Construct a semantic value object for the return value */
+       type = jit_type_get_return(signature);
+       if(type == jit_type_void)
+       {
+               dpas_sem_set_void(rvalue);
+       }
+       else
+       {
+               dpas_sem_set_rvalue(rvalue, type, return_value);
+       }
+       return rvalue;
+}
+
 /*
  * Handle a numeric binary operator.
  */
@@ -523,6 +671,72 @@ static void parameter_list_merge(dpas_params *list1, dpas_params *list2)
                        } \
                } while (0)
 
+/*
+ * Definition of the loop stack.
+ */
+typedef struct
+{
+       jit_label_t             expr_label;
+       jit_label_t             top_label;
+       jit_label_t             exit_label;
+
+} dpas_loop_info;
+static dpas_loop_info *loop_stack = 0;
+static int loop_stack_size = 0;
+static int loop_stack_max = 0;
+
+/*
+ * Push an entry onto the loop stack.
+ */
+static void push_loop
+       (jit_label_t expr_label, jit_label_t top_label, jit_label_t exit_label)
+{
+       dpas_loop_info *new_stack;
+       if(loop_stack_size >= loop_stack_max)
+       {
+               new_stack = (dpas_loop_info *)jit_realloc
+                       (loop_stack, sizeof(dpas_loop_info) * (loop_stack_size + 1));
+               if(!new_stack)
+               {
+                       dpas_out_of_memory();
+               }
+               loop_stack = new_stack;
+               ++loop_stack_max;
+       }
+       loop_stack[loop_stack_size].expr_label = expr_label;
+       loop_stack[loop_stack_size].top_label = top_label;
+       loop_stack[loop_stack_size].exit_label = exit_label;
+       ++loop_stack_size;
+}
+
+/*
+ * Definition of the "if" stack.
+ */
+static jit_label_t *if_stack = 0;
+static int if_stack_size = 0;
+static int if_stack_max = 0;
+
+/*
+ * Push an entry onto the loop stack.
+ */
+static void push_if(jit_label_t end_label)
+{
+       jit_label_t *new_stack;
+       if(if_stack_size >= if_stack_max)
+       {
+               new_stack = (jit_label_t *)jit_realloc
+                       (if_stack, sizeof(jit_label_t) * (if_stack_size + 1));
+               if(!new_stack)
+               {
+                       dpas_out_of_memory();
+               }
+               if_stack = new_stack;
+               ++if_stack_max;
+       }
+       if_stack[if_stack_size] = end_label;
+       ++if_stack_size;
+}
+
 %}
 
 /*
@@ -560,6 +774,11 @@ static void parameter_list_merge(dpas_params *list1, dpas_params *list2)
                dpas_params     bounds;
        }                               param_type;
        dpas_semvalue   semvalue;
+       struct
+       {
+               dpas_semvalue *exprs;
+               int                     len;
+       }                               expr_list;
 }
 
 /*
@@ -656,6 +875,9 @@ static void parameter_list_merge(dpas_params *list1, dpas_params *list2)
 
 %type <semvalue>                       Variable Expression SimpleExpression
 %type <semvalue>                       AdditionExpression Term Factor Power
+%type <semvalue>                       BooleanExpression
+
+%type <expr_list>                      ExpressionList ActualParameters
 
 %expect 3
 
@@ -717,9 +939,23 @@ ProgramBlock
                                        dpas_out_of_memory();
                                }
 
-                               /* Compile the function */
-                               /* TODO */
-                               jit_dump_function(stdout, func, "main");
+                               /* Dump the before-compile state of the function */
+                               if(dpas_dump_functions)
+                               {
+                                       jit_dump_function(stdout, func, "main");
+                               }
+
+                               /* Compile the procedure/function */
+                               if(!jit_function_compile(func))
+                               {
+                                       dpas_out_of_memory();
+                               }
+
+                               /* Dump the after-compile state of the function */
+                               if(dpas_dump_functions > 1)
+                               {
+                                       jit_dump_function(stdout, func, "main");
+                               }
 
                                /* Pop the "main" function */
                                dpas_pop_function();
@@ -963,17 +1199,23 @@ ProcedureOrFunctionDeclaration
                                if(item)
                                {
                                        dpas_redeclared($1.name, item);
+                                       item = 0;
                                }
                                else
                                {
                                        dpas_scope_add(dpas_scope_current(), $1.name, $1.type,
                                                                   DPAS_ITEM_PROCEDURE, 0, 0,
                                                                   dpas_filename, dpas_linenum);
+                                       item = dpas_scope_lookup(dpas_scope_current(), $1.name, 0);
                                }
 
                                /* Push into a new scope for the procedure/function body */
                                dpas_scope_push();
                                func = dpas_new_function($1.type);
+                               if(item)
+                               {
+                                       dpas_scope_item_set_info(item, func);
+                               }
 
                                /* Declare the parameters into the scope.  If a name
                                   is NULL, then it indicates that a duplicate parameter
@@ -1006,12 +1248,6 @@ ProcedureOrFunctionDeclaration
                                                dpas_error("`%s' is declared as both a parameter "
                                                                   "and a function name", $1.name);
                                        }
-                                       else
-                                       {
-                                               dpas_scope_add(dpas_scope_current(), $1.name, type,
-                                                                          DPAS_ITEM_FUNC_RETURN, 0, 0,
-                                                                          dpas_filename, dpas_linenum);
-                                       }
                                }
                        } Body {
                                jit_function_t func = dpas_current_function();
@@ -1033,9 +1269,23 @@ ProcedureOrFunctionDeclaration
                                dpas_pop_function();
                                dpas_scope_pop();
 
-                               /* TODO: compile the procedure/function */
+                               /* Dump the before-compile state of the function */
+                               if(dpas_dump_functions)
+                               {
+                                       jit_dump_function(stdout, func, $1.name);
+                               }
+
+                               /* Compile the procedure/function */
+                               if(!jit_function_compile(func))
+                               {
+                                       dpas_out_of_memory();
+                               }
 
-                               jit_dump_function(stdout, func, $1.name);
+                               /* Dump the after-compile state of the function */
+                               if(dpas_dump_functions > 1)
+                               {
+                                       jit_dump_function(stdout, func, $1.name);
+                               }
 
                                /* Free values that we no longer require */
                                jit_free($1.name);
@@ -1237,36 +1487,240 @@ Statement
 
 InnerStatement
        : Variable K_ASSIGN Expression                  {
-                               /* TODO: type checking and non-local variables */
-                               if(dpas_sem_is_lvalue($1) && dpas_sem_is_rvalue($3))
+                               jit_type_t ltype;
+                               jit_type_t rtype;
+                               jit_value_t dest;
+                               jit_value_t value;
+
+                               /* Convert variable references to the current function
+                                  into function return semantic values */
+                               if(dpas_sem_is_procedure($1) &&
+                                  ((jit_function_t)dpas_scope_item_info
+                                                       (dpas_sem_get_procedure($1))) ==
+                                               dpas_current_function())
                                {
-                                       if(!jit_insn_store(dpas_current_function(),
-                                                                          dpas_sem_get_value($1),
-                                                                          dpas_sem_get_value($3)))
+                                       dpas_sem_set_return
+                                               ($1, jit_type_get_return(dpas_sem_get_type($1)));
+                               }
+
+                               /* Validate the l-value expression */
+                               if(!dpas_sem_is_lvalue($1) && !dpas_sem_is_lvalue_ea($1) &&
+                                  !dpas_sem_is_return($1))
+                               {
+                                       if(!dpas_sem_is_error($1))
                                        {
-                                               dpas_out_of_memory();
+                                               dpas_error("invalid l-value in assignment statement");
+                                       }
+                                       ltype = jit_type_void;
+                               }
+                               else
+                               {
+                                       ltype = dpas_sem_get_type($1);
+                               }
+
+                               /* Validate the r-value expression */
+                               if(!dpas_sem_is_rvalue($3))
+                               {
+                                       if(!dpas_sem_is_error($3))
+                                       {
+                                               dpas_error("invalid r-value in assignment statement");
+                                       }
+                                       rtype = jit_type_void;
+                               }
+                               else
+                               {
+                                       rtype = dpas_sem_get_type($3);
+                               }
+
+                               /* Type-check the source against the destination */
+                               /* TODO */
+                               value = dpas_sem_get_value($3);
+
+                               /* Determine the kind of assignment we should perform */
+                               if(dpas_sem_is_return($1) && rtype != jit_type_void)
+                               {
+                                       /* We are returning a value from this function */
+                                       if(dpas_sem_is_lvalue_ea($3))
+                                       {
+                                               if(!jit_insn_return_ptr
+                                                               (dpas_current_function(), value, ltype))
+                                               {
+                                                       dpas_out_of_memory();
+                                               }
+                                       }
+                                       else
+                                       {
+                                               if(!jit_insn_return
+                                                               (dpas_current_function(), value))
+                                               {
+                                                       dpas_out_of_memory();
+                                               }
+                                       }
+                               }
+                               else if(dpas_sem_is_lvalue_ea($1) && rtype != jit_type_void)
+                               {
+                                       /* The destination is specified as an effective address */
+                                       dest = dpas_sem_get_value($1);
+                                       if(dpas_type_is_record(ltype))
+                                       {
+                                               /* We need an effective address for the source */
+                                               if(!dpas_sem_is_lvalue_ea($3))
+                                               {
+                                                       value = jit_insn_address_of
+                                                               (dpas_current_function(), value);
+                                                       if(!value)
+                                                       {
+                                                               dpas_out_of_memory();
+                                                       }
+                                               }
+                                               if(!jit_insn_memcpy
+                                                       (dpas_current_function(), dest, value,
+                                                        jit_value_create_nint_constant
+                                                               (dpas_current_function(), jit_type_nint,
+                                                                (jit_nint)jit_type_get_size(rtype))))
+                                               {
+                                                       dpas_out_of_memory();
+                                               }
+                                       }
+                                       else
+                                       {
+                                               /* Don't use an effective address for the source */
+                                               if(dpas_sem_is_lvalue_ea($3))
+                                               {
+                                                       value = jit_insn_load_relative
+                                                               (dpas_current_function(), value, 0, rtype);
+                                                       if(!value)
+                                                       {
+                                                               dpas_out_of_memory();
+                                                       }
+                                               }
+                                               if(!jit_insn_store_relative
+                                                       (dpas_current_function(), dest, 0, value))
+                                               {
+                                                       dpas_out_of_memory();
+                                               }
                                        }
                                }
+                               else if(dpas_sem_is_lvalue($1) && rtype != jit_type_void)
+                               {
+                                       /* The destination is specified as a local value */
+                                       dest = dpas_sem_get_value($1);
+                                       if(dpas_type_is_record(ltype))
+                                       {
+                                               /* We need effective addresses for both */
+                                               if(!dpas_sem_is_lvalue_ea($1))
+                                               {
+                                                       dest = jit_insn_address_of
+                                                               (dpas_current_function(), dest);
+                                                       if(!dest)
+                                                       {
+                                                               dpas_out_of_memory();
+                                                       }
+                                               }
+                                               if(!dpas_sem_is_lvalue_ea($3))
+                                               {
+                                                       value = jit_insn_address_of
+                                                               (dpas_current_function(), value);
+                                                       if(!value)
+                                                       {
+                                                               dpas_out_of_memory();
+                                                       }
+                                               }
+                                               if(!jit_insn_memcpy
+                                                       (dpas_current_function(), dest, value,
+                                                        jit_value_create_nint_constant
+                                                               (dpas_current_function(), jit_type_nint,
+                                                                (jit_nint)jit_type_get_size(rtype))))
+                                               {
+                                                       dpas_out_of_memory();
+                                               }
+                                       }
+                                       else
+                                       {
+                                               /* Don't use an effective address for the source */
+                                               if(dpas_sem_is_lvalue_ea($3))
+                                               {
+                                                       value = jit_insn_load_relative
+                                                               (dpas_current_function(), value, 0, rtype);
+                                                       if(!value)
+                                                       {
+                                                               dpas_out_of_memory();
+                                                       }
+                                               }
+                                               if(!jit_insn_store
+                                                       (dpas_current_function(), dest, value))
+                                               {
+                                                       dpas_out_of_memory();
+                                               }
+                                       }
+                               }
+                       }
+       | Variable ActualParameters             {
+                               /* Call a procedure or an ignored-result function */
+                               if(dpas_sem_is_builtin($1))
+                               {
+                                       /* Expand a call to a builtin procedure */
+                                       dpas_expand_builtin
+                                               (dpas_sem_get_builtin($1), $2.exprs, $2.len);
+                               }
+                               else if(dpas_sem_is_procedure($1))
+                               {
+                                       /* Invoke a user-defined procedure */
+                                       dpas_scope_item_t item = dpas_sem_get_procedure($1);
+                                       invoke_procedure
+                                               ((jit_function_t)dpas_scope_item_info(item),
+                                                dpas_scope_item_name(item),
+                                                dpas_scope_item_type(item), 0, $2.exprs, $2.len);
+                               }
+                               else if(dpas_sem_is_rvalue($1) &&
+                                               jit_type_is_signature(dpas_sem_get_type($1)))
+                               {
+                                       /* Invoke a procedure via an indirect pointer */
+                                       invoke_procedure
+                                               (0, 0, dpas_sem_get_type($1), dpas_sem_get_value($1),
+                                                $2.exprs, $2.len);
+                               }
                                else
                                {
-                                       dpas_error("invalid assignment");
+                                       if(!dpas_sem_is_error($1))
+                                       {
+                                               dpas_error("invalid function or procedure name");
+                                       }
                                }
+                               expression_list_free($2.exprs, $2.len);
                        }
-       | Identifier                                                    {}
-       | Identifier '(' ExpressionList ')'             {}
        | K_GOTO Label
        | CompoundStatement
-       | K_WHILE Expression K_DO Statement
-       | K_REPEAT StatementSequence OptSemi K_UNTIL Expression
+       | IfStatement
+       | WhileStatement
+       | RepeatStatement
        | K_FOR Identifier K_ASSIGN Expression Direction Expression K_DO Statement
-       | K_IF Expression K_THEN Statement
-       | K_IF Expression K_THEN Statement K_ELSE Statement
        | CaseStatement
        | K_WITH VariableList K_DO Statement
        | K_THROW Expression
        | K_THROW
        | TryStatement
-       | K_EXIT
+       | K_EXIT                {
+                               /* Exit from the current loop level */
+                               if(loop_stack_size > 0)
+                               {
+                                       if(!jit_insn_branch
+                                               (dpas_current_function(),
+                                                &(loop_stack[loop_stack_size - 1].exit_label)))
+                                       {
+                                               dpas_out_of_memory();
+                                       }
+                               }
+                               else
+                               {
+                                       dpas_error("`exit' used outside loop");
+                               }
+                       }
+       ;
+
+ActualParameters
+       : /* empty */                           { $$.exprs = 0; $$.len = 0; }
+       | '(' ExpressionList ')'        { $$ = $2; }
        ;
 
 CompoundStatement
@@ -1274,6 +1728,175 @@ CompoundStatement
        | K_BEGIN error K_END
        ;
 
+IfStatement
+       : K_IF BooleanExpression K_THEN         {
+                               jit_label_t label = jit_label_undefined;
+
+                               /* Check the condition and jump if false */
+                               if(!jit_insn_branch_if_not
+                                               (dpas_current_function(),
+                                                dpas_sem_get_value($2), &label))
+                               {
+                                       dpas_out_of_memory();
+                               }
+
+                               /* Push into an "if" context, to remember the label */
+                               push_if(label);
+
+                       } IfTail                        {
+
+                               /* Set the final label at the end of the "if" */
+                               if(if_stack[if_stack_size - 1] != jit_label_undefined)
+                               {
+                                       if(!jit_insn_label
+                                                       (dpas_current_function(),
+                                                        &(if_stack[if_stack_size - 1])))
+                                       {
+                                               dpas_out_of_memory();
+                                       }
+                               }
+                               --if_stack_size;
+                       }
+       ;
+
+IfTail
+       : Statement
+       | Statement K_ELSE              {
+                               jit_label_t label = jit_label_undefined;
+
+                               /* Jump to the end of the "if" statement */
+                               if(jit_block_ends_in_dead
+                                               (jit_block_previous(dpas_current_function(), 0)))
+                               {
+                                       if(!jit_insn_branch(dpas_current_function(), &label))
+                                       {
+                                               dpas_out_of_memory();
+                                       }
+                               }
+
+                               /* Set the position of the "else" clause */
+                               if(!jit_insn_label
+                                               (dpas_current_function(),
+                                                &(if_stack[if_stack_size - 1])))
+                               {
+                                       dpas_out_of_memory();
+                               }
+
+                               /* Replace the end point of the "if" */
+                               if_stack[if_stack_size - 1] = label;
+
+                       } Statement
+       ;
+
+WhileStatement
+       : K_WHILE                                       {
+                               jit_label_t label = jit_label_undefined;
+
+                               /* Jump to the beginning of the expression block.
+                                  Right now, the expression block is at the head
+                                  of the loop body.  Once we've process the entire
+                                  body, we will move the expression block to the end */
+                               if(!jit_insn_branch(dpas_current_function(), &label))
+                               {
+                                       dpas_out_of_memory();
+                               }
+
+                               /* Mark the start of the expression block */
+                               if(!jit_insn_label(dpas_current_function(), &label))
+                               {
+                                       dpas_out_of_memory();
+                               }
+
+                               /* Push the label onto the loop stack */
+                               push_loop(label, jit_label_undefined, jit_label_undefined);
+
+                       } BooleanExpression K_DO        {
+                               /* Test the expression and jump to the top of the body */
+                               if(!dpas_sem_is_error($3))
+                               {
+                                       if(!jit_insn_branch_if
+                                                       (dpas_current_function(),
+                                                        dpas_sem_get_value($3),
+                                                        &(loop_stack[loop_stack_size - 1].top_label)))
+                                       {
+                                               dpas_out_of_memory();
+                                       }
+                               }
+
+                               /* Mark the end of the expression block and the start
+                                  of the while loop's body.  This is also the end
+                                  of the code we'll need to move to the end */
+                               if(!jit_insn_label
+                                               (dpas_current_function(),
+                                                &(loop_stack[loop_stack_size - 1].top_label)))
+                               {
+                                       dpas_out_of_memory();
+                               }
+                       } Statement                     {
+
+                               /* Move the expression blocks down to this point */
+                               jit_insn_move_blocks
+                                       (dpas_current_function(),
+                                        loop_stack[loop_stack_size - 1].expr_label,
+                                        loop_stack[loop_stack_size - 1].top_label);
+
+                               /* Define the "exit" label to this point in the code */
+                               if(!jit_insn_label
+                                               (dpas_current_function(),
+                                                &(loop_stack[loop_stack_size - 1].exit_label)))
+                               {
+                                       dpas_out_of_memory();
+                               }
+
+                               /* Pop the top-most entry from the loop stack */
+                               --loop_stack_size;
+                       }
+       ;
+
+RepeatStatement
+       : K_REPEAT                      {
+
+                               /* Define a label at the top of the loop body */
+                               jit_label_t label = jit_label_undefined;
+                               if(!jit_insn_label(dpas_current_function(), &label))
+                               {
+                                       dpas_out_of_memory();
+                               }
+
+                               /* Push into a new loop context */
+                               push_loop(jit_label_undefined, label, jit_label_undefined);
+
+                       } StatementSequence OptSemi K_UNTIL BooleanExpression {
+
+                               /* Branch back to the top of the loop */
+                               if(!jit_insn_branch_if_not
+                                               (dpas_current_function(),
+                                                dpas_sem_get_value($6),
+                                                &(loop_stack[loop_stack_size - 1].top_label)))
+                               {
+                                       dpas_out_of_memory();
+                               }
+
+                               /* Set the label for the "exit" point of the loop */
+                               if(!jit_insn_label
+                                               (dpas_current_function(),
+                                                &(loop_stack[loop_stack_size - 1].exit_label)))
+                               {
+                                       dpas_out_of_memory();
+                               }
+
+                               /* Pop out of the current loop context */
+                               --loop_stack_size;
+                       }
+       ;
+
+BooleanExpression
+       : Expression            {
+                               /* TODO: type checking */
+                               $$ = $1;
+                       }
+       ;
+
 Direction
        : K_TO
        | K_DOWNTO
@@ -1346,8 +1969,15 @@ Expression
        ;
 
 ExpressionList
-       : Expression                                            { /* TODO */ }
-       | ExpressionList ',' Expression         { /* TODO */ }
+       : Expression                                            {
+                               $$.exprs = 0;
+                               $$.len = 0;
+                               expression_list_add(&($$.exprs), &($$.len), $1);
+                       }
+       | ExpressionList ',' Expression         {
+                               $$ = $1;
+                               expression_list_add(&($$.exprs), &($$.len), $3);
+                       }
        ;
 
 SimpleExpression
@@ -1465,7 +2095,7 @@ AdditionExpression
 Term
        : Power                                                 { $$ = $1; }
        | Term '*' Power                                {
-                               handle_binary("*", jit_insn_div, $1, $3);
+                               handle_binary("*", jit_insn_mul, $1, $3);
                        }
        | Term '/' Power                                {
                                /* Standard Pascal always returns a floating-point
@@ -1562,7 +2192,13 @@ Power
        ;
 
 Factor
-       : Variable                                              { $$ = $1; }
+       : Variable                                              {
+                               if(!dpas_sem_is_rvalue($1) && !dpas_sem_is_error($1))
+                               {
+                                       dpas_error("invalid r-value used in expression");
+                               }
+                               $$ = $1;
+                       }
        | BasicConstant                                 {
                                jit_value_t value = jit_value_create_constant
                                        (dpas_current_function(), &($1));
@@ -1662,7 +2298,46 @@ Factor
                                }
                        }
        | '(' Expression ')'                    { $$ = $2; }
-       | Variable '(' ExpressionList ')'               { /* TODO */ }
+       | Variable '(' ExpressionList ')'               {
+                               /* Call a function, with no ignored result */
+                               if(dpas_sem_is_builtin($1))
+                               {
+                                       /* Expand a call to a builtin procedure */
+                                       $$ = dpas_expand_builtin
+                                               (dpas_sem_get_builtin($1), $3.exprs, $3.len);
+                               }
+                               else if(dpas_sem_is_procedure($1))
+                               {
+                                       /* Invoke a user-defined function */
+                                       dpas_scope_item_t item = dpas_sem_get_procedure($1);
+                                       $$ = invoke_procedure
+                                               ((jit_function_t)dpas_scope_item_info(item),
+                                                dpas_scope_item_name(item),
+                                                dpas_scope_item_type(item), 0, $3.exprs, $3.len);
+                               }
+                               else if(dpas_sem_is_rvalue($1) &&
+                                               jit_type_is_signature(dpas_sem_get_type($1)))
+                               {
+                                       /* Invoke a function via an indirect pointer */
+                                       $$ = invoke_procedure
+                                               (0, 0, dpas_sem_get_type($1), dpas_sem_get_value($1),
+                                                $3.exprs, $3.len);
+                               }
+                               else
+                               {
+                                       if(!dpas_sem_is_error($1))
+                                       {
+                                               dpas_error("invalid function name");
+                                       }
+                                       dpas_sem_set_error($$);
+                               }
+                               expression_list_free($3.exprs, $3.len);
+                               if(dpas_sem_is_void($$))
+                               {
+                                       dpas_error("cannot use a procedure in this context");
+                                       dpas_sem_set_error($$);
+                               }
+                       }
        | K_VA_ARG '(' TypeIdentifier ')'               { /* TODO */ }
        | K_SIZEOF '(' Variable ')'                             { /* TODO */ }
        | '(' K_IF Expression K_THEN Expression K_ELSE Expression ')'   {
@@ -1673,11 +2348,21 @@ Factor
 Variable
        : Identifier                                            {
                                dpas_scope_item_t item;
+                               int builtin;
                                item = dpas_scope_lookup(dpas_scope_current(), $1, 1);
                                if(!item)
                                {
-                                       dpas_error("`%s' is not declared in the current scope", $1);
-                                       dpas_sem_set_error($$);
+                                       builtin = dpas_is_builtin($1);
+                                       if(!builtin)
+                                       {
+                                               dpas_error
+                                                       ("`%s' is not declared in the current scope", $1);
+                                               dpas_sem_set_error($$);
+                                       }
+                                       else
+                                       {
+                                               dpas_sem_set_builtin($$, builtin);
+                                       }
                                }
                                else
                                {
index 50b32d901e4a32885acbddd6d6be0622384606b2..50065f36a4e90ec008fa536345b6c896151052fc 100644 (file)
@@ -275,6 +275,11 @@ void dpas_scope_check_undefined(dpas_scope_t scope)
        }
 }
 
+const char *dpas_scope_item_name(dpas_scope_item_t item)
+{
+       return item->name;
+}
+
 int dpas_scope_item_kind(dpas_scope_item_t item)
 {
        return item->kind;
@@ -290,6 +295,11 @@ void *dpas_scope_item_info(dpas_scope_item_t item)
        return item->info;
 }
 
+void dpas_scope_item_set_info(dpas_scope_item_t item, void *info)
+{
+       item->info = info;
+}
+
 const char *dpas_scope_item_filename(dpas_scope_item_t item)
 {
        return item->filename;
index 8d6633d0b66019b24f54a378d4aba5b4ee60da8e..b0f3770286520e1b4d576a25b5ea094ead201197 100644 (file)
@@ -89,6 +89,11 @@ void dpas_scope_add_const(dpas_scope_t scope, const char *name,
  */
 void dpas_scope_check_undefined(dpas_scope_t scope);
 
+/*
+ * Get the name associated with a scope item.
+ */
+const char *dpas_scope_item_name(dpas_scope_item_t item);
+
 /*
  * Get the kind associated with a scope item.
  */
@@ -104,6 +109,11 @@ jit_type_t dpas_scope_item_type(dpas_scope_item_t item);
  */
 void *dpas_scope_item_info(dpas_scope_item_t item);
 
+/*
+ * Set the information block associated with a scope item.
+ */
+void dpas_scope_item_set_info(dpas_scope_item_t item, void *info);
+
 /*
  * Get the filename associated with a scope item.
  */
index 8d4dd954728acaedd6a4477f64072ac0c4c0da1f..d89777126a1acd3a400455afbaf2c36435b47cab 100644 (file)
@@ -46,6 +46,8 @@ typedef struct
 #define        DPAS_SEM_ERROR                  (1 << 4)
 #define        DPAS_SEM_RETURN                 (1 << 5)
 #define        DPAS_SEM_LVALUE_EA              (1 << 6)
+#define        DPAS_SEM_VOID                   (1 << 7)
+#define        DPAS_SEM_BUILTIN                (1 << 8)
 
 /*
  * Set a semantic value to an l-value.
@@ -130,6 +132,26 @@ typedef struct
                        (sem).value__ = 0; \
                } while (0)
 
+/*
+ * Set a semantic value to indicate "void" for a procedure return.
+ */
+#define        dpas_sem_set_void(sem)  \
+               do { \
+                       (sem).kind__ = DPAS_SEM_VOID; \
+                       (sem).type__ = jit_type_void; \
+                       (sem).value__ = 0; \
+               } while (0)
+
+/*
+ * Set a semantic value to indicate a builtin function.
+ */
+#define        dpas_sem_set_builtin(sem,value) \
+               do { \
+                       (sem).kind__ = DPAS_SEM_BUILTIN; \
+                       (sem).type__ = jit_type_void; \
+                       (sem).value__ = (jit_value_t)(jit_nint)(value); \
+               } while (0)
+
 /*
  * Determine if a semantic value has a specific kind.
  */
@@ -140,6 +162,8 @@ typedef struct
 #define        dpas_sem_is_procedure(sem)      (((sem).kind__ & DPAS_SEM_PROCEDURE) != 0)
 #define        dpas_sem_is_error(sem)          (((sem).kind__ & DPAS_SEM_ERROR) != 0)
 #define        dpas_sem_is_return(sem)         (((sem).kind__ & DPAS_SEM_RETURN) != 0)
+#define        dpas_sem_is_void(sem)           (((sem).kind__ & DPAS_SEM_VOID) != 0)
+#define        dpas_sem_is_builtin(sem)        (((sem).kind__ & DPAS_SEM_BUILTIN) != 0)
 
 /*
  * Extract the type information from a semantic value.
@@ -151,6 +175,21 @@ typedef struct
  */
 #define        dpas_sem_get_value(sem)         ((sem).value__)
 
+/*
+ * Extract the procedure information from a semantic value.
+ */
+#define        dpas_sem_get_procedure(sem)     ((dpas_scope_item_t)((sem).value__))
+
+/*
+ * Extract the builtin function information from a semantic value.
+ */
+#define        dpas_sem_get_builtin(sem)       ((int)(jit_nint)((sem).value__))
+
+/*
+ * Convert an l-value effective address into a plain r-value.
+ */
+dpas_semvalue dpas_lvalue_to_rvalue(dpas_semvalue value);
+
 #ifdef __cplusplus
 };
 #endif
index 18f04a58dffaf106b7cf24ec9f21a048106b51e3..56cafc806dda963f738a09e926b9c9747be3ec18 100644 (file)
@@ -1137,3 +1137,19 @@ int dpas_type_is_boolean(jit_type_t type)
 {
        return (type == dpas_type_boolean || type == dpas_type_cboolean);
 }
+
+int dpas_type_is_record(jit_type_t type)
+{
+       type = jit_type_normalize(type);
+       return (jit_type_is_struct(type) || jit_type_is_union(type));
+}
+
+jit_type_t dpas_type_is_var(jit_type_t type)
+{
+       if(jit_type_is_tagged(type) &&
+          jit_type_get_tagged_kind(type) == DPAS_TAG_VAR)
+       {
+               return jit_type_get_ref(jit_type_normalize(type));
+       }
+       return 0;
+}
index ac5c4fecdfcd70e62213cfcc375139db3926b7ed..295769c5b9b054177837dd8ef9de0999dbca698e 100644 (file)
@@ -178,6 +178,16 @@ int dpas_type_is_numeric(jit_type_t type);
 int dpas_type_is_integer(jit_type_t type);
 int dpas_type_is_boolean(jit_type_t type);
 
+/*
+ * Determine if a type is a record.
+ */
+int dpas_type_is_record(jit_type_t type);
+
+/*
+ * Determine if a type is a "var" parameter, and return its element type.
+ */
+jit_type_t dpas_type_is_var(jit_type_t type);
+
 #ifdef __cplusplus
 };
 #endif
index d51dcd3dbe2351d6492030764272e18d7c4d8de5..b4a5295e36ca2e026982624dcc4e170a35c86289 100644 (file)
@@ -41,6 +41,7 @@ int jit_block_set_meta(jit_block_t block, int type, void *data,
 void *jit_block_get_meta(jit_block_t block, int type) JIT_NOTHROW;
 void jit_block_free_meta(jit_block_t block, int type) JIT_NOTHROW;
 int jit_block_is_reachable(jit_block_t block) JIT_NOTHROW;
+int jit_block_ends_in_dead(jit_block_t block) JIT_NOTHROW;
 
 #ifdef __cplusplus
 };
index d5b1a8438cabb63642cf02f81b5700c81de3f068..f667c3f9b62f2eb23dc89199905886a4321b88fe 100644 (file)
@@ -248,6 +248,8 @@ jit_value_t jit_insn_import
 int jit_insn_push(jit_function_t func, jit_value_t value) JIT_NOTHROW;
 int jit_insn_pop_stack(jit_function_t func, jit_nint num_items) JIT_NOTHROW;
 int jit_insn_return(jit_function_t func, jit_value_t value) JIT_NOTHROW;
+int jit_insn_return_ptr
+       (jit_function_t func, jit_value_t value, jit_type_t type) JIT_NOTHROW;
 int jit_insn_default_return(jit_function_t func) JIT_NOTHROW;
 int jit_insn_throw(jit_function_t func, jit_value_t value) JIT_NOTHROW;
 jit_value_t jit_insn_get_call_stack(jit_function_t func) JIT_NOTHROW;
@@ -276,6 +278,9 @@ int jit_insn_memset
        (jit_function_t func, jit_value_t dest,
         jit_value_t value, jit_value_t size) JIT_NOTHROW;
 
+int jit_insn_move_blocks
+       (jit_function_t func, jit_label_t from_label, jit_label_t to_label);
+
 void jit_insn_iter_init(jit_insn_iter_t *iter, jit_block_t block) JIT_NOTHROW;
 void jit_insn_iter_init_last
        (jit_insn_iter_t *iter, jit_block_t block) JIT_NOTHROW;
index 051ef659221117d51e0a39350c9ea9b65dde195f..7288b891e5830bb5b44369f3deaa7568fb0d50ab 100644 (file)
@@ -305,6 +305,7 @@ public:
        jit_value insn_import(jit_value value);
        void insn_return(const jit_value& value);
        void insn_return();
+       void insn_return_ptr(const jit_value& value, jit_type_t type);
        void insn_default_return();
        void insn_throw(const jit_value& value);
        jit_value insn_get_call_stack();
index d6f69608a47cfddf11b745fdbd88a39a332a1488..8878ecb72097dc9feffeadcfbfaa1dcad23a9228 100644 (file)
@@ -371,3 +371,14 @@ int jit_block_is_reachable(jit_block_t block)
 {
        return (block->entered_via_top || block->entered_via_branch);
 }
+
+/*@
+ * @deftypefun int jit_block_ends_in_dead (jit_block_t block)
+ * Determine if a block ends in a "dead" marker.  That is, control
+ * will not fall out through the end of the block.
+ * @end deftypefun
+@*/
+int jit_block_ends_in_dead(jit_block_t block)
+{
+       return block->ends_in_dead;
+}
index 7d66792e8c2e76f39f40a43920c67ae666a10d3c..914e9b8d1816d2654c6bf45b03ab37954ea9b8db 100644 (file)
@@ -589,9 +589,7 @@ static void dump_interp_code(FILE *stream, void **pc)
                                }
                                else if((info->flags & JIT_OPCODE_IS_CALL_EXTERNAL) != 0)
                                {
-                                       putc(' ', stream);
-                                       jit_dump_type(stream, (jit_type_t)(pc[0]));
-                                       fprintf(stream, ", 0x%lX, %ld",
+                                       fprintf(stream, " 0x%lX, %ld",
                                                        (long)(jit_nint)(pc[1]), (long)(jit_nint)(pc[2]));
                                        pc += 3;
                                }
index 0fc1cf0e1d8c4b1776a5f1dbc56933bbdb55ae04..d73e1e4e6db05dcd96826bb9fb926e9d6710b7d3 100644 (file)
@@ -517,7 +517,7 @@ static void compile_block(jit_gencode_t gen, jit_function_t func,
                        case JIT_OP_PREPARE_FOR_LEAVE:
                        {
                                /* Call the finally clauses that are relevant to the
-                                  "JIT_OP_BRANCH" instruction that follows */
+                                  "JIT_OP_BR" instruction that follows */
                                _jit_regs_spill_all(gen);
                                insn = jit_insn_iter_next(&iter);
                                branch_block = jit_block_from_label
index 6de9057a6724f9d98f5f0aaa4ae021e4c0cf2477..b12e48faa846edbcd53edfce68b6a0513384e02a 100644 (file)
@@ -1096,9 +1096,8 @@ int jit_insn_label(jit_function_t func, jit_label_t *label)
                if(last)
                {
                        /* We will be entered via the top if the last block
-                          did not end in an unconditional branch and it
                           is not explicitly marked as "dead" */
-                       if(last->opcode != JIT_OP_BR && !(current->ends_in_dead))
+                       if(!(current->ends_in_dead))
                        {
                                block->entered_via_top = 1;
                        }
@@ -3455,6 +3454,7 @@ int jit_insn_branch(jit_function_t func, jit_label_t *label)
        insn->opcode = (short)JIT_OP_BR;
        insn->flags = JIT_INSN_DEST_IS_LABEL;
        insn->dest = (jit_value_t)(*label);
+       func->builder->current_block->ends_in_dead = 1;
        block = _jit_block_create(func, 0);
        if(!block)
        {
@@ -5221,6 +5221,10 @@ jit_value_t jit_insn_call_native
        insn->flags = JIT_INSN_DEST_IS_NATIVE | JIT_INSN_VALUE1_IS_NAME;
        insn->dest = (jit_value_t)native_func;
        insn->value1 = (jit_value_t)name;
+#ifdef JIT_BACKEND_INTERP
+       insn->flags |= JIT_INSN_VALUE2_IS_SIGNATURE;
+       insn->value2 = (jit_value_t)jit_type_copy(signature);
+#endif
 
        /* If the function does not return, then end the current block.
           The next block does not have "entered_via_top" set so that
@@ -5824,16 +5828,43 @@ int jit_insn_return(jit_function_t func, jit_value_t value)
                        case JIT_TYPE_UNION:
                        {
                                jit_value_t return_ptr = jit_value_get_struct_pointer(func);
+                               jit_value_t value_addr;
                                if(return_ptr)
                                {
-                                       /* Return the structure via the supplied pointer */
-                                       /* TODO */
+                                       /* Copy the structure's contents to the supplied pointer */
+                                       value_addr = jit_insn_address_of(func, value);
+                                       if(!value_addr)
+                                       {
+                                               return 0;
+                                       }
+                                       if(!jit_insn_memcpy
+                                                  (func, return_ptr, value_addr,
+                                                   jit_value_create_nint_constant
+                                                               (func, jit_type_nint,
+                                                                (jit_nint)(jit_type_get_size(type)))))
+                                       {
+                                               return 0;
+                                       }
+
+                                       /* Output a regular return for the function */
+                                       if(!create_noarg_note(func, JIT_OP_RETURN))
+                                       {
+                                               return 0;
+                                       }
                                }
                                else
                                {
                                        /* Return the structure via registers */
-                                       if(!create_unary_note
-                                                       (func, JIT_OP_RETURN_SMALL_STRUCT, value))
+                                       value_addr = jit_insn_address_of(func, value);
+                                       if(!value_addr)
+                                       {
+                                               return 0;
+                                       }
+                                       if(!create_note
+                                               (func, JIT_OP_RETURN_SMALL_STRUCT, value_addr,
+                                        jit_value_create_nint_constant
+                                                       (func, jit_type_nint,
+                                                        (jit_nint)(jit_type_get_size(type)))))
                                        {
                                                break;
                                        }
@@ -5847,7 +5878,107 @@ int jit_insn_return(jit_function_t func, jit_value_t value)
        func->builder->current_block->ends_in_dead = 1;
 
        /* Start a new block just after the "return" instruction */
-       return jit_insn_label(func, 0);
+       if(!_jit_block_create(func, 0))
+       {
+               return 0;
+       }
+       return 1;
+}
+
+/*@
+ * @deftypefun int jit_insn_return_ptr (jit_function_t func, jit_value_t value, jit_type_t type)
+ * Output an instruction to return @code{*value} as the function's result.
+ * This is normally used for returning @code{struct} and @code{union}
+ * values where you have the effective address of the structure, rather
+ * than the structure's contents, in @code{value}.
+ * @end deftypefun
+@*/
+int jit_insn_return_ptr
+       (jit_function_t func, jit_value_t value, jit_type_t type)
+{
+       jit_value_t return_ptr;
+
+       /* Ensure that we have a builder for this function */
+       if(!_jit_function_ensure_builder(func))
+       {
+               return 0;
+       }
+
+       /* This function has an ordinary return path */
+       func->builder->ordinary_return = 1;
+
+       /* Convert the value into a pointer */
+       value = jit_insn_convert(func, value, jit_type_void_ptr, 0);
+       if(!value)
+       {
+               return 0;
+       }
+
+       /* Determine how to return the value, based on the pointed-to type */
+       switch(jit_type_normalize(type)->kind)
+       {
+               case JIT_TYPE_STRUCT:
+               case JIT_TYPE_UNION:
+               {
+                       /* Handle "finally" clauses if necessary */
+                       if(!handle_finally(func, JIT_OP_PREPARE_FOR_RETURN))
+                       {
+                               return 0;
+                       }
+
+                       /* Determine the kind of structure return to use */
+                       return_ptr = jit_value_get_struct_pointer(func);
+                       if(return_ptr)
+                       {
+                               /* Copy the structure's contents to the supplied pointer */
+                               if(!jit_insn_memcpy
+                                          (func, return_ptr, value,
+                                           jit_value_create_nint_constant
+                                                       (func, jit_type_nint,
+                                                        (jit_nint)(jit_type_get_size(type)))))
+                               {
+                                       return 0;
+                               }
+
+                               /* Output a regular return for the function */
+                               if(!create_noarg_note(func, JIT_OP_RETURN))
+                               {
+                                       return 0;
+                               }
+                       }
+                       else
+                       {
+                               /* Return the structure via registers */
+                               if(!create_note
+                                       (func, JIT_OP_RETURN_SMALL_STRUCT, value,
+                                    jit_value_create_nint_constant
+                                               (func, jit_type_nint,
+                                                (jit_nint)(jit_type_get_size(type)))))
+                               {
+                                       break;
+                               }
+                       }
+               }
+               break;
+
+               default:
+               {
+                       /* Everything else uses the normal return logic */
+                       return jit_insn_return
+                               (func, jit_insn_load_relative(func, value, 0, type));
+               }
+               /* Not reached */
+       }
+
+       /* Mark the current block as "ends in dead" */
+       func->builder->current_block->ends_in_dead = 1;
+
+       /* Start a new block just after the "return" instruction */
+       if(!_jit_block_create(func, 0))
+       {
+               return 0;
+       }
+       return 1;
 }
 
 /*@
@@ -5884,9 +6015,9 @@ int jit_insn_default_return(jit_function_t func)
        last = _jit_block_get_last(current);
        if(last)
        {
-               if(last->opcode == JIT_OP_BR)
+               if(current->ends_in_dead)
                {
-                       /* This block ends in an unconditional branch */
+                       /* This block ends in an unconditional branch, return, etc */
                        return 2;
                }
        }
@@ -6373,6 +6504,72 @@ int jit_insn_memset
        return apply_ternary(func, JIT_OP_MEMSET, dest, value, size);
 }
 
+/*@
+ * @deftypefun int jit_insn_move_blocks (jit_function_t func, jit_label_t from_label, jit_label_t to_label)
+ * Move all of the blocks between @code{from_label} (inclusive) and
+ * @code{to_label} (exclusive) to the end of the current function.
+ * This is typically used to move the expression in a @code{while}
+ * loop to the end of the body, where it can be executed more
+ * efficiently.
+ * @end deftypefun
+@*/
+int jit_insn_move_blocks
+       (jit_function_t func, jit_label_t from_label, jit_label_t to_label)
+{
+       jit_block_t first_block;
+       jit_block_t block;
+       jit_block_t next;
+
+       /* Find the first block that needs to be moved */
+       first_block = jit_block_from_label(func, from_label);
+       if(!first_block)
+       {
+               return 0;
+       }
+
+       /* Keep moving blocks until we come across "to_label" */
+       block = first_block;
+       while(block != 0 && block->label != to_label)
+       {
+               next = block->next;
+               if(block->next != 0)
+               {
+                       block->next->prev = block->prev;
+               }
+               else
+               {
+                       func->builder->last_block = block->prev;
+               }
+               if(block->prev != 0)
+               {
+                       block->prev->next = block->next;
+               }
+               else
+               {
+                       func->builder->first_block = block->next;
+               }
+               block->next = 0;
+               block->prev = func->builder->last_block;
+               if(func->builder->last_block)
+               {
+                       func->builder->last_block->next = block;
+               }
+               else
+               {
+                       func->builder->first_block = block;
+               }
+               func->builder->last_block = block;
+               block = next;
+       }
+       func->builder->current_block = func->builder->last_block;
+
+       /* The first block will be entered via its top now */
+       first_block->entered_via_top = 1;
+
+       /* Create a new block after the last one we moved, to start fresh */
+       return jit_insn_label(func, 0);
+}
+
 /*@
  * @deftypefun void jit_insn_iter_init ({jit_insn_iter_t *} iter, jit_block_t block)
  * Initialize an iterator to point to the first instruction in @code{block}.
index 8ec640cee7db3ece1821d44eef0d988f954c6400..a754b0d8acf29a6f774f5515362fa1224aea24b6 100644 (file)
@@ -3455,8 +3455,8 @@ void _jit_run_function(jit_function_interp *func, jit_item *args,
                {
                        /* Return from the current function, with a small structure */
                #if JIT_APPLY_MAX_STRUCT_IN_REG != 0
-                       jit_memcpy(return_area->struct_value, stacktop,
-                                          (unsigned int)VM_NINT_ARG);
+                       jit_memcpy(return_area->struct_value, VM_STK_PTR1,
+                                          (unsigned int)VM_STK_NINT0);
                #endif
                        return;
                }
index 6ded14474f5dbea57ebcac44cf74b766360516d6..7086ac453debbf294e05721d74d4cb9dfb99b4b9 100644 (file)
@@ -410,7 +410,7 @@ jit_opcode_info_t const jit_opcodes[JIT_OP_NUM_OPCODES] = {
        {"return_float32",                              F_(EMPTY, FLOAT32, EMPTY)},
        {"return_float64",                              F_(EMPTY, FLOAT64, EMPTY)},
        {"return_nfloat",                               F_(EMPTY, NFLOAT, EMPTY)},
-       {"return_small_struct",                 F_(EMPTY, PTR, EMPTY) | NINT_ARG},
+       {"return_small_struct",                 F_(EMPTY, PTR, PTR)},
        {"setup_for_nested",                    F_(EMPTY, INT, EMPTY)},
        {"setup_for_sibling",                   F_(EMPTY, INT, INT) | NINT_ARG},
        {"import",                                              F_(PTR, ANY, INT)},
@@ -511,9 +511,9 @@ jit_opcode_info_t const jit_opcodes[JIT_OP_NUM_OPCODES] = {
        /*
         * Block operations.
         */
-       {"memcpy",                                              F_(PTR, PTR, INT)},
-       {"memmove",                                             F_(PTR, PTR, INT)},
-       {"memset",                                              F_(PTR, INT, INT)},
+       {"memcpy",                                              F_(PTR, PTR, PTR)},
+       {"memmove",                                             F_(PTR, PTR, PTR)},
+       {"memset",                                              F_(PTR, INT, PTR)},
 };
 
 #if defined(JIT_BACKEND_INTERP)
index e85101f3a792ce2d5d583b0cd09db7c4caf291b2..28bb7ebac1d3636eba2a808d9643aa0fd8698b83 100644 (file)
@@ -479,7 +479,7 @@ int _jit_create_call_return_insns
                        return 0;
                }
        }
-       else
+       else if(return_type->kind != JIT_TYPE_VOID)
        {
                if(!jit_insn_return_reg(func, return_value, ARM_R0))
                {
index 181ebb1acc88ff63ffdfb1b09bd24dc458694ab0..74aaa9f2ab53a8217485a0c769a9a7bbdcd987ec 100644 (file)
@@ -504,7 +504,7 @@ int _jit_create_call_return_insns
                        return 0;
                }
        }
-       else
+       else if(return_type->kind != JIT_TYPE_VOID)
        {
                if(!jit_insn_return_reg(func, return_value, 0))
                {
@@ -1027,7 +1027,6 @@ void _jit_gen_insn(jit_gencode_t gen, jit_function_t func,
                /* Not reached */
 
                case JIT_OP_CALL:
-               case JIT_OP_CALL_EXTERNAL:
                {
                        /* Call a function, whose pointer is supplied explicitly */
                        jit_cache_opcode(&(gen->posn), insn->opcode);
@@ -1035,6 +1034,17 @@ void _jit_gen_insn(jit_gencode_t gen, jit_function_t func,
                }
                break;
 
+               case JIT_OP_CALL_EXTERNAL:
+               {
+                       /* Call a native function, whose pointer is supplied explicitly */
+                       jit_cache_opcode(&(gen->posn), insn->opcode);
+                       jit_cache_native(&(gen->posn), (jit_nint)(insn->value2));
+                       jit_cache_native(&(gen->posn), (jit_nint)(insn->dest));
+                       jit_cache_native(&(gen->posn), (jit_nint)
+                                       (jit_type_num_params((jit_type_t)(insn->value2))));
+               }
+               break;
+
                case JIT_OP_CALL_INDIRECT:
                case JIT_OP_CALL_VTABLE_PTR:
                {
index 1b3bcabd06d7c804fb2a758ed00a870576ae6fd6..441463536e420cfc01d2647f81b79d0c057a8818 100644 (file)
@@ -651,7 +651,7 @@ int _jit_create_call_return_insns
                        return 0;
                }
        }
-       else
+       else if(return_type->kind != JIT_TYPE_VOID)
        {
                if(!jit_insn_return_reg(func, return_value, X86_REG_EAX))
                {
index f9c923a7d32af965753c5c6d04b02098a2b7fba1..ff9a2fa6d2a7280c4acfd75bb925a4b6917a8743 100644 (file)
@@ -452,7 +452,7 @@ void jit_type_free(jit_type_t type)
                return;
        }
        jit_type_free(type->sub_type);
-       for(index = 0; index < type->num_components; ++type)
+       for(index = 0; index < type->num_components; ++index)
        {
                jit_type_free(type->components[index].type);
                if(type->components[index].name)
index 781c304722e174842d0aa36a9e30f2c30e69b5c5..25e550e9aa5ff7b1fe43cfbfb2893cd320925dd9 100644 (file)
@@ -600,7 +600,7 @@ int jit_value_is_constant(jit_value_t value)
 @*/
 void jit_value_ref(jit_function_t func, jit_value_t value)
 {
-       if(!_jit_function_ensure_builder(func))
+       if(!value || !_jit_function_ensure_builder(func))
        {
                return;
        }
index 4adee3cba0731607b38757842640918af37b8cfa..9b64830619bf47b9c7d1f10843adc78c930dd1d0 100644 (file)
@@ -637,6 +637,7 @@ jit_value jit_function::get_struct_pointer()
  * @deftypemethodx jit_function jit_value insn_import (jit_value value)
  * @deftypemethodx jit_function void insn_return ({const jit_value&} value)
  * @deftypemethodx jit_function void insn_return ()
+ * @deftypemethodx jit_function void insn_return_ptr ({const jit_value&} value, jit_type_t type)
  * @deftypemethodx jit_function void insn_default_return ()
  * @deftypemethodx jit_function void insn_throw ({const jit_value&} value)
  * @deftypemethodx jit_function jit_value insn_get_call_stack ()
@@ -1130,6 +1131,14 @@ void jit_function::insn_return()
        }
 }
 
+void jit_function::insn_return_ptr(const jit_value& value, jit_type_t type)
+{
+       if(!jit_insn_return_ptr(func, value.raw(), type))
+       {
+               out_of_memory();
+       }
+}
+
 void jit_function::insn_default_return()
 {
        if(!jit_insn_default_return(func))