libjit.git - libjit

index : libjit.git
libjit
summary refs log tree commit diff
diff options
context:
space:
mode:
Diffstat
-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
27 files changed, 1381 insertions, 57 deletions
diff --git a/ChangeLog b/ChangeLog
index 4d1035f..723c495 100644
--- 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.
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))
generated by cgit v1.2.3 (git 2.39.1) at 2025年09月22日 15:57:51 +0000

AltStyle によって変換されたページ (->オリジナル) /