-rw-r--r-- | ChangeLog | 13 | ||||
-rw-r--r-- | dpas/Makefile.am | 1 | ||||
-rw-r--r-- | dpas/dpas-builtin.c | 266 | ||||
-rw-r--r-- | dpas/dpas-function.c | 17 | ||||
-rw-r--r-- | dpas/dpas-internal.h | 17 | ||||
-rw-r--r-- | dpas/dpas-main.c | 8 | ||||
-rw-r--r-- | dpas/dpas-parser.y | 749 | ||||
-rw-r--r-- | dpas/dpas-scope.c | 10 | ||||
-rw-r--r-- | dpas/dpas-scope.h | 10 | ||||
-rw-r--r-- | dpas/dpas-semantics.h | 39 | ||||
-rw-r--r-- | dpas/dpas-types.c | 16 | ||||
-rw-r--r-- | dpas/dpas-types.h | 10 | ||||
-rw-r--r-- | include/jit/jit-block.h | 1 | ||||
-rw-r--r-- | include/jit/jit-insn.h | 5 | ||||
-rw-r--r-- | include/jit/jit-plus.h | 1 | ||||
-rw-r--r-- | jit/jit-block.c | 11 | ||||
-rw-r--r-- | jit/jit-dump.c | 4 | ||||
-rw-r--r-- | jit/jit-function.c | 2 | ||||
-rw-r--r-- | jit/jit-insn.c | 215 | ||||
-rw-r--r-- | jit/jit-interp.cpp | 4 | ||||
-rw-r--r-- | jit/jit-opcode.c | 8 | ||||
-rw-r--r-- | jit/jit-rules-arm.c | 2 | ||||
-rw-r--r-- | jit/jit-rules-interp.c | 14 | ||||
-rw-r--r-- | jit/jit-rules-x86.c | 2 | ||||
-rw-r--r-- | jit/jit-type.c | 2 | ||||
-rw-r--r-- | jit/jit-value.c | 2 | ||||
-rw-r--r-- | jitplus/jit-plus-function.cpp | 9 |
@@ -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. diff --git a/dpas/Makefile.am b/dpas/Makefile.am index c405af3..a379b41 100644 --- a/dpas/Makefile.am +++ b/dpas/Makefile.am @@ -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 index 0000000..0af678b --- /dev/null +++ b/dpas/dpas-builtin.c @@ -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; +} diff --git a/dpas/dpas-function.c b/dpas/dpas-function.c index 98511d3..73f3577 100644 --- a/dpas/dpas-function.c +++ b/dpas/dpas-function.c @@ -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; +} diff --git a/dpas/dpas-internal.h b/dpas/dpas-internal.h index db7bc1b..c2e4757 100644 --- a/dpas/dpas-internal.h +++ b/dpas/dpas-internal.h @@ -39,6 +39,11 @@ 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). */ typedef struct @@ -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 diff --git a/dpas/dpas-main.c b/dpas/dpas-main.c index b0d8c2f..f10f495 100644 --- a/dpas/dpas-main.c +++ b/dpas/dpas-main.c @@ -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(); diff --git a/dpas/dpas-parser.y b/dpas/dpas-parser.y index 2b3c513..98837b2 100644 --- a/dpas/dpas-parser.y +++ b/dpas/dpas-parser.y @@ -47,6 +47,11 @@ extern char yytext[]; int dpas_error_reported = 0; /* + * Function dumping flag. + */ +int dpas_dump_functions = 0; + +/* * Report error messages from the parser. */ static void yyerror(char *msg) @@ -444,6 +449,149 @@ static void parameter_list_merge(dpas_params *list1, dpas_params *list2) } /* + * 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. */ #define handle_binary(name,func,arg1,arg2) \ @@ -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 { diff --git a/dpas/dpas-scope.c b/dpas/dpas-scope.c index 50b32d9..50065f3 100644 --- a/dpas/dpas-scope.c +++ b/dpas/dpas-scope.c @@ -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; diff --git a/dpas/dpas-scope.h b/dpas/dpas-scope.h index 8d6633d..b0f3770 100644 --- a/dpas/dpas-scope.h +++ b/dpas/dpas-scope.h @@ -90,6 +90,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. */ int dpas_scope_item_kind(dpas_scope_item_t item); @@ -105,6 +110,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. */ const char *dpas_scope_item_filename(dpas_scope_item_t item); diff --git a/dpas/dpas-semantics.h b/dpas/dpas-semantics.h index 8d4dd95..d897771 100644 --- a/dpas/dpas-semantics.h +++ b/dpas/dpas-semantics.h @@ -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. @@ -131,6 +133,26 @@ typedef struct } 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. */ #define dpas_sem_is_lvalue(sem) (((sem).kind__ & DPAS_SEM_LVALUE) != 0) @@ -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 diff --git a/dpas/dpas-types.c b/dpas/dpas-types.c index 18f04a5..56cafc8 100644 --- a/dpas/dpas-types.c +++ b/dpas/dpas-types.c @@ -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; +} diff --git a/dpas/dpas-types.h b/dpas/dpas-types.h index ac5c4fe..295769c 100644 --- a/dpas/dpas-types.h +++ b/dpas/dpas-types.h @@ -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 diff --git a/include/jit/jit-block.h b/include/jit/jit-block.h index d51dcd3..b4a5295 100644 --- a/include/jit/jit-block.h +++ b/include/jit/jit-block.h @@ -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 }; diff --git a/include/jit/jit-insn.h b/include/jit/jit-insn.h index d5b1a84..f667c3f 100644 --- a/include/jit/jit-insn.h +++ b/include/jit/jit-insn.h @@ -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; diff --git a/include/jit/jit-plus.h b/include/jit/jit-plus.h index 051ef65..7288b89 100644 --- a/include/jit/jit-plus.h +++ b/include/jit/jit-plus.h @@ -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(); diff --git a/jit/jit-block.c b/jit/jit-block.c index d6f6960..8878ecb 100644 --- a/jit/jit-block.c +++ b/jit/jit-block.c @@ -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; +} diff --git a/jit/jit-dump.c b/jit/jit-dump.c index 7d66792..914e9b8 100644 --- a/jit/jit-dump.c +++ b/jit/jit-dump.c @@ -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; } diff --git a/jit/jit-function.c b/jit/jit-function.c index 0fc1cf0..d73e1e4 100644 --- a/jit/jit-function.c +++ b/jit/jit-function.c @@ -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 diff --git a/jit/jit-insn.c b/jit/jit-insn.c index 6de9057..b12e48f 100644 --- a/jit/jit-insn.c +++ b/jit/jit-insn.c @@ -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; } } @@ -6374,6 +6505,72 @@ int jit_insn_memset } /*@ + * @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}. * @end deftypefun diff --git a/jit/jit-interp.cpp b/jit/jit-interp.cpp index 8ec640c..a754b0d 100644 --- a/jit/jit-interp.cpp +++ b/jit/jit-interp.cpp @@ -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; } diff --git a/jit/jit-opcode.c b/jit/jit-opcode.c index 6ded144..7086ac4 100644 --- a/jit/jit-opcode.c +++ b/jit/jit-opcode.c @@ -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) diff --git a/jit/jit-rules-arm.c b/jit/jit-rules-arm.c index e85101f..28bb7eb 100644 --- a/jit/jit-rules-arm.c +++ b/jit/jit-rules-arm.c @@ -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)) { diff --git a/jit/jit-rules-interp.c b/jit/jit-rules-interp.c index 181ebb1..74aaa9f 100644 --- a/jit/jit-rules-interp.c +++ b/jit/jit-rules-interp.c @@ -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: { diff --git a/jit/jit-rules-x86.c b/jit/jit-rules-x86.c index 1b3bcab..4414635 100644 --- a/jit/jit-rules-x86.c +++ b/jit/jit-rules-x86.c @@ -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)) { diff --git a/jit/jit-type.c b/jit/jit-type.c index f9c923a..ff9a2fa 100644 --- a/jit/jit-type.c +++ b/jit/jit-type.c @@ -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) diff --git a/jit/jit-value.c b/jit/jit-value.c index 781c304..25e550e 100644 --- a/jit/jit-value.c +++ b/jit/jit-value.c @@ -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; } diff --git a/jitplus/jit-plus-function.cpp b/jitplus/jit-plus-function.cpp index 4adee3c..9b64830 100644 --- a/jitplus/jit-plus-function.cpp +++ b/jitplus/jit-plus-function.cpp @@ -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)) |