mirror of
https://github.com/janet-lang/janet
synced 2024-11-18 06:34:48 +00:00
Change how labels are recorded.
Disallow jumping to arbitrary instructions - instead, only allow jumps to label ids. This will make various transformations and validations easier since adding or remove instructions does not break jumps.
This commit is contained in:
parent
8a394f2506
commit
480c5b5e9d
@ -45,7 +45,8 @@
|
||||
t)
|
||||
|
||||
(defn setup-default-types
|
||||
[into]
|
||||
[ctx]
|
||||
(def into @[])
|
||||
(defn add-prim-type
|
||||
[name native-name]
|
||||
(array/push into ~(type-prim ,name ,native-name))
|
||||
@ -54,7 +55,9 @@
|
||||
(add-prim-type 'double 'f64)
|
||||
(add-prim-type 'int 's32)
|
||||
(add-prim-type 'pointer 'pointer)
|
||||
(add-prim-type 'boolean 'boolean))
|
||||
(add-prim-type 'boolean 'boolean)
|
||||
(sysir/asm ctx into)
|
||||
ctx)
|
||||
|
||||
(defn type-extract
|
||||
"Given a symbol:type combination, extract the proper name and the type separately"
|
||||
@ -66,9 +69,13 @@
|
||||
(var do-binop nil)
|
||||
(var do-comp nil)
|
||||
|
||||
###
|
||||
### Inside functions
|
||||
###
|
||||
|
||||
(defn visit1
|
||||
"Take in a form and compile code and put it into `into`. Return result slot."
|
||||
[code into]
|
||||
[code into &opt no-return]
|
||||
(cond
|
||||
|
||||
# Compile a constant
|
||||
@ -79,6 +86,14 @@
|
||||
(array/push into ~(constant ,slot ,code))
|
||||
slot)
|
||||
|
||||
# Booleans
|
||||
(boolean? code)
|
||||
(let [slot (get-slot)
|
||||
slottype 'boolean]
|
||||
(array/push into ~(bind ,slot ,slottype))
|
||||
(array/push into ~(constant ,slot ,(if code -1 0)))
|
||||
slot)
|
||||
|
||||
# Binding
|
||||
(symbol? code)
|
||||
(named-slot code)
|
||||
@ -136,13 +151,27 @@
|
||||
(array/push into ~(move ,slot ,result))
|
||||
slot)
|
||||
|
||||
# Named variables
|
||||
'var
|
||||
(do
|
||||
(assert (= 2 (length args)))
|
||||
(def [full-name value] args)
|
||||
(assert (symbol? full-name))
|
||||
(def [name tp] (type-extract full-name 'int))
|
||||
(def result (visit1 value into))
|
||||
(def slot (get-slot name))
|
||||
(when tp
|
||||
(array/push into ~(bind ,slot ,tp)))
|
||||
(array/push into ~(move ,slot ,result))
|
||||
slot)
|
||||
|
||||
# Assignment
|
||||
'set
|
||||
(do
|
||||
(assert (= 2 (length args)))
|
||||
(def [to x] args)
|
||||
(def result (visit1 x into))
|
||||
(def toslot (get-slot to))
|
||||
(def toslot (named-slot to))
|
||||
(array/push into ~(move ,toslot ,result))
|
||||
toslot)
|
||||
|
||||
@ -160,9 +189,24 @@
|
||||
# Sequence of operations
|
||||
'do
|
||||
(do
|
||||
(var ret nil)
|
||||
(each form args (set ret (visit1 form into)))
|
||||
ret)
|
||||
(each form (slice args 0 -2) (visit1 form into true))
|
||||
(visit1 (last args) into))
|
||||
|
||||
# While loop
|
||||
'while
|
||||
(do
|
||||
(def lab-test (keyword (gensym)))
|
||||
(def lab-exit (keyword (gensym)))
|
||||
(assert (< 1 (length args)))
|
||||
(def [cnd & body] args)
|
||||
(array/push into lab-test)
|
||||
(def condition-slot (visit1 cnd into))
|
||||
(array/push into ~(branch-not ,condition-slot ,lab-exit))
|
||||
(each code body
|
||||
(visit1 code into true))
|
||||
(array/push into ~(jump ,lab-test))
|
||||
(array/push into lab-exit)
|
||||
nil)
|
||||
|
||||
# Branch
|
||||
'if
|
||||
@ -186,7 +230,7 @@
|
||||
# Assume function call
|
||||
(do
|
||||
(def slots @[])
|
||||
(def ret (get-slot))
|
||||
(def ret (if no-return nil (get-slot)))
|
||||
(each arg args
|
||||
(array/push slots (visit1 arg into)))
|
||||
(array/push into ~(call ,ret ,op ,;slots))
|
||||
@ -235,28 +279,79 @@
|
||||
(set left right))
|
||||
result)
|
||||
|
||||
###
|
||||
### Top level
|
||||
###
|
||||
|
||||
(defn top
|
||||
"Visit and emit code for a top level form."
|
||||
[ctx form]
|
||||
(assert (tuple? form))
|
||||
(def [head & rest] form)
|
||||
(case head
|
||||
|
||||
# Top level function definition
|
||||
'defn
|
||||
(do
|
||||
# TODO doc strings
|
||||
(table/clear name-to-slot)
|
||||
(array/clear slot-to-name)
|
||||
(def [name args & body] rest)
|
||||
(assert (tuple? args))
|
||||
(def [fn-name fn-tp] (type-extract name 'int))
|
||||
(def pcount (length args)) #TODO - more complicated signatures
|
||||
(def ir-asm
|
||||
@[~(link-name ,(string fn-name))
|
||||
~(parameter-count ,pcount)])
|
||||
(each arg args
|
||||
(def [name tp] (type-extract arg 'int))
|
||||
(def slot (get-slot name))
|
||||
(array/push ir-asm ~(bind ,slot ,tp)))
|
||||
(each part body
|
||||
(visit1 part ir-asm true))
|
||||
(eprintf "%.99M\n" ir-asm)
|
||||
(sysir/asm ctx ir-asm))
|
||||
|
||||
(errorf "unknown form %v" form)))
|
||||
|
||||
###
|
||||
###
|
||||
###
|
||||
|
||||
(def myprog
|
||||
'(do
|
||||
'(defn myprog []
|
||||
(def xyz:int (+ 1 2 3))
|
||||
(def abc:int (* 4 5 6))
|
||||
(def x:boolean (= 5 7))
|
||||
(the int (printf "hello, world!\n%d\n" (the int (if x abc xyz))))
|
||||
(var i:int 0)
|
||||
(while (< i 10)
|
||||
(set i (+ 1 i))
|
||||
(printf "i = %d\n" (the int i)))
|
||||
(printf "hello, world!\n%d\n" (the int (if x abc xyz)))
|
||||
(return (/ abc xyz))))
|
||||
|
||||
(def doloop
|
||||
'(defn doloop [x:int y:int]
|
||||
(var i:int x)
|
||||
(while (< i y)
|
||||
(set i (+ 1 i))
|
||||
(printf "i = %d\n" (the int i)))
|
||||
(return x)))
|
||||
|
||||
(def main-fn
|
||||
'(defn main:int []
|
||||
(var x:int 10)
|
||||
(doloop 10 20)
|
||||
(printf "done!\n")
|
||||
(return (the int 0))))
|
||||
|
||||
(defn dotest
|
||||
[]
|
||||
(def ctx (sysir/context))
|
||||
(def ir-asm
|
||||
@['(link-name "main")
|
||||
'(parameter-count 0)])
|
||||
(setup-default-types ir-asm)
|
||||
(visit1 myprog ir-asm)
|
||||
(eprintf "%.99M" ir-asm)
|
||||
(sysir/asm ctx ir-asm)
|
||||
(setup-default-types ctx)
|
||||
#(top ctx myprog)
|
||||
(top ctx doloop)
|
||||
(top ctx main-fn)
|
||||
(print (sysir/to-c ctx)))
|
||||
|
||||
(dotest)
|
||||
|
188
src/core/sysir.c
188
src/core/sysir.c
@ -51,7 +51,7 @@
|
||||
* [x] support for stack allocation of arrays
|
||||
* [ ] more math intrinsics
|
||||
* [x] source mapping (using built in Janet source mapping metadata on tuples)
|
||||
* [ ] unit type or void type
|
||||
* [x] unit type or void type
|
||||
* [ ] (typed) function pointer types and remove calling untyped pointers
|
||||
* [x] APL array semantics for binary operands (maybe?)
|
||||
* [ ] a few built-in array combinators (maybe?)
|
||||
@ -66,7 +66,6 @@
|
||||
#include <janet.h>
|
||||
#include "util.h"
|
||||
#include "vector.h"
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
@ -85,6 +84,7 @@ typedef enum {
|
||||
JANET_PRIM_STRUCT,
|
||||
JANET_PRIM_UNION,
|
||||
JANET_PRIM_ARRAY,
|
||||
JANET_PRIM_VOID,
|
||||
JANET_PRIM_UNKNOWN
|
||||
} JanetPrim;
|
||||
|
||||
@ -109,6 +109,7 @@ static const JanetPrimName prim_names[] = {
|
||||
{"u64", JANET_PRIM_U64},
|
||||
{"u8", JANET_PRIM_U8},
|
||||
{"union", JANET_PRIM_UNION},
|
||||
{"void", JANET_PRIM_VOID},
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
@ -139,6 +140,7 @@ typedef enum {
|
||||
JANET_SYSOP_RETURN,
|
||||
JANET_SYSOP_JUMP,
|
||||
JANET_SYSOP_BRANCH,
|
||||
JANET_SYSOP_BRANCH_NOT,
|
||||
JANET_SYSOP_ADDRESS,
|
||||
JANET_SYSOP_CALLK,
|
||||
JANET_SYSOP_TYPE_PRIMITIVE,
|
||||
@ -153,6 +155,7 @@ typedef enum {
|
||||
JANET_SYSOP_TYPE_UNION,
|
||||
JANET_SYSOP_POINTER_ADD,
|
||||
JANET_SYSOP_POINTER_SUBTRACT,
|
||||
JANET_SYSOP_LABEL
|
||||
} JanetSysOp;
|
||||
|
||||
typedef struct {
|
||||
@ -170,6 +173,7 @@ static const JanetSysInstrName sys_op_names[] = {
|
||||
{"bnot", JANET_SYSOP_BNOT},
|
||||
{"bor", JANET_SYSOP_BOR},
|
||||
{"branch", JANET_SYSOP_BRANCH},
|
||||
{"branch-not", JANET_SYSOP_BRANCH_NOT},
|
||||
{"bxor", JANET_SYSOP_BXOR},
|
||||
{"call", JANET_SYSOP_CALL},
|
||||
{"cast", JANET_SYSOP_CAST},
|
||||
@ -180,6 +184,7 @@ static const JanetSysInstrName sys_op_names[] = {
|
||||
{"gt", JANET_SYSOP_GT},
|
||||
{"gte", JANET_SYSOP_GTE},
|
||||
{"jump", JANET_SYSOP_JUMP},
|
||||
{"label", JANET_SYSOP_LABEL},
|
||||
{"link-name", JANET_SYSOP_LINK_NAME},
|
||||
{"load", JANET_SYSOP_LOAD},
|
||||
{"lt", JANET_SYSOP_LT},
|
||||
@ -235,7 +240,14 @@ typedef struct {
|
||||
uint32_t dest;
|
||||
uint32_t callee;
|
||||
uint32_t arg_count;
|
||||
uint32_t has_dest;
|
||||
} call;
|
||||
struct {
|
||||
uint32_t dest;
|
||||
uint32_t constant;
|
||||
uint32_t arg_count;
|
||||
uint32_t has_dest;
|
||||
} callk;
|
||||
struct {
|
||||
uint32_t dest;
|
||||
uint32_t src;
|
||||
@ -244,27 +256,16 @@ typedef struct {
|
||||
uint32_t src;
|
||||
} one;
|
||||
struct {
|
||||
union {
|
||||
uint32_t to;
|
||||
Janet temp_label;
|
||||
};
|
||||
} jump;
|
||||
struct {
|
||||
uint32_t cond;
|
||||
union {
|
||||
uint32_t to;
|
||||
Janet temp_label;
|
||||
};
|
||||
} branch;
|
||||
struct {
|
||||
uint32_t dest;
|
||||
uint32_t constant;
|
||||
} constant;
|
||||
struct {
|
||||
uint32_t dest;
|
||||
uint32_t constant;
|
||||
uint32_t arg_count;
|
||||
} callk;
|
||||
struct {
|
||||
uint32_t dest_type;
|
||||
uint32_t prim;
|
||||
@ -294,6 +295,9 @@ typedef struct {
|
||||
uint32_t type;
|
||||
uint64_t fixed_count;
|
||||
} array;
|
||||
struct {
|
||||
uint32_t id;
|
||||
} label;
|
||||
};
|
||||
int32_t line;
|
||||
int32_t column;
|
||||
@ -328,12 +332,11 @@ typedef struct {
|
||||
uint32_t constant_count;
|
||||
uint32_t return_type;
|
||||
uint32_t parameter_count;
|
||||
uint32_t label_count;
|
||||
uint32_t *types;
|
||||
JanetSysInstruction *instructions;
|
||||
JanetString *register_names;
|
||||
Janet *constants;
|
||||
|
||||
/* Can/should we remove this info after initial compilation? */
|
||||
JanetTable *register_name_lookup;
|
||||
JanetTable *labels;
|
||||
} JanetSysIR;
|
||||
@ -406,16 +409,21 @@ static uint64_t instr_read_u64(Janet x, JanetSysIR *ir) {
|
||||
return janet_getuinteger64(&x, 0);
|
||||
}
|
||||
|
||||
static uint32_t instr_read_type_operand(Janet x, JanetSysIR *ir) {
|
||||
static uint32_t instr_read_type_operand(Janet x, JanetSysIR *ir, int is_definition) {
|
||||
JanetSysIRLinkage *linkage = ir->linkage;
|
||||
if (janet_checktype(x, JANET_SYMBOL)) {
|
||||
Janet check = janet_table_get(linkage->type_name_lookup, x);
|
||||
if (janet_checktype(check, JANET_NUMBER)) {
|
||||
if (is_definition) {
|
||||
janet_panicf("cannot redefine type %v", x);
|
||||
}
|
||||
return (uint32_t) janet_unwrap_number(check);
|
||||
} else {
|
||||
} else if (is_definition) {
|
||||
uint32_t operand = linkage->type_def_count++;
|
||||
janet_table_put(linkage->type_name_lookup, x, janet_wrap_number(operand));
|
||||
return operand;
|
||||
} else {
|
||||
janet_panicf("unknown type %v", x);
|
||||
}
|
||||
}
|
||||
if (!janet_checkuint(x)) janet_panicf("expected non-negative integer operand, got %v", x);
|
||||
@ -440,15 +448,13 @@ static JanetPrim instr_read_prim(Janet x) {
|
||||
}
|
||||
|
||||
static uint32_t instr_read_label(JanetSysIR *sysir, Janet x) {
|
||||
(void) sysir;
|
||||
uint32_t ret = 0;
|
||||
Janet check = janet_table_get(sysir->labels, x);
|
||||
if (!janet_checktype(check, JANET_NIL)) {
|
||||
ret = (uint32_t) janet_unwrap_number(check);
|
||||
if (janet_checktype(check, JANET_NIL)) {
|
||||
ret = sysir->label_count++;
|
||||
janet_table_put(sysir->labels, x, janet_wrap_number(ret));
|
||||
} else {
|
||||
if (janet_checktype(x, JANET_KEYWORD)) janet_panicf("unknown label %v", x);
|
||||
if (!janet_checkuint(x)) janet_panicf("expected non-negative integer label, got %v", x);
|
||||
ret = (uint32_t) janet_unwrap_number(x);
|
||||
ret = (uint32_t) janet_unwrap_number(check);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@ -465,8 +471,22 @@ static void janet_sysir_init_instructions(JanetSysIR *out, JanetView instruction
|
||||
Janet x = janet_wrap_nil();
|
||||
for (int32_t i = 0; i < instructions.len; i++) {
|
||||
x = instructions.items[i];
|
||||
/* Shorthand for labels */
|
||||
if (janet_checktype(x, JANET_KEYWORD)) {
|
||||
janet_table_put(labels, x, janet_wrap_number(janet_v_count(ir)));
|
||||
/* Check for existing label */
|
||||
JanetSysInstruction instruction;
|
||||
instruction.opcode = JANET_SYSOP_LABEL;
|
||||
instruction.line = -1;
|
||||
instruction.column = -1;
|
||||
instruction.label.id = instr_read_label(out, x);
|
||||
Janet label_id = janet_wrap_number(instruction.label.id);
|
||||
Janet check_defined = janet_table_get(labels, label_id);
|
||||
if (janet_checktype(check_defined, JANET_NIL)) {
|
||||
janet_table_put(labels, label_id, janet_wrap_number(janet_v_count(ir)));
|
||||
} else {
|
||||
janet_panicf("label %v already defined", x);
|
||||
}
|
||||
janet_v_push(ir, instruction);
|
||||
continue;
|
||||
}
|
||||
if (!janet_checktype(x, JANET_TUPLE)) {
|
||||
@ -540,7 +560,13 @@ static void janet_sysir_init_instructions(JanetSysIR *out, JanetView instruction
|
||||
break;
|
||||
case JANET_SYSOP_CALL:
|
||||
instr_assert_min_length(tuple, 2, opvalue);
|
||||
if (janet_checktype(tuple[1], JANET_NIL)) {
|
||||
instruction.call.dest = 0;
|
||||
instruction.call.has_dest = 0;
|
||||
} else {
|
||||
instruction.call.dest = instr_read_operand(tuple[1], out);
|
||||
instruction.call.has_dest = 1;
|
||||
}
|
||||
Janet c = tuple[2];
|
||||
if (janet_checktype(c, JANET_SYMBOL)) {
|
||||
instruction.callk.arg_count = janet_tuple_length(tuple) - 3;
|
||||
@ -599,14 +625,15 @@ static void janet_sysir_init_instructions(JanetSysIR *out, JanetView instruction
|
||||
janet_v_push(ir, instruction);
|
||||
break;
|
||||
case JANET_SYSOP_BRANCH:
|
||||
case JANET_SYSOP_BRANCH_NOT:
|
||||
instr_assert_length(tuple, 3, opvalue);
|
||||
instruction.branch.cond = instr_read_operand(tuple[1], out);
|
||||
instruction.branch.temp_label = tuple[2];
|
||||
instruction.branch.to = instr_read_label(out, tuple[2]);
|
||||
janet_v_push(ir, instruction);
|
||||
break;
|
||||
case JANET_SYSOP_JUMP:
|
||||
instr_assert_length(tuple, 2, opvalue);
|
||||
instruction.jump.temp_label = tuple[1];
|
||||
instruction.jump.to = instr_read_label(out, tuple[1]);
|
||||
janet_v_push(ir, instruction);
|
||||
break;
|
||||
case JANET_SYSOP_CONSTANT: {
|
||||
@ -626,22 +653,22 @@ static void janet_sysir_init_instructions(JanetSysIR *out, JanetView instruction
|
||||
}
|
||||
case JANET_SYSOP_TYPE_PRIMITIVE: {
|
||||
instr_assert_length(tuple, 3, opvalue);
|
||||
instruction.type_prim.dest_type = instr_read_type_operand(tuple[1], out);
|
||||
instruction.type_prim.dest_type = instr_read_type_operand(tuple[1], out, 1);
|
||||
instruction.type_prim.prim = instr_read_prim(tuple[2]);
|
||||
janet_v_push(ir, instruction);
|
||||
break;
|
||||
}
|
||||
case JANET_SYSOP_TYPE_POINTER: {
|
||||
instr_assert_length(tuple, 3, opvalue);
|
||||
instruction.pointer.dest_type = instr_read_type_operand(tuple[1], out);
|
||||
instruction.pointer.type = instr_read_type_operand(tuple[2], out);
|
||||
instruction.pointer.dest_type = instr_read_type_operand(tuple[1], out, 1);
|
||||
instruction.pointer.type = instr_read_type_operand(tuple[2], out, 0);
|
||||
janet_v_push(ir, instruction);
|
||||
break;
|
||||
}
|
||||
case JANET_SYSOP_TYPE_ARRAY: {
|
||||
instr_assert_length(tuple, 4, opvalue);
|
||||
instruction.array.dest_type = instr_read_type_operand(tuple[1], out);
|
||||
instruction.array.type = instr_read_type_operand(tuple[2], out);
|
||||
instruction.array.dest_type = instr_read_type_operand(tuple[1], out, 1);
|
||||
instruction.array.type = instr_read_type_operand(tuple[2], out, 0);
|
||||
instruction.array.fixed_count = instr_read_u64(tuple[3], out);
|
||||
janet_v_push(ir, instruction);
|
||||
break;
|
||||
@ -649,7 +676,7 @@ static void janet_sysir_init_instructions(JanetSysIR *out, JanetView instruction
|
||||
case JANET_SYSOP_TYPE_STRUCT:
|
||||
case JANET_SYSOP_TYPE_UNION: {
|
||||
instr_assert_min_length(tuple, 1, opvalue);
|
||||
instruction.type_types.dest_type = instr_read_type_operand(tuple[1], out);
|
||||
instruction.type_types.dest_type = instr_read_type_operand(tuple[1], out, 1);
|
||||
instruction.type_types.arg_count = janet_tuple_length(tuple) - 2;
|
||||
janet_v_push(ir, instruction);
|
||||
for (int32_t j = 2; j < janet_tuple_length(tuple); j += 3) {
|
||||
@ -663,7 +690,7 @@ static void janet_sysir_init_instructions(JanetSysIR *out, JanetView instruction
|
||||
int32_t remaining = janet_tuple_length(tuple) - j;
|
||||
if (remaining > 3) remaining = 3;
|
||||
for (int32_t k = 0; k < remaining; k++) {
|
||||
arginstr.arg.args[k] = instr_read_type_operand(tuple[j + k], out);
|
||||
arginstr.arg.args[k] = instr_read_type_operand(tuple[j + k], out, 0);
|
||||
}
|
||||
janet_v_push(ir, arginstr);
|
||||
}
|
||||
@ -672,7 +699,24 @@ static void janet_sysir_init_instructions(JanetSysIR *out, JanetView instruction
|
||||
case JANET_SYSOP_TYPE_BIND: {
|
||||
instr_assert_length(tuple, 3, opvalue);
|
||||
instruction.type_bind.dest = instr_read_operand(tuple[1], out);
|
||||
instruction.type_bind.type = instr_read_type_operand(tuple[2], out);
|
||||
instruction.type_bind.type = instr_read_type_operand(tuple[2], out, 0);
|
||||
janet_v_push(ir, instruction);
|
||||
break;
|
||||
}
|
||||
case JANET_SYSOP_LABEL: {
|
||||
instr_assert_length(tuple, 2, opvalue);
|
||||
Janet x = tuple[1];
|
||||
if (!janet_checktype(x, JANET_KEYWORD)) {
|
||||
janet_panicf("expected keyword label, got %v", x);
|
||||
}
|
||||
instruction.label.id = instr_read_label(out, x);
|
||||
Janet label_id = janet_wrap_number(instruction.label.id);
|
||||
Janet check_defined = janet_table_get(labels, label_id);
|
||||
if (janet_checktype(check_defined, JANET_NIL)) {
|
||||
janet_table_put(labels, label_id, janet_wrap_number(janet_v_count(ir)));
|
||||
} else {
|
||||
janet_panicf("label %v already defined", x);
|
||||
}
|
||||
janet_v_push(ir, instruction);
|
||||
break;
|
||||
}
|
||||
@ -705,7 +749,7 @@ static void janet_sysir_init_instructions(JanetSysIR *out, JanetView instruction
|
||||
}
|
||||
int32_t lasti = ircount - 1;
|
||||
if ((ir[lasti].opcode != JANET_SYSOP_JUMP) && (ir[lasti].opcode != JANET_SYSOP_RETURN)) {
|
||||
janet_panicf("last instruction must be jump or return, got %v", x);
|
||||
janet_panicf("last instruction must be jump or return, got %q", x);
|
||||
}
|
||||
|
||||
|
||||
@ -716,24 +760,6 @@ static void janet_sysir_init_instructions(JanetSysIR *out, JanetView instruction
|
||||
out->register_count, out->parameter_count);
|
||||
}
|
||||
|
||||
/* Fix up labels */
|
||||
for (uint32_t i = 0; i < ircount; i++) {
|
||||
JanetSysInstruction instruction = out->instructions[i];
|
||||
uint32_t label_target;
|
||||
switch (instruction.opcode) {
|
||||
default:
|
||||
break;
|
||||
case JANET_SYSOP_BRANCH:
|
||||
label_target = instr_read_label(out, instruction.branch.temp_label);
|
||||
out->instructions[i].branch.to = label_target;
|
||||
break;
|
||||
case JANET_SYSOP_JUMP:
|
||||
label_target = instr_read_label(out, instruction.jump.temp_label);
|
||||
out->instructions[i].jump.to = label_target;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Build constants */
|
||||
out->constant_count = next_constant;
|
||||
out->constants = next_constant ? janet_malloc(sizeof(Janet) * out->constant_count) : NULL;
|
||||
@ -986,6 +1012,7 @@ static int tcheck_cast_type(JanetSysIR *sysir, uint32_t td, uint32_t ts) {
|
||||
case JANET_PRIM_UNKNOWN:
|
||||
case JANET_PRIM_ARRAY:
|
||||
case JANET_PRIM_POINTER:
|
||||
case JANET_PRIM_VOID:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -1069,7 +1096,7 @@ static void tcheck_pointer_math(JanetSysIR *sysir, uint32_t dest, uint32_t lhs,
|
||||
static JanetString rname(JanetSysIR *sysir, uint32_t regid) {
|
||||
JanetString name = sysir->register_names[regid];
|
||||
if (NULL == name) {
|
||||
return janet_formatc("value%u", regid);
|
||||
return janet_formatc("value[%u]", regid);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
@ -1150,6 +1177,7 @@ static void janet_sysir_type_check(JanetSysIR *sysir) {
|
||||
tcheck_pointer(sysir, sysir->types[instruction.two.dest]);
|
||||
break;
|
||||
case JANET_SYSOP_BRANCH:
|
||||
case JANET_SYSOP_BRANCH_NOT:
|
||||
tcheck_boolean(sysir, sysir->types[instruction.branch.cond]);
|
||||
if (instruction.branch.to >= sysir->instruction_count) {
|
||||
janet_panicf("label outside of range [0, %u), got %u", sysir->instruction_count, instruction.branch.to);
|
||||
@ -1201,12 +1229,8 @@ static void janet_sysir_type_check(JanetSysIR *sysir) {
|
||||
case JANET_SYSOP_ARG:
|
||||
case JANET_SYSOP_LINK_NAME:
|
||||
case JANET_SYSOP_PARAMETER_COUNT:
|
||||
break;
|
||||
case JANET_SYSOP_JUMP:
|
||||
;
|
||||
if (instruction.jump.to >= sysir->instruction_count) {
|
||||
janet_panicf("label outside of range [0, %u), got %u", sysir->instruction_count, instruction.jump.to);
|
||||
}
|
||||
case JANET_SYSOP_LABEL:
|
||||
break;
|
||||
case JANET_SYSOP_RETURN: {
|
||||
uint32_t ret_type = sysir->types[instruction.one.src];
|
||||
@ -1279,10 +1303,8 @@ static void janet_sysir_type_check(JanetSysIR *sysir) {
|
||||
tcheck_pointer(sysir, sysir->types[instruction.two.dest]);
|
||||
break;
|
||||
case JANET_SYSOP_BRANCH:
|
||||
case JANET_SYSOP_BRANCH_NOT:
|
||||
tcheck_boolean(sysir, sysir->types[instruction.branch.cond]);
|
||||
if (instruction.branch.to >= sysir->instruction_count) {
|
||||
janet_panicf("label outside of range [0, %u), got %u", sysir->instruction_count, instruction.branch.to);
|
||||
}
|
||||
break;
|
||||
case JANET_SYSOP_CONSTANT:
|
||||
tcheck_constant(sysir, instruction.constant.dest, sysir->constants[instruction.constant.constant]);
|
||||
@ -1492,23 +1514,9 @@ void janet_sys_ir_lower_to_c(JanetSysIRLinkage *linkage, JanetBuffer *buffer) {
|
||||
/* Emit body */
|
||||
for (uint32_t i = 0; i < ir->instruction_count; i++) {
|
||||
JanetSysInstruction instruction = ir->instructions[i];
|
||||
/* Skip instruction label for some opcodes */
|
||||
switch (instruction.opcode) {
|
||||
case JANET_SYSOP_TYPE_PRIMITIVE:
|
||||
case JANET_SYSOP_TYPE_BIND:
|
||||
case JANET_SYSOP_TYPE_STRUCT:
|
||||
case JANET_SYSOP_TYPE_UNION:
|
||||
case JANET_SYSOP_TYPE_POINTER:
|
||||
case JANET_SYSOP_TYPE_ARRAY:
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
janet_formatb(buffer, "_i%u:\n", i);
|
||||
if (instruction.line > 0) {
|
||||
janet_formatb(buffer, "#line %d\n ", instruction.line);
|
||||
}
|
||||
janet_buffer_push_cstring(buffer, " ");
|
||||
switch (instruction.opcode) {
|
||||
case JANET_SYSOP_TYPE_PRIMITIVE:
|
||||
case JANET_SYSOP_TYPE_BIND:
|
||||
@ -1520,6 +1528,10 @@ void janet_sys_ir_lower_to_c(JanetSysIRLinkage *linkage, JanetBuffer *buffer) {
|
||||
case JANET_SYSOP_LINK_NAME:
|
||||
case JANET_SYSOP_PARAMETER_COUNT:
|
||||
break;
|
||||
case JANET_SYSOP_LABEL: {
|
||||
janet_formatb(buffer, "\n_label_%u:\n", instruction.label.id);
|
||||
break;
|
||||
}
|
||||
case JANET_SYSOP_CONSTANT: {
|
||||
uint32_t cast = ir->types[instruction.two.dest];
|
||||
janet_formatb(buffer, " _r%u = (_t%u) %j;\n", instruction.two.dest, cast, ir->constants[instruction.two.src]);
|
||||
@ -1529,10 +1541,13 @@ void janet_sys_ir_lower_to_c(JanetSysIRLinkage *linkage, JanetBuffer *buffer) {
|
||||
janet_formatb(buffer, " _r%u = (char *) &_r%u;\n", instruction.two.dest, instruction.two.src);
|
||||
break;
|
||||
case JANET_SYSOP_JUMP:
|
||||
janet_formatb(buffer, "goto _i%u;\n", instruction.jump.to);
|
||||
janet_formatb(buffer, " goto _label_%u;\n", instruction.jump.to);
|
||||
break;
|
||||
case JANET_SYSOP_BRANCH:
|
||||
janet_formatb(buffer, "if (_r%u) goto _i%u;\n", instruction.branch.cond, instruction.branch.to);
|
||||
janet_formatb(buffer, " if (_r%u) goto _label_%u;\n", instruction.branch.cond, instruction.branch.to);
|
||||
break;
|
||||
case JANET_SYSOP_BRANCH_NOT:
|
||||
janet_formatb(buffer, " if (!_r%u) goto _label_%u;\n", instruction.branch.cond, instruction.branch.to);
|
||||
break;
|
||||
case JANET_SYSOP_RETURN:
|
||||
janet_formatb(buffer, " return _r%u;\n", instruction.one.src);
|
||||
@ -1584,25 +1599,34 @@ void janet_sys_ir_lower_to_c(JanetSysIRLinkage *linkage, JanetBuffer *buffer) {
|
||||
case JANET_SYSOP_SHR:
|
||||
EMITBINOP(">>");
|
||||
break;
|
||||
case JANET_SYSOP_CALL:
|
||||
case JANET_SYSOP_CALL: {
|
||||
if (instruction.call.has_dest) {
|
||||
janet_formatb(buffer, " _r%u = _r%u(", instruction.call.dest, instruction.call.callee);
|
||||
} else {
|
||||
janet_formatb(buffer, " _r%u(", instruction.call.callee);
|
||||
}
|
||||
for (uint32_t j = 0; j < instruction.call.arg_count; j++) {
|
||||
uint32_t offset = j / 3 + 1;
|
||||
uint32_t index = j % 3;
|
||||
JanetSysInstruction arg_instruction = ir->instructions[i + offset];
|
||||
janet_formatb(buffer, j ? ", _r%u" : "_r%u", arg_instruction.arg.args[index]);
|
||||
}
|
||||
janet_formatb(buffer, ");\n");
|
||||
janet_formatb(buffer, "); // CALL\n");
|
||||
break;
|
||||
}
|
||||
case JANET_SYSOP_CALLK:
|
||||
janet_formatb(buffer, "_r%u = %j(", instruction.callk.dest, ir->constants[instruction.callk.constant]);
|
||||
if (instruction.callk.has_dest) {
|
||||
janet_formatb(buffer, " _r%u = %v(", instruction.callk.dest, ir->constants[instruction.callk.constant]);
|
||||
} else {
|
||||
janet_formatb(buffer, " %v(", ir->constants[instruction.callk.constant]);
|
||||
}
|
||||
for (uint32_t j = 0; j < instruction.callk.arg_count; j++) {
|
||||
uint32_t offset = j / 3 + 1;
|
||||
uint32_t index = j % 3;
|
||||
JanetSysInstruction arg_instruction = ir->instructions[i + offset];
|
||||
janet_formatb(buffer, j ? ", _r%u" : "_r%u", arg_instruction.arg.args[index]);
|
||||
}
|
||||
janet_formatb(buffer, ");\n");
|
||||
janet_formatb(buffer, "); // CALLK\n");
|
||||
break;
|
||||
case JANET_SYSOP_CAST: {
|
||||
uint32_t to = ir->types[instruction.two.dest];
|
||||
|
Loading…
Reference in New Issue
Block a user