1
0
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:
Calvin Rose 2024-06-02 09:43:33 -05:00
parent 8a394f2506
commit 480c5b5e9d
2 changed files with 236 additions and 117 deletions

View File

@ -45,7 +45,8 @@
t) t)
(defn setup-default-types (defn setup-default-types
[into] [ctx]
(def into @[])
(defn add-prim-type (defn add-prim-type
[name native-name] [name native-name]
(array/push into ~(type-prim ,name ,native-name)) (array/push into ~(type-prim ,name ,native-name))
@ -54,7 +55,9 @@
(add-prim-type 'double 'f64) (add-prim-type 'double 'f64)
(add-prim-type 'int 's32) (add-prim-type 'int 's32)
(add-prim-type 'pointer 'pointer) (add-prim-type 'pointer 'pointer)
(add-prim-type 'boolean 'boolean)) (add-prim-type 'boolean 'boolean)
(sysir/asm ctx into)
ctx)
(defn type-extract (defn type-extract
"Given a symbol:type combination, extract the proper name and the type separately" "Given a symbol:type combination, extract the proper name and the type separately"
@ -66,9 +69,13 @@
(var do-binop nil) (var do-binop nil)
(var do-comp nil) (var do-comp nil)
###
### Inside functions
###
(defn visit1 (defn visit1
"Take in a form and compile code and put it into `into`. Return result slot." "Take in a form and compile code and put it into `into`. Return result slot."
[code into] [code into &opt no-return]
(cond (cond
# Compile a constant # Compile a constant
@ -79,6 +86,14 @@
(array/push into ~(constant ,slot ,code)) (array/push into ~(constant ,slot ,code))
slot) 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 # Binding
(symbol? code) (symbol? code)
(named-slot code) (named-slot code)
@ -136,13 +151,27 @@
(array/push into ~(move ,slot ,result)) (array/push into ~(move ,slot ,result))
slot) 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 # Assignment
'set 'set
(do (do
(assert (= 2 (length args))) (assert (= 2 (length args)))
(def [to x] args) (def [to x] args)
(def result (visit1 x into)) (def result (visit1 x into))
(def toslot (get-slot to)) (def toslot (named-slot to))
(array/push into ~(move ,toslot ,result)) (array/push into ~(move ,toslot ,result))
toslot) toslot)
@ -160,9 +189,24 @@
# Sequence of operations # Sequence of operations
'do 'do
(do (do
(var ret nil) (each form (slice args 0 -2) (visit1 form into true))
(each form args (set ret (visit1 form into))) (visit1 (last args) into))
ret)
# 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 # Branch
'if 'if
@ -186,7 +230,7 @@
# Assume function call # Assume function call
(do (do
(def slots @[]) (def slots @[])
(def ret (get-slot)) (def ret (if no-return nil (get-slot)))
(each arg args (each arg args
(array/push slots (visit1 arg into))) (array/push slots (visit1 arg into)))
(array/push into ~(call ,ret ,op ,;slots)) (array/push into ~(call ,ret ,op ,;slots))
@ -235,28 +279,79 @@
(set left right)) (set left right))
result) 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 (def myprog
'(do '(defn myprog []
(def xyz:int (+ 1 2 3)) (def xyz:int (+ 1 2 3))
(def abc:int (* 4 5 6)) (def abc:int (* 4 5 6))
(def x:boolean (= 5 7)) (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)))) (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 (defn dotest
[] []
(def ctx (sysir/context)) (def ctx (sysir/context))
(def ir-asm (setup-default-types ctx)
@['(link-name "main") #(top ctx myprog)
'(parameter-count 0)]) (top ctx doloop)
(setup-default-types ir-asm) (top ctx main-fn)
(visit1 myprog ir-asm)
(eprintf "%.99M" ir-asm)
(sysir/asm ctx ir-asm)
(print (sysir/to-c ctx))) (print (sysir/to-c ctx)))
(dotest) (dotest)

View File

@ -51,7 +51,7 @@
* [x] support for stack allocation of arrays * [x] support for stack allocation of arrays
* [ ] more math intrinsics * [ ] more math intrinsics
* [x] source mapping (using built in Janet source mapping metadata on tuples) * [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 * [ ] (typed) function pointer types and remove calling untyped pointers
* [x] APL array semantics for binary operands (maybe?) * [x] APL array semantics for binary operands (maybe?)
* [ ] a few built-in array combinators (maybe?) * [ ] a few built-in array combinators (maybe?)
@ -66,7 +66,6 @@
#include <janet.h> #include <janet.h>
#include "util.h" #include "util.h"
#include "vector.h" #include "vector.h"
#include <math.h>
#endif #endif
typedef enum { typedef enum {
@ -85,6 +84,7 @@ typedef enum {
JANET_PRIM_STRUCT, JANET_PRIM_STRUCT,
JANET_PRIM_UNION, JANET_PRIM_UNION,
JANET_PRIM_ARRAY, JANET_PRIM_ARRAY,
JANET_PRIM_VOID,
JANET_PRIM_UNKNOWN JANET_PRIM_UNKNOWN
} JanetPrim; } JanetPrim;
@ -109,6 +109,7 @@ static const JanetPrimName prim_names[] = {
{"u64", JANET_PRIM_U64}, {"u64", JANET_PRIM_U64},
{"u8", JANET_PRIM_U8}, {"u8", JANET_PRIM_U8},
{"union", JANET_PRIM_UNION}, {"union", JANET_PRIM_UNION},
{"void", JANET_PRIM_VOID},
}; };
typedef enum { typedef enum {
@ -139,6 +140,7 @@ typedef enum {
JANET_SYSOP_RETURN, JANET_SYSOP_RETURN,
JANET_SYSOP_JUMP, JANET_SYSOP_JUMP,
JANET_SYSOP_BRANCH, JANET_SYSOP_BRANCH,
JANET_SYSOP_BRANCH_NOT,
JANET_SYSOP_ADDRESS, JANET_SYSOP_ADDRESS,
JANET_SYSOP_CALLK, JANET_SYSOP_CALLK,
JANET_SYSOP_TYPE_PRIMITIVE, JANET_SYSOP_TYPE_PRIMITIVE,
@ -153,6 +155,7 @@ typedef enum {
JANET_SYSOP_TYPE_UNION, JANET_SYSOP_TYPE_UNION,
JANET_SYSOP_POINTER_ADD, JANET_SYSOP_POINTER_ADD,
JANET_SYSOP_POINTER_SUBTRACT, JANET_SYSOP_POINTER_SUBTRACT,
JANET_SYSOP_LABEL
} JanetSysOp; } JanetSysOp;
typedef struct { typedef struct {
@ -170,6 +173,7 @@ static const JanetSysInstrName sys_op_names[] = {
{"bnot", JANET_SYSOP_BNOT}, {"bnot", JANET_SYSOP_BNOT},
{"bor", JANET_SYSOP_BOR}, {"bor", JANET_SYSOP_BOR},
{"branch", JANET_SYSOP_BRANCH}, {"branch", JANET_SYSOP_BRANCH},
{"branch-not", JANET_SYSOP_BRANCH_NOT},
{"bxor", JANET_SYSOP_BXOR}, {"bxor", JANET_SYSOP_BXOR},
{"call", JANET_SYSOP_CALL}, {"call", JANET_SYSOP_CALL},
{"cast", JANET_SYSOP_CAST}, {"cast", JANET_SYSOP_CAST},
@ -180,6 +184,7 @@ static const JanetSysInstrName sys_op_names[] = {
{"gt", JANET_SYSOP_GT}, {"gt", JANET_SYSOP_GT},
{"gte", JANET_SYSOP_GTE}, {"gte", JANET_SYSOP_GTE},
{"jump", JANET_SYSOP_JUMP}, {"jump", JANET_SYSOP_JUMP},
{"label", JANET_SYSOP_LABEL},
{"link-name", JANET_SYSOP_LINK_NAME}, {"link-name", JANET_SYSOP_LINK_NAME},
{"load", JANET_SYSOP_LOAD}, {"load", JANET_SYSOP_LOAD},
{"lt", JANET_SYSOP_LT}, {"lt", JANET_SYSOP_LT},
@ -235,7 +240,14 @@ typedef struct {
uint32_t dest; uint32_t dest;
uint32_t callee; uint32_t callee;
uint32_t arg_count; uint32_t arg_count;
uint32_t has_dest;
} call; } call;
struct {
uint32_t dest;
uint32_t constant;
uint32_t arg_count;
uint32_t has_dest;
} callk;
struct { struct {
uint32_t dest; uint32_t dest;
uint32_t src; uint32_t src;
@ -244,27 +256,16 @@ typedef struct {
uint32_t src; uint32_t src;
} one; } one;
struct { struct {
union { uint32_t to;
uint32_t to;
Janet temp_label;
};
} jump; } jump;
struct { struct {
uint32_t cond; uint32_t cond;
union { uint32_t to;
uint32_t to;
Janet temp_label;
};
} branch; } branch;
struct { struct {
uint32_t dest; uint32_t dest;
uint32_t constant; uint32_t constant;
} constant; } constant;
struct {
uint32_t dest;
uint32_t constant;
uint32_t arg_count;
} callk;
struct { struct {
uint32_t dest_type; uint32_t dest_type;
uint32_t prim; uint32_t prim;
@ -294,6 +295,9 @@ typedef struct {
uint32_t type; uint32_t type;
uint64_t fixed_count; uint64_t fixed_count;
} array; } array;
struct {
uint32_t id;
} label;
}; };
int32_t line; int32_t line;
int32_t column; int32_t column;
@ -328,12 +332,11 @@ typedef struct {
uint32_t constant_count; uint32_t constant_count;
uint32_t return_type; uint32_t return_type;
uint32_t parameter_count; uint32_t parameter_count;
uint32_t label_count;
uint32_t *types; uint32_t *types;
JanetSysInstruction *instructions; JanetSysInstruction *instructions;
JanetString *register_names; JanetString *register_names;
Janet *constants; Janet *constants;
/* Can/should we remove this info after initial compilation? */
JanetTable *register_name_lookup; JanetTable *register_name_lookup;
JanetTable *labels; JanetTable *labels;
} JanetSysIR; } JanetSysIR;
@ -406,16 +409,21 @@ static uint64_t instr_read_u64(Janet x, JanetSysIR *ir) {
return janet_getuinteger64(&x, 0); 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; JanetSysIRLinkage *linkage = ir->linkage;
if (janet_checktype(x, JANET_SYMBOL)) { if (janet_checktype(x, JANET_SYMBOL)) {
Janet check = janet_table_get(linkage->type_name_lookup, x); Janet check = janet_table_get(linkage->type_name_lookup, x);
if (janet_checktype(check, JANET_NUMBER)) { if (janet_checktype(check, JANET_NUMBER)) {
if (is_definition) {
janet_panicf("cannot redefine type %v", x);
}
return (uint32_t) janet_unwrap_number(check); return (uint32_t) janet_unwrap_number(check);
} else { } else if (is_definition) {
uint32_t operand = linkage->type_def_count++; uint32_t operand = linkage->type_def_count++;
janet_table_put(linkage->type_name_lookup, x, janet_wrap_number(operand)); janet_table_put(linkage->type_name_lookup, x, janet_wrap_number(operand));
return operand; return operand;
} else {
janet_panicf("unknown type %v", x);
} }
} }
if (!janet_checkuint(x)) janet_panicf("expected non-negative integer operand, got %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) { static uint32_t instr_read_label(JanetSysIR *sysir, Janet x) {
(void) sysir;
uint32_t ret = 0; uint32_t ret = 0;
Janet check = janet_table_get(sysir->labels, x); Janet check = janet_table_get(sysir->labels, x);
if (!janet_checktype(check, JANET_NIL)) { if (janet_checktype(check, JANET_NIL)) {
ret = (uint32_t) janet_unwrap_number(check); ret = sysir->label_count++;
janet_table_put(sysir->labels, x, janet_wrap_number(ret));
} else { } else {
if (janet_checktype(x, JANET_KEYWORD)) janet_panicf("unknown label %v", x); ret = (uint32_t) janet_unwrap_number(check);
if (!janet_checkuint(x)) janet_panicf("expected non-negative integer label, got %v", x);
ret = (uint32_t) janet_unwrap_number(x);
} }
return ret; return ret;
} }
@ -465,8 +471,22 @@ static void janet_sysir_init_instructions(JanetSysIR *out, JanetView instruction
Janet x = janet_wrap_nil(); Janet x = janet_wrap_nil();
for (int32_t i = 0; i < instructions.len; i++) { for (int32_t i = 0; i < instructions.len; i++) {
x = instructions.items[i]; x = instructions.items[i];
/* Shorthand for labels */
if (janet_checktype(x, JANET_KEYWORD)) { 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; continue;
} }
if (!janet_checktype(x, JANET_TUPLE)) { if (!janet_checktype(x, JANET_TUPLE)) {
@ -540,7 +560,13 @@ static void janet_sysir_init_instructions(JanetSysIR *out, JanetView instruction
break; break;
case JANET_SYSOP_CALL: case JANET_SYSOP_CALL:
instr_assert_min_length(tuple, 2, opvalue); instr_assert_min_length(tuple, 2, opvalue);
instruction.call.dest = instr_read_operand(tuple[1], out); 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]; Janet c = tuple[2];
if (janet_checktype(c, JANET_SYMBOL)) { if (janet_checktype(c, JANET_SYMBOL)) {
instruction.callk.arg_count = janet_tuple_length(tuple) - 3; 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); janet_v_push(ir, instruction);
break; break;
case JANET_SYSOP_BRANCH: case JANET_SYSOP_BRANCH:
case JANET_SYSOP_BRANCH_NOT:
instr_assert_length(tuple, 3, opvalue); instr_assert_length(tuple, 3, opvalue);
instruction.branch.cond = instr_read_operand(tuple[1], out); 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); janet_v_push(ir, instruction);
break; break;
case JANET_SYSOP_JUMP: case JANET_SYSOP_JUMP:
instr_assert_length(tuple, 2, opvalue); 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); janet_v_push(ir, instruction);
break; break;
case JANET_SYSOP_CONSTANT: { case JANET_SYSOP_CONSTANT: {
@ -626,22 +653,22 @@ static void janet_sysir_init_instructions(JanetSysIR *out, JanetView instruction
} }
case JANET_SYSOP_TYPE_PRIMITIVE: { case JANET_SYSOP_TYPE_PRIMITIVE: {
instr_assert_length(tuple, 3, opvalue); 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]); instruction.type_prim.prim = instr_read_prim(tuple[2]);
janet_v_push(ir, instruction); janet_v_push(ir, instruction);
break; break;
} }
case JANET_SYSOP_TYPE_POINTER: { case JANET_SYSOP_TYPE_POINTER: {
instr_assert_length(tuple, 3, opvalue); instr_assert_length(tuple, 3, opvalue);
instruction.pointer.dest_type = instr_read_type_operand(tuple[1], out); instruction.pointer.dest_type = instr_read_type_operand(tuple[1], out, 1);
instruction.pointer.type = instr_read_type_operand(tuple[2], out); instruction.pointer.type = instr_read_type_operand(tuple[2], out, 0);
janet_v_push(ir, instruction); janet_v_push(ir, instruction);
break; break;
} }
case JANET_SYSOP_TYPE_ARRAY: { case JANET_SYSOP_TYPE_ARRAY: {
instr_assert_length(tuple, 4, opvalue); instr_assert_length(tuple, 4, opvalue);
instruction.array.dest_type = instr_read_type_operand(tuple[1], out); instruction.array.dest_type = instr_read_type_operand(tuple[1], out, 1);
instruction.array.type = instr_read_type_operand(tuple[2], out); instruction.array.type = instr_read_type_operand(tuple[2], out, 0);
instruction.array.fixed_count = instr_read_u64(tuple[3], out); instruction.array.fixed_count = instr_read_u64(tuple[3], out);
janet_v_push(ir, instruction); janet_v_push(ir, instruction);
break; break;
@ -649,7 +676,7 @@ static void janet_sysir_init_instructions(JanetSysIR *out, JanetView instruction
case JANET_SYSOP_TYPE_STRUCT: case JANET_SYSOP_TYPE_STRUCT:
case JANET_SYSOP_TYPE_UNION: { case JANET_SYSOP_TYPE_UNION: {
instr_assert_min_length(tuple, 1, opvalue); 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; instruction.type_types.arg_count = janet_tuple_length(tuple) - 2;
janet_v_push(ir, instruction); janet_v_push(ir, instruction);
for (int32_t j = 2; j < janet_tuple_length(tuple); j += 3) { 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; int32_t remaining = janet_tuple_length(tuple) - j;
if (remaining > 3) remaining = 3; if (remaining > 3) remaining = 3;
for (int32_t k = 0; k < remaining; k++) { 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); janet_v_push(ir, arginstr);
} }
@ -672,7 +699,24 @@ static void janet_sysir_init_instructions(JanetSysIR *out, JanetView instruction
case JANET_SYSOP_TYPE_BIND: { case JANET_SYSOP_TYPE_BIND: {
instr_assert_length(tuple, 3, opvalue); instr_assert_length(tuple, 3, opvalue);
instruction.type_bind.dest = instr_read_operand(tuple[1], out); 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); janet_v_push(ir, instruction);
break; break;
} }
@ -705,7 +749,7 @@ static void janet_sysir_init_instructions(JanetSysIR *out, JanetView instruction
} }
int32_t lasti = ircount - 1; int32_t lasti = ircount - 1;
if ((ir[lasti].opcode != JANET_SYSOP_JUMP) && (ir[lasti].opcode != JANET_SYSOP_RETURN)) { 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); 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 */ /* Build constants */
out->constant_count = next_constant; out->constant_count = next_constant;
out->constants = next_constant ? janet_malloc(sizeof(Janet) * out->constant_count) : NULL; 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_UNKNOWN:
case JANET_PRIM_ARRAY: case JANET_PRIM_ARRAY:
case JANET_PRIM_POINTER: case JANET_PRIM_POINTER:
case JANET_PRIM_VOID:
return -1; 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) { static JanetString rname(JanetSysIR *sysir, uint32_t regid) {
JanetString name = sysir->register_names[regid]; JanetString name = sysir->register_names[regid];
if (NULL == name) { if (NULL == name) {
return janet_formatc("value%u", regid); return janet_formatc("value[%u]", regid);
} }
return name; return name;
} }
@ -1150,6 +1177,7 @@ static void janet_sysir_type_check(JanetSysIR *sysir) {
tcheck_pointer(sysir, sysir->types[instruction.two.dest]); tcheck_pointer(sysir, sysir->types[instruction.two.dest]);
break; break;
case JANET_SYSOP_BRANCH: case JANET_SYSOP_BRANCH:
case JANET_SYSOP_BRANCH_NOT:
tcheck_boolean(sysir, sysir->types[instruction.branch.cond]); tcheck_boolean(sysir, sysir->types[instruction.branch.cond]);
if (instruction.branch.to >= sysir->instruction_count) { if (instruction.branch.to >= sysir->instruction_count) {
janet_panicf("label outside of range [0, %u), got %u", sysir->instruction_count, instruction.branch.to); 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_ARG:
case JANET_SYSOP_LINK_NAME: case JANET_SYSOP_LINK_NAME:
case JANET_SYSOP_PARAMETER_COUNT: case JANET_SYSOP_PARAMETER_COUNT:
break;
case JANET_SYSOP_JUMP: case JANET_SYSOP_JUMP:
; case JANET_SYSOP_LABEL:
if (instruction.jump.to >= sysir->instruction_count) {
janet_panicf("label outside of range [0, %u), got %u", sysir->instruction_count, instruction.jump.to);
}
break; break;
case JANET_SYSOP_RETURN: { case JANET_SYSOP_RETURN: {
uint32_t ret_type = sysir->types[instruction.one.src]; 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]); tcheck_pointer(sysir, sysir->types[instruction.two.dest]);
break; break;
case JANET_SYSOP_BRANCH: case JANET_SYSOP_BRANCH:
case JANET_SYSOP_BRANCH_NOT:
tcheck_boolean(sysir, sysir->types[instruction.branch.cond]); 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; break;
case JANET_SYSOP_CONSTANT: case JANET_SYSOP_CONSTANT:
tcheck_constant(sysir, instruction.constant.dest, sysir->constants[instruction.constant.constant]); tcheck_constant(sysir, instruction.constant.dest, sysir->constants[instruction.constant.constant]);
@ -1388,7 +1410,7 @@ static void emit_binop(JanetSysIR *ir, JanetBuffer *buffer, JanetBuffer *tempbuf
/* Add nested for loops for any dimensionality of array */ /* Add nested for loops for any dimensionality of array */
while (linkage->type_defs[operand_type].prim == JANET_PRIM_ARRAY) { while (linkage->type_defs[operand_type].prim == JANET_PRIM_ARRAY) {
janet_formatb(buffer, "for (size_t _j%u = 0; _j%u < %u; _j%u++) ", janet_formatb(buffer, " for (size_t _j%u = 0; _j%u < %u; _j%u++) ",
index_index, index_index, index_index, index_index,
linkage->type_defs[operand_type].array.fixed_count, linkage->type_defs[operand_type].array.fixed_count,
index_index); index_index);
@ -1403,14 +1425,14 @@ static void emit_binop(JanetSysIR *ir, JanetBuffer *buffer, JanetBuffer *tempbuf
} }
if (is_pointer) { if (is_pointer) {
janet_formatb(buffer, "*_r%u = *_r%u %s *_r%u;\n", janet_formatb(buffer, " *_r%u = *_r%u %s *_r%u;\n",
instruction.three.dest, instruction.three.dest,
instruction.three.lhs, instruction.three.lhs,
op, op,
instruction.three.rhs); instruction.three.rhs);
} else { } else {
Janet index_part = janet_wrap_buffer(tempbuf); Janet index_part = janet_wrap_buffer(tempbuf);
janet_formatb(buffer, "_r%u%V = _r%u%V %s _r%u%V;\n", janet_formatb(buffer, " _r%u%V = _r%u%V %s _r%u%V;\n",
instruction.three.dest, index_part, instruction.three.dest, index_part,
instruction.three.lhs, index_part, instruction.three.lhs, index_part,
op, op,
@ -1492,23 +1514,9 @@ void janet_sys_ir_lower_to_c(JanetSysIRLinkage *linkage, JanetBuffer *buffer) {
/* Emit body */ /* Emit body */
for (uint32_t i = 0; i < ir->instruction_count; i++) { for (uint32_t i = 0; i < ir->instruction_count; i++) {
JanetSysInstruction instruction = ir->instructions[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) { if (instruction.line > 0) {
janet_formatb(buffer, "#line %d\n ", instruction.line); janet_formatb(buffer, "#line %d\n ", instruction.line);
} }
janet_buffer_push_cstring(buffer, " ");
switch (instruction.opcode) { switch (instruction.opcode) {
case JANET_SYSOP_TYPE_PRIMITIVE: case JANET_SYSOP_TYPE_PRIMITIVE:
case JANET_SYSOP_TYPE_BIND: case JANET_SYSOP_TYPE_BIND:
@ -1520,22 +1528,29 @@ void janet_sys_ir_lower_to_c(JanetSysIRLinkage *linkage, JanetBuffer *buffer) {
case JANET_SYSOP_LINK_NAME: case JANET_SYSOP_LINK_NAME:
case JANET_SYSOP_PARAMETER_COUNT: case JANET_SYSOP_PARAMETER_COUNT:
break; break;
case JANET_SYSOP_LABEL: {
janet_formatb(buffer, "\n_label_%u:\n", instruction.label.id);
break;
}
case JANET_SYSOP_CONSTANT: { case JANET_SYSOP_CONSTANT: {
uint32_t cast = ir->types[instruction.two.dest]; 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]); janet_formatb(buffer, " _r%u = (_t%u) %j;\n", instruction.two.dest, cast, ir->constants[instruction.two.src]);
break; break;
} }
case JANET_SYSOP_ADDRESS: case JANET_SYSOP_ADDRESS:
janet_formatb(buffer, "_r%u = (char *) &_r%u;\n", instruction.two.dest, instruction.two.src); janet_formatb(buffer, " _r%u = (char *) &_r%u;\n", instruction.two.dest, instruction.two.src);
break; break;
case JANET_SYSOP_JUMP: 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; break;
case JANET_SYSOP_BRANCH: 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; break;
case JANET_SYSOP_RETURN: case JANET_SYSOP_RETURN:
janet_formatb(buffer, "return _r%u;\n", instruction.one.src); janet_formatb(buffer, " return _r%u;\n", instruction.one.src);
break; break;
case JANET_SYSOP_ADD: case JANET_SYSOP_ADD:
case JANET_SYSOP_POINTER_ADD: case JANET_SYSOP_POINTER_ADD:
@ -1584,51 +1599,60 @@ void janet_sys_ir_lower_to_c(JanetSysIRLinkage *linkage, JanetBuffer *buffer) {
case JANET_SYSOP_SHR: case JANET_SYSOP_SHR:
EMITBINOP(">>"); EMITBINOP(">>");
break; break;
case JANET_SYSOP_CALL: case JANET_SYSOP_CALL: {
janet_formatb(buffer, "_r%u = _r%u(", instruction.call.dest, instruction.call.callee); 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++) { for (uint32_t j = 0; j < instruction.call.arg_count; j++) {
uint32_t offset = j / 3 + 1; uint32_t offset = j / 3 + 1;
uint32_t index = j % 3; uint32_t index = j % 3;
JanetSysInstruction arg_instruction = ir->instructions[i + offset]; JanetSysInstruction arg_instruction = ir->instructions[i + offset];
janet_formatb(buffer, j ? ", _r%u" : "_r%u", arg_instruction.arg.args[index]); janet_formatb(buffer, j ? ", _r%u" : "_r%u", arg_instruction.arg.args[index]);
} }
janet_formatb(buffer, ");\n"); janet_formatb(buffer, "); // CALL\n");
break; break;
}
case JANET_SYSOP_CALLK: 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++) { for (uint32_t j = 0; j < instruction.callk.arg_count; j++) {
uint32_t offset = j / 3 + 1; uint32_t offset = j / 3 + 1;
uint32_t index = j % 3; uint32_t index = j % 3;
JanetSysInstruction arg_instruction = ir->instructions[i + offset]; JanetSysInstruction arg_instruction = ir->instructions[i + offset];
janet_formatb(buffer, j ? ", _r%u" : "_r%u", arg_instruction.arg.args[index]); janet_formatb(buffer, j ? ", _r%u" : "_r%u", arg_instruction.arg.args[index]);
} }
janet_formatb(buffer, ");\n"); janet_formatb(buffer, "); // CALLK\n");
break; break;
case JANET_SYSOP_CAST: { case JANET_SYSOP_CAST: {
uint32_t to = ir->types[instruction.two.dest]; uint32_t to = ir->types[instruction.two.dest];
janet_formatb(buffer, "_r%u = (_t%u) (_r%u);\n", instruction.two.dest, to, instruction.two.src); janet_formatb(buffer, " _r%u = (_t%u) (_r%u);\n", instruction.two.dest, to, instruction.two.src);
break; break;
} }
case JANET_SYSOP_MOVE: case JANET_SYSOP_MOVE:
janet_formatb(buffer, "_r%u = _r%u;\n", instruction.two.dest, instruction.two.src); janet_formatb(buffer, " _r%u = _r%u;\n", instruction.two.dest, instruction.two.src);
break; break;
case JANET_SYSOP_BNOT: case JANET_SYSOP_BNOT:
janet_formatb(buffer, "_r%u = ~_r%u;\n", instruction.two.dest, instruction.two.src); janet_formatb(buffer, " _r%u = ~_r%u;\n", instruction.two.dest, instruction.two.src);
break; break;
case JANET_SYSOP_LOAD: case JANET_SYSOP_LOAD:
janet_formatb(buffer, "_r%u = *(_r%u);\n", instruction.two.dest, instruction.two.src); janet_formatb(buffer, " _r%u = *(_r%u);\n", instruction.two.dest, instruction.two.src);
break; break;
case JANET_SYSOP_STORE: case JANET_SYSOP_STORE:
janet_formatb(buffer, "*(_r%u) = _r%u;\n", instruction.two.dest, instruction.two.src); janet_formatb(buffer, " *(_r%u) = _r%u;\n", instruction.two.dest, instruction.two.src);
break; break;
case JANET_SYSOP_FIELD_GETP: case JANET_SYSOP_FIELD_GETP:
janet_formatb(buffer, "_r%u = &(_r%u._f%u);\n", instruction.field.r, instruction.field.st, instruction.field.field); janet_formatb(buffer, " _r%u = &(_r%u._f%u);\n", instruction.field.r, instruction.field.st, instruction.field.field);
break; break;
case JANET_SYSOP_ARRAY_GETP: case JANET_SYSOP_ARRAY_GETP:
janet_formatb(buffer, "_r%u = &(_r%u.els[_r%u]);\n", instruction.three.dest, instruction.three.lhs, instruction.three.rhs); janet_formatb(buffer, " _r%u = &(_r%u.els[_r%u]);\n", instruction.three.dest, instruction.three.lhs, instruction.three.rhs);
break; break;
case JANET_SYSOP_ARRAY_PGETP: case JANET_SYSOP_ARRAY_PGETP:
janet_formatb(buffer, "_r%u = &(_r%u->els[_r%u]);\n", instruction.three.dest, instruction.three.lhs, instruction.three.rhs); janet_formatb(buffer, " _r%u = &(_r%u->els[_r%u]);\n", instruction.three.dest, instruction.three.lhs, instruction.three.rhs);
break; break;
} }
} }