12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904 |
- #include "minilisp.h"
- #include "reader.h"
- #include "writer.h"
- #include "alloc.h"
- #include "compiler_new.h"
- #include "stream.h"
- //#include "utf8.c"
- #define env_t StrMap
- static env_t* global_env = NULL;
- //#define CHECK_BOUNDS // enforce boundaries of array put/get
- #ifdef CPU_X86
- #define ARG_SPILLOVER 0
- #else
- #define ARG_SPILLOVER 3 // max 4 args via regs, rest via stack
- #endif
- #define LBDREG R4 // register base used for passing args to functions
- #define DEBUG_ASM_SRC
- static int debug_mode = 0;
- env_entry* lookup_global_symbol(char* name) {
- env_entry* res;
- int found = sm_get(global_env, name, (void**)&res);
- //printf("[lookup] %s res: %p\n",name,res);
- if (!found) return NULL;
- return res;
- }
- Cell* insert_symbol(Cell* symbol, Cell* cell, env_t** env) {
- env_entry* e;
- int found = sm_get(*env, symbol->ar.addr, (void**)&e);
-
- if (found) {
- e->cell = cell;
- //printf("[insert_symbol] update %s entry at %p (cell: %p value: %d)\r\n",symbol->ar.addr,e,e->cell,e->cell->ar.value);
- return e->cell;
- }
-
- e = malloc(sizeof(env_entry));
- memcpy(e->name, (char*)symbol->ar.addr, symbol->dr.size);
- e->cell = cell;
- //printf("[insert_symbol] %s entry at %p (cell: %p)\r\n",symbol->ar.addr,e,e->cell);
- sm_put(*env, e->name, e);
- return e->cell;
- }
- Cell* insert_global_symbol(Cell* symbol, Cell* cell) {
- return insert_symbol(symbol, cell, &global_env);
- }
- #define TMP_PRINT_BUFSZ 1024
- static FILE* jit_out;
- static Cell* cell_heap_start;
- static int label_skip_count = 0;
- static char temp_print_buffer[TMP_PRINT_BUFSZ];
- static Cell* consed_type_error;
- static Cell* prototype_type_error;
- static Cell* prototype_nil;
- static Cell* prototype_int;
- static Cell* prototype_any;
- static Cell* prototype_void;
- static Cell* prototype_struct;
- static Cell* prototype_struct_def;
- static Cell* prototype_stream;
- static Cell* prototype_string;
- static Cell* prototype_symbol;
- static Cell* prototype_lambda;
- static Cell* prototype_cons;
- #ifdef CPU_ARM
- #include "jit_arm_raw.c"
- #define PTRSZ 4
- #endif
- #ifdef CPU_X64
- #include "jit_x64.c"
- #define PTRSZ 8
- #endif
- #ifdef CPU_X86
- #include "jit_x86.c"
- #define PTRSZ 4
- #endif
- #ifdef __AMIGA
- #include "jit_m68k.c"
- #define PTRSZ 4
- #endif
- void debug_break(Cell* arg) {
- printf("argr0: %p\r\n",arg);
- exit(0);
- }
- Cell* lisp_print(Cell* arg) {
- lisp_write(arg, temp_print_buffer, TMP_PRINT_BUFSZ);
- printf("%s\r\n",temp_print_buffer);
- return arg;
- }
- void load_int(int dreg, Arg arg, Frame* f) {
- if (arg.type == ARGT_CONST) {
- // argument is a constant like 123, "foo"
- jit_movi(dreg, (jit_word_t)arg.cell->ar.value);
- }
- else if (arg.type == ARGT_ENV) {
- // argument is an environment table entry, load e->cell->ar.value
- jit_lea(dreg, arg.env);
- jit_ldr(dreg);
- jit_ldr(dreg);
- }
- else if (arg.type == ARGT_REG) {
- // argument comes from a register
- jit_movr(dreg, arg.slot);
- jit_ldr(dreg);
- }
- else if (arg.type == ARGT_REG_INT) {
- if (dreg!=arg.slot) {
- jit_movr(dreg, arg.slot);
- }
- }
- else if (arg.type == ARGT_STACK) {
- //printf("loading int from stack slot %d + sp %d to reg %d\n",arg.slot,f->sp,dreg);
- jit_ldr_stack(dreg, PTRSZ*(f->sp-arg.slot));
- jit_ldr(dreg);
- }
- else if (arg.type == ARGT_STACK_INT) {
- //printf("loading int from stack_int sp %d - slot %d to reg %d\n",f->sp,arg.slot,dreg);
- jit_ldr_stack(dreg, PTRSZ*(f->sp-arg.slot));
- }
- else {
- jit_movi(dreg, 0xdeadbeef);
- }
- }
- void load_cell(int dreg, Arg arg, Frame* f) {
- if (arg.type == ARGT_CONST) {
- // argument is a constant like 123, "foo"
- jit_movi(dreg, (jit_word_t)arg.cell);
- }
- else if (arg.type == ARGT_ENV) {
- jit_lea(dreg, arg.env);
- jit_ldr(dreg);
- }
- else if (arg.type == ARGT_REG) {
- jit_movr(dreg, arg.slot);
- }
- else if (arg.type == ARGT_REG_INT) {
- jit_call(alloc_int, "alloc_int");
- jit_movr(dreg,R0);
- }
- else if (arg.type == ARGT_STACK) {
- //printf("loading cell from stack slot %d + sp %d to reg %d\n",arg.slot,f->sp,dreg);
- jit_ldr_stack(dreg, PTRSZ*(f->sp-arg.slot));
- }
- else if (arg.type == ARGT_STACK_INT) {
- int adjust = 0;
- //printf("loading cell from stack_int sp %d - slot %d + adjust %d = %d to reg %d\n",f->sp,arg.slot,adjust,f->sp-arg.slot+adjust,dreg);
- if (dreg!=ARGR0) {jit_push(ARGR0,ARGR0); adjust++;}
- if (dreg!=R0) {jit_push(R0,R0); adjust++;}
- jit_ldr_stack(ARGR0, PTRSZ*(f->sp-arg.slot+adjust));
- jit_call(alloc_int, "alloc_int");
- jit_movr(dreg,R0);
- if (dreg!=R0) jit_pop(R0,R0);
- if (dreg!=ARGR0) jit_pop(ARGR0,ARGR0);
- }
- else {
- printf("<load_cell unhandled arg.type: %d>\r\n",arg.type);
- jit_movi(dreg, 0xdeadcafe);
- }
- }
- int get_sym_frame_idx(char* argname, Arg* fn_frame, int ignore_regs) {
- int i;
- if (!fn_frame) return -1;
-
- for (i=0; i<MAXFRAME; i++) {
- if (fn_frame[i].name) {
- //printf("<< get_sym_frame_idx %i (type %d, reg = %d, looking for %s): %s\n",i,fn_frame[i].type,ARGT_REG,argname,fn_frame[i].name);
-
- if (!((fn_frame[i].type == ARGT_REG) && ignore_regs)) {
- if (!strcmp(argname, fn_frame[i].name)) {
- //printf("!! get_sym_frame_idx %i (type %d): %s\n",i,fn_frame[i].type,fn_frame[i].name);
- //printf("returning %d\n",i);
- return i;
- }
- }
- }
- }
- return -1;
- }
- // TODO: optimize!
- int push_frame_regs(Arg* fn_frame) {
- int pushreg=0;
- int i;
-
- if (!fn_frame) return 0;
-
- for (i=0; i<MAXFRAME; i++) {
- if (fn_frame[i].type == ARGT_REG) {
- pushreg++;
- }
- }
- //printf("pushing %d frame regs\n",pushreg);
- if (pushreg) {
- jit_push(LBDREG,LBDREG+pushreg-1);
- }
- return pushreg;
- }
- int pop_frame_regs(Arg* fn_frame) {
- int pushreg=0;
- int i;
-
- if (!fn_frame) return 0;
-
- for (i=0; i<MAXFRAME; i++) {
- if (fn_frame[i].type == ARGT_REG) {
- pushreg++;
- }
- }
- //printf("popping %d frame regs\n",pushreg);
- if (pushreg) {
- jit_pop(LBDREG,LBDREG+pushreg-1);
- }
- return pushreg;
- }
- static char* analyze_buffer[MAXFRAME];
- int analyze_fn(Cell* expr, Cell* parent, int num_lets) {
- if (expr->tag == TAG_SYM) {
- env_entry* op_env = lookup_global_symbol(expr->ar.addr);
- if (op_env) {
- Cell* op = op_env->cell;
- if (op->tag == TAG_BUILTIN) {
- //printf("analyze_fn: found builtin: %s\n",expr->ar.addr);
- if (op->ar.value == BUILTIN_LET) {
- Cell* sym = car(cdr(parent));
- if (sym) {
- int existing = 0, i;
- for (i=0; i<num_lets; i++) {
- if (!strcmp(analyze_buffer[i], sym->ar.addr)) {
- //printf("-- we already know local %s\r\n",sym->ar.addr);
- existing = 1;
- break;
- }
- }
- if (!existing) {
- analyze_buffer[num_lets] = sym->ar.addr;
- num_lets++;
- }
- } else {
- printf("<analyze_fn error: malformed let!>\r\n");
- }
- }
- }
- }
- }
- else if (expr->tag == TAG_CONS) {
- if (car(expr)) {
- num_lets = analyze_fn(car(expr), expr, num_lets);
- }
- if (cdr(expr)) {
- num_lets = analyze_fn(cdr(expr), expr, num_lets);
- }
- }
- return num_lets;
- }
- int compatible_type(int given, int required) {
- if (given == required) return 1;
- if ((given == TAG_STR || given == TAG_BYTES) &&
- (required == TAG_STR || required == TAG_BYTES)) return 1;
- return 0;
- }
- Cell* clean_return(int args_pushed, Frame* frame, Cell* compiled_type) {
- if (args_pushed) {
- jit_inc_stack(args_pushed*PTRSZ);
- frame->sp-=args_pushed;
- }
- return compiled_type;
- }
- // returns a prototype cell that can be used for type information
- Cell* compile_expr(Cell* expr, Frame* frame, Cell* return_type) {
- Cell* compiled_type = prototype_any;
- Arg* fn_frame = frame->f;
- Cell* opsym, *args, *orig_args, *signature_args, *op, *orig_op=NULL;
- env_entry* op_env;
- char* op_name;
-
- int is_let = 0;
- int argi = 0;
- int args_pushed = 0;
- Arg argdefs[MAXARGS];
- if (!expr) return 0;
- if (!frame) return 0;
-
- if (expr->tag != TAG_CONS) {
- if (expr->tag == TAG_SYM) {
- int arg_frame_idx = get_sym_frame_idx(expr->ar.addr, fn_frame, 0);
- env_entry* env;
-
- if (arg_frame_idx>=0) {
- load_cell(R0, fn_frame[arg_frame_idx], frame);
- return compiled_type;
- }
- env = lookup_global_symbol(expr->ar.addr);
- if (env) {
- Cell* value = env->cell;
- jit_movi(R0,(jit_word_t)env);
- jit_ldr(R0);
- return value; // FIXME TODO forbid later type change
- } else {
- printf("<undefined symbol %s>\r\n",(char*)expr->ar.addr);
- jit_movi(R0,0);
- return 0;
- }
- } else {
- // return the expr
- jit_movi(R0,(jit_word_t)expr);
- return compiled_type;
- }
- return 0;
- }
- cell_heap_start = get_cell_heap();
-
- opsym = car(expr);
- args = cdr(expr);
- orig_args = args; // keep around for specials forms like DO
- signature_args = NULL;
- if (!opsym || opsym->tag != TAG_SYM) {
- printf("<error: non-symbol in operator position>\r\n");
- return 0;
- }
- op_name = (char*)opsym->ar.addr;
- op_env = lookup_global_symbol(op_name);
- if (!op_env || !op_env->cell) {
- printf("<error: undefined symbol %s in operator position>\r\n",op_name);
- return 0;
- }
- op = op_env->cell;
-
- //printf("op tag: %d\n",op->tag);
- if (op->tag == TAG_BUILTIN) {
- signature_args = op->dr.next;
- if (op->ar.value == BUILTIN_LET) {
- is_let = 1;
- }
- }
- else if (op->tag == TAG_LAMBDA) {
- signature_args = car((Cell*)(op->ar.addr));
- }
- else if (op->tag == TAG_STRUCT_DEF) {
- signature_args = NULL;
- orig_op = op;
- op_env = lookup_global_symbol("new");
- op = op_env->cell;
- }
- else {
- printf("<error: non-lambda/struct symbol %s in operator position>\r\n",(char*)opsym->ar.addr);
- return 0;
- }
- //printf("[op] %s\n",debug_buf);
- //lisp_write(signature_args, debug_buf, sizeof(debug_buf));
- //printf("[sig] %s\n",debug_buf);
- #ifdef DEBUG_ASM_SRC
- char* debug_buf = malloc(256);
- lisp_write(expr, debug_buf, 255);
- jit_comment(debug_buf);
- free(debug_buf);
- #endif
- if (debug_mode) {
- char* debug_buf = malloc(256);
- push_frame_regs(frame->f);
- lisp_write(expr, debug_buf, 256);
- jit_push(R0, ARGR1);
- jit_lea(ARGR0, debug_buf);
- jit_lea(ARGR1, frame);
- jit_call(debug_handler,"dbg");
- jit_pop(R0, ARGR1);
- pop_frame_regs(frame->f);
- }
-
- // first, we need a signature
- do {
- Cell* arg = car(args);
- Cell* signature_arg = car(signature_args);
- char arg_name[32];
- snprintf(arg_name,sizeof(arg_name),"a%d",argi+1);
- // 1. is the arg the required type? i.e. a pointer or a number?
- if (signature_arg && signature_arg->tag == TAG_CONS) {
- // named argument
- snprintf(arg_name,sizeof(arg_name),"%s",(char*)(car(signature_arg)->ar.addr));
-
- //printf("named arg: %s\r\n",arg_name);
- signature_arg = cdr(signature_arg);
- }
- /*if (signature_args) {
- char dbg[256];
- lisp_write(signature_args,dbg,256);
- printf("!! %s sig: %s\r\n",opsym->ar.addr,dbg);
- }*/
- if (arg && (!signature_args || signature_arg)) {
- int given_tag = arg->tag;
- int sig_tag = 0;
- if (signature_arg) sig_tag = signature_arg->tag;
-
- if (is_let && argi==1) {
- int type_hint = -1;
- // check the symbol to see if we already have type information
- int fidx = get_sym_frame_idx(argdefs[0].cell->ar.addr, fn_frame, 1);
- if (fidx>=0) {
- //printf("existing type information for %s: %d\r\n", argdefs[0].cell->ar.addr,fn_frame[fidx].type);
- type_hint = fn_frame[fidx].type;
- }
-
- if (given_tag == TAG_INT || type_hint == ARGT_STACK_INT) {
- //printf("INT mode of let\r\n");
- // let prefers raw integers!
- sig_tag = TAG_INT;
- signature_arg = prototype_int;
- } else {
- //printf("ANY mode of let\r\n");
- // but cells are ok, too
- sig_tag = TAG_ANY;
- signature_arg = prototype_any;
- }
- }
- if (!signature_args) {
- // any number of arguments allowed
- argdefs[argi].cell = arg;
- argdefs[argi].type = ARGT_STACK;
- }
- else if (sig_tag == TAG_LAMBDA) {
- // lazy evaluation by form
- argdefs[argi].cell = arg;
- argdefs[argi].type = ARGT_LAMBDA;
- }
- else if (arg->tag == TAG_CONS) {
- // eager evaluation
- // nested expression
- Cell* cons_type = compile_expr(arg, frame, signature_arg);
- if (!cons_type) return NULL; // failure
- given_tag = cons_type->tag;
-
- argdefs[argi].cell = NULL; // cell is in R0 at runtime
- argdefs[argi].slot = ++frame->sp; // record sp at this point
- if (given_tag == TAG_INT) {
- argdefs[argi].type = ARGT_STACK_INT;
- } else {
- argdefs[argi].type = ARGT_STACK;
- }
- if (given_tag == TAG_STRUCT) {
- // struct extraction
- Cell** fields = cons_type->ar.addr;
- Cell** def_fields = fields[0]->ar.addr;
- argdefs[argi].type_name = def_fields[0]->ar.addr;
- printf("!!! nested struct name extracted: %s (arg# %d argt %d) !!!\r\n",argdefs[argi].type_name,argi,argdefs[argi].type);
- }
-
- jit_push(R0,R0);
- args_pushed++;
-
- }
- else if (given_tag == TAG_SYM && sig_tag != TAG_SYM) {
- // symbol given, lookup (indirect)
- //printf("indirect symbol lookup (name: %p)\n",arg->ar.value);
- int arg_frame_idx = get_sym_frame_idx(arg->ar.addr, fn_frame, 0);
- // argument passed to function in register
- if (arg_frame_idx>=0) {
- argdefs[argi] = fn_frame[arg_frame_idx];
- //printf("argument %s from stack frame.\n", arg->ar.addr);
- //printf("-> cell %p slot %d type %d\n", fn_frame[arg_frame_idx].cell, fn_frame[arg_frame_idx].slot, fn_frame[arg_frame_idx].type);
- } else {
- argdefs[argi].env = lookup_global_symbol((char*)arg->ar.addr);
- argdefs[argi].type = ARGT_ENV;
-
- //printf("argument %i:%s from environment.\n", argi, arg->ar.addr);
- }
- //printf("arg_frame_idx: %d\n",arg_frame_idx);
- if (!argdefs[argi].env && arg_frame_idx<0) {
- printf("<undefined symbol %s given for argument %s of %s>\r\n",(char*)arg->ar.addr,arg_name,op_name);
- return 0;
- }
- }
- else if (compatible_type(given_tag, sig_tag) || sig_tag==TAG_ANY) {
- argdefs[argi].cell = arg;
- argdefs[argi].slot = argi-1;
- argdefs[argi].type = ARGT_CONST;
- if (given_tag == TAG_SYM || given_tag == TAG_CONS || given_tag == TAG_INT || given_tag == TAG_STR || given_tag == TAG_BYTES) {
- //argdefs[argi].type = ARGT_CONST;
- }
- //printf("const arg of type %d at %p\n",arg->tag,arg);
- } else {
- // check if we can typecast
- // else, fail with type error
- printf("<type mismatch for argument %s of %s (given %s, expected %s)>\r\n",arg_name,op_name,tag_to_str(given_tag),tag_to_str(sig_tag));
- return 0;
- }
- } else {
- if (!arg && signature_arg) {
- // missing arguments
- printf("<argument %s of %s missing!>\r\n",arg_name,op_name);
- return 0;
- } else if (arg && !signature_arg) {
- // surplus arguments
- printf("<surplus arguments to %s!>\r\n",op_name);
- return 0;
- }
- }
-
- argi++;
- } while (argi<MAXARGS && (args = cdr(args)) && (!signature_args || (signature_args = cdr(signature_args))));
- // args are prepared, execute op
- if (op->tag == TAG_BUILTIN) {
- switch (op->ar.value) {
- case BUILTIN_BITAND: {
- load_int(ARGR0,argdefs[0], frame);
- load_int(R2,argdefs[1], frame);
- jit_andr(ARGR0,R2);
- if (return_type->tag == TAG_ANY) jit_call(alloc_int, "alloc_int");
- else {
- compiled_type = prototype_int;
- jit_movr(R0,ARGR0);
- }
- break;
- }
- case BUILTIN_BITNOT: {
- load_int(ARGR0,argdefs[0], frame);
- jit_notr(ARGR0);
- if (return_type->tag == TAG_ANY) jit_call(alloc_int, "alloc_int");
- else {
- compiled_type = prototype_int;
- jit_movr(R0,ARGR0);
- }
- break;
- }
- case BUILTIN_BITOR: {
- load_int(ARGR0,argdefs[0], frame);
- load_int(R2,argdefs[1], frame);
- jit_orr(ARGR0,R2);
- if (return_type->tag == TAG_ANY) jit_call(alloc_int, "alloc_int");
- else {
- compiled_type = prototype_int;
- jit_movr(R0,ARGR0);
- }
- break;
- }
- case BUILTIN_BITXOR: {
- load_int(ARGR0,argdefs[0], frame);
- load_int(R2,argdefs[1], frame);
- jit_xorr(ARGR0,R2);
- if (return_type->tag == TAG_ANY) jit_call(alloc_int, "alloc_int");
- else {
- compiled_type = prototype_int;
- jit_movr(R0,ARGR0);
- }
- break;
- }
- case BUILTIN_SHL: {
- load_int(ARGR0,argdefs[0], frame);
- load_int(R2,argdefs[1], frame);
- jit_shlr(ARGR0,R2);
- if (return_type->tag == TAG_ANY) jit_call(alloc_int, "alloc_int");
- else {
- compiled_type = prototype_int;
- jit_movr(R0,ARGR0);
- }
- break;
- }
- case BUILTIN_SHR: {
- load_int(ARGR0,argdefs[0], frame);
- load_int(R2,argdefs[1], frame);
- jit_shrr(ARGR0,R2);
- if (return_type->tag == TAG_ANY) jit_call(alloc_int, "alloc_int");
- else {
- compiled_type = prototype_int;
- jit_movr(R0,ARGR0);
- }
- break;
- }
- case BUILTIN_ADD: {
- load_int(ARGR0,argdefs[0], frame);
- load_int(R2,argdefs[1], frame);
- jit_addr(ARGR0,R2);
- if (return_type->tag == TAG_ANY) jit_call(alloc_int, "alloc_int");
- else {
- compiled_type = prototype_int;
- jit_movr(R0,ARGR0);
- }
- break;
- }
- case BUILTIN_SUB: {
- load_int(ARGR0,argdefs[0], frame);
- load_int(R2,argdefs[1], frame);
- jit_subr(ARGR0,R2);
- if (return_type->tag == TAG_ANY) jit_call(alloc_int, "alloc_int");
- else {
- compiled_type = prototype_int;
- jit_movr(R0,ARGR0);
- }
- break;
- }
- case BUILTIN_MUL: {
- load_int(ARGR0,argdefs[0], frame);
- load_int(R2,argdefs[1], frame);
- jit_mulr(ARGR0,R2);
- if (return_type->tag == TAG_ANY) jit_call(alloc_int, "alloc_int");
- else {
- compiled_type = prototype_int;
- jit_movr(R0,ARGR0);
- }
- break;
- }
- case BUILTIN_DIV: {
- load_int(ARGR0,argdefs[0], frame);
- load_int(R2,argdefs[1], frame);
- jit_divr(ARGR0,R2);
- if (return_type->tag == TAG_ANY) jit_call(alloc_int, "alloc_int");
- else {
- compiled_type = prototype_int;
- jit_movr(R0,ARGR0);
- }
- break;
- }
- case BUILTIN_MOD: {
- load_int(ARGR0,argdefs[0], frame);
- load_int(R2,argdefs[1], frame);
- jit_modr(ARGR0,R2);
- if (return_type->tag == TAG_ANY) jit_call(alloc_int, "alloc_int");
- else {
- compiled_type = prototype_int;
- jit_movr(R0,ARGR0);
- }
- break;
- }
- case BUILTIN_GT: {
- load_int(ARGR0,argdefs[0], frame);
- load_int(R2,argdefs[1], frame);
- jit_movi(R3,0);
- jit_subr(ARGR0,R2);
- jit_movneg(ARGR0,R3);
- if (return_type->tag == TAG_ANY) jit_call(alloc_int, "alloc_int");
- else {
- compiled_type = prototype_int;
- jit_movr(R0,ARGR0);
- }
- break;
- }
- case BUILTIN_LT: {
- load_int(R2,argdefs[0], frame);
- load_int(ARGR0,argdefs[1], frame);
- jit_movi(R3,0);
- jit_subr(ARGR0,R2);
- jit_movneg(ARGR0,R3);
- if (return_type->tag == TAG_ANY) jit_call(alloc_int, "alloc_int");
- else {
- compiled_type = prototype_int;
- jit_movr(R0,ARGR0);
- }
- break;
- }
- case BUILTIN_EQ: {
- load_int(R1, argdefs[0], frame);
- load_int(R2, argdefs[1], frame);
- jit_movi(R0,0);
- jit_movi(R3,1);
- jit_cmpr(R1,R2);
- jit_moveq(R0,R3);
- if (return_type->tag == TAG_ANY) {
- jit_movr(ARGR0,R0);
- jit_call(alloc_int, "alloc_int");
- }
- else {
- compiled_type = prototype_int;
- // int is in R0 already
- }
- break;
- }
- case BUILTIN_DEF: {
- // TODO in the future, we could pre-allocate symbols
- // and especially their types based on type inference
-
- jit_lea(ARGR0,argdefs[0].cell); // load symbol address
- load_cell(ARGR1,argdefs[1],frame);
-
- push_frame_regs(frame->f);
- jit_call2(insert_global_symbol, "insert_global_symbol");
- pop_frame_regs(frame->f);
- break;
- }
- case BUILTIN_LET: {
- int is_int, offset, fidx, is_reg;
-
- if (!frame->f) {
- printf("<error: let is not allowed on global level, only in fn>\r\n");
- return 0;
- }
-
- is_int = 0;
- is_reg = 0;
- offset = MAXARGS + frame->locals;
- fidx = get_sym_frame_idx(argdefs[0].cell->ar.addr, fn_frame, 0);
- if (fidx >= 0) {
- // existing stack entry
- offset = fidx;
- //printf("+~ frame entry %s, existing stack-local idx %d (type %d)\n",fn_frame[offset].name,fn_frame[offset].slot,fn_frame[offset].type);
- // is_int from existing entry
- if (fn_frame[offset].type == ARGT_REG_INT ||
- fn_frame[offset].type == ARGT_STACK_INT) {
- is_int = 1;
- }
-
- if (fn_frame[offset].type == ARGT_REG_INT ||
- fn_frame[offset].type == ARGT_REG) {
- is_reg = 1;
- }
-
- } else {
- if ((argdefs[1].type == ARGT_REG_INT ||
- argdefs[1].type == ARGT_STACK_INT ||
- (argdefs[1].type == ARGT_CONST && argdefs[1].cell->tag == TAG_INT)
- )) {
- is_int = 1;
- }
- // create new stack entry for this let
- fn_frame[offset].name = argdefs[0].cell->ar.addr;
- fn_frame[offset].type_name = argdefs[1].type_name; // copy inferred type
- fn_frame[offset].cell = NULL;
- if (is_int) {
- fn_frame[offset].type = ARGT_STACK_INT;
- //printf("new let %s inferred INT\n",argdefs[0].cell->ar.addr);
- } else {
- fn_frame[offset].type = ARGT_STACK;
- //printf("new let %s inferred ANY\n",argdefs[0].cell->ar.addr);
- }
- fn_frame[offset].slot = -frame->locals;
- #ifdef DEBUG_ASM_SRC
- debug_buf = malloc(256);
- snprintf(debug_buf,255,"++ frame entry %s, new stack-local idx %d, is_int %d\n",fn_frame[offset].name,fn_frame[offset].slot,is_int);
- jit_comment(debug_buf);
- free(debug_buf);
- #endif
-
- frame->locals++;
- if (frame->locals+MAXARGS>=MAXFRAME) {
- printf("<error: too many locals (maximum %d)>\r\n",MAXFRAME-MAXARGS);
- }
- }
-
- if (is_int) {
- jit_comment("(let) load int");
- load_int(R0, argdefs[1], frame);
- compiled_type = prototype_int;
- } else {
- jit_comment("(let) load cell");
- load_cell(R0, argdefs[1], frame);
- compiled_type = prototype_any;
- }
- if (!is_reg) {
- jit_comment("(let) store to stack");
- jit_str_stack(R0,PTRSZ*(frame->sp-fn_frame[offset].slot));
- }
-
- if (is_reg) {
- #ifdef DEBUG_ASM_SRC
- debug_buf = malloc(256);
- snprintf(debug_buf,255,"(let) store %s to reg %d",fn_frame[offset].name,fn_frame[offset].slot);
- jit_comment(debug_buf);
- free(debug_buf);
- #endif
- jit_movr(fn_frame[offset].slot, R0);
- }
-
- if (compiled_type->tag == TAG_INT && return_type->tag == TAG_ANY) {
- jit_comment("(let) box int");
- jit_movr(ARGR0,R0);
- jit_call(alloc_int, "alloc_int");
- compiled_type = prototype_any;
- } else {
- }
- break;
- }
- case BUILTIN_FN: {
- Cell* fn_body, *fn_args, *lambda;
- Arg fn_new_frame[MAXFRAME];
- int num_lets, i, j, spo_count, fn_argc;
- Cell* compiled_type;
- char label_fn[64];
- char label_fe[64];
-
- Frame* nframe_ptr;
- Frame nframe = {fn_new_frame, 0, 0, frame->stack_end};
- #if CPU_ARM||__AMIGA||CPU_X86
- Label* fn_lbl;
- #endif
-
- if (argi<2) {
- printf("error: trying to define fn without body.\n");
- return 0;
- }
-
- // body
- fn_body = argdefs[argi-2].cell;
- // estimate stack space for locals
- num_lets = analyze_fn(fn_body,NULL,0);
-
- // scan args (build signature)
- fn_args = alloc_nil();
-
- for (i=0; i<MAXFRAME; i++) {
- fn_new_frame[i].type = 0;
- fn_new_frame[i].slot = -1;
- fn_new_frame[i].name = NULL;
- }
- spo_count = 0;
- fn_argc = 0;
- for (j=argi-3; j>=0; j--) {
- Cell* arg;
- Cell* arg_prototype = prototype_any;
- fn_new_frame[j].type = 0;
- fn_new_frame[j].name = NULL;
- fn_new_frame[j].type_name = NULL;
-
- if (j>=ARG_SPILLOVER) { // max args passed in registers
- fn_new_frame[j].type = ARGT_STACK;
- fn_new_frame[j].slot = -num_lets - (j - ARG_SPILLOVER) - 2;
- spo_count++;
- }
- else {
- fn_new_frame[j].type = ARGT_REG;
- fn_new_frame[j].slot = j + LBDREG;
- }
-
- if (argdefs[j].cell->tag == TAG_SYM) {
- fn_new_frame[j].name = argdefs[j].cell->ar.addr;
- } else if (argdefs[j].cell->tag == TAG_CONS) {
- env_entry* type_env = NULL;
- Cell* type_cell = car(cdr(argdefs[j].cell));
-
- if (!type_cell) {
- printf("<missing struct-name in (arg-name struct-name) declaration>\r\n");
- return 0;
- }
- if (type_cell->tag!=TAG_SYM) {
- printf("<non-symbol struct-name in (arg-name struct-name) declaration>\r\n");
- return 0;
- }
- fn_new_frame[j].name = car(argdefs[j].cell)->ar.addr;
- fn_new_frame[j].type_name = type_cell->ar.addr;
- type_env = lookup_global_symbol(fn_new_frame[j].type_name);
- if (!type_env || !type_env->cell) {
- printf("<undefined struct-name %s in (arg-name struct-name) declaration>\r\n",fn_new_frame[j].type_name);
- return 0;
- }
- if (type_env->cell->tag!=TAG_STRUCT_DEF) {
- printf("<struct-name %s in (arg-name struct-name) declaration does not resolve to a struct definition>\r\n",fn_new_frame[j].type_name);
- return 0;
- }
-
- // TODO other types!
- arg_prototype = type_env->cell;
- } else {
- // illegal type
- printf("<error: only symbols or (symbol typename) allowed in fn signature>\r\n");
- return 0;
- }
-
- arg = alloc_cons(alloc_sym(fn_new_frame[j].name),arg_prototype);
- fn_args = alloc_cons(arg,fn_args);
- fn_argc++;
- //printf("arg j %d: %s\r\n",j,fn_new_frame[j].name);
- }
- //char sig_debug[128];
- //lisp_write(fn_args, sig_debug, sizeof(sig_debug));
- //printf("signature: %s\n",sig_debug);
- //lisp_write(fn_body, sig_debug, sizeof(sig_debug));
-
- lambda = alloc_lambda(alloc_cons(fn_args,fn_body));
- lambda->dr.next = 0;
- sprintf(label_fn,"L0_%p",lambda);
- sprintf(label_fe,"L1_%p",lambda);
-
- jit_jmp(label_fe);
- jit_label(label_fn);
- jit_movi(R2,(jit_word_t)lambda|STACK_FRAME_MARKER);
- jit_push(R2,R2);
-
- jit_dec_stack(num_lets*PTRSZ);
- if (debug_mode) {
- Arg* nargs_ptr;
- // in debug mode, we need a copy of the frame definition at runtime
- nframe_ptr = malloc(sizeof(Frame));
- memcpy(nframe_ptr, &nframe, sizeof(Frame));
- nargs_ptr = malloc(sizeof(Arg)*MAXFRAME);
- memcpy(nargs_ptr, nframe.f, sizeof(Arg)*MAXFRAME);
- nframe_ptr->f = nargs_ptr;
- //printf("frame copied: %p args: %p\r\n",nframe_ptr,nframe_ptr->f);
- } else {
- nframe_ptr = &nframe;
- }
- //nframe_ptr->parent_frame = frame;
- // TODO here we can introduce function return types
- compiled_type = compile_expr(fn_body, nframe_ptr, prototype_any); // new frame, fresh sp
- if (!compiled_type) return 0;
- //printf(">> fn has %d args and %d locals. predicted locals: %d\r\n",fn_argc,nframe.locals,num_lets);
-
- jit_inc_stack(num_lets*PTRSZ);
- jit_inc_stack(PTRSZ);
- jit_ret();
- jit_label(label_fe);
- jit_lea(R0,lambda);
-
- #if CPU_ARM||__AMIGA||CPU_X86
- fn_lbl = find_label(label_fn);
- //printf("fn_lbl idx: %d code: %p\r\n",fn_lbl->idx,code);
- lambda->dr.next = code + fn_lbl->idx;
- //printf("fn_lbl next: %p\r\n",lambda->dr.next);
- #endif
-
- break;
- }
- case BUILTIN_IF: {
- Cell* then_type=NULL;
- Cell* else_type=NULL;
- char label_skip[64];
- sprintf(label_skip,"Lelse_%d",++label_skip_count);
-
- // load the condition
- load_int(R0, argdefs[0], frame);
- // compare to zero
- jit_cmpi(R0,0);
- jit_je(label_skip);
- // then
- then_type = compile_expr(argdefs[1].cell, frame, return_type);
- if (!then_type) return 0;
- // else
- if (argdefs[2].cell) {
- char label_end[64];
- sprintf(label_end,"Lendif_%d",++label_skip_count);
- jit_jmp(label_end);
-
- jit_label(label_skip);
- else_type = compile_expr(argdefs[2].cell, frame, return_type);
- if (!else_type) return 0;
-
- jit_label(label_end);
- } else {
- jit_label(label_skip);
- }
- if (return_type->tag!=TAG_VOID && then_type && else_type && then_type->tag!=else_type->tag) {
- printf("<incompatible then/else types of if: %s/%s, return type: %s>\r\n",tag_to_str(then_type->tag),tag_to_str(else_type->tag),tag_to_str(return_type->tag));
- return 0;
- }
-
- break;
- }
- case BUILTIN_WHILE: {
- char label_loop[64];
- char label_skip[64];
- char label_skip2[64];
- sprintf(label_loop, "Lloop_%d",++label_skip_count);
- sprintf(label_skip, "Lskip_%d",label_skip_count);
- sprintf(label_skip2,"Lskip2_%d",label_skip_count);
-
- jit_label(label_loop);
-
- compiled_type = compile_expr(argdefs[0].cell, frame, prototype_int);
- if (!compiled_type) return 0;
- // load the condition
- if (compiled_type->tag != TAG_INT) {
- jit_ldr(R0);
- }
- // compare to zero
- jit_cmpi(R0,0);
- jit_je(label_skip);
- // while body
- compiled_type = compile_expr(argdefs[1].cell, frame, return_type);
- if (!compiled_type) return 0;
- jit_jmp(label_loop);
- jit_label(label_skip);
- if (return_type->tag == TAG_ANY) {
- // if the while never executed, we have to create a zero int cell
- // from r0
- jit_cmpi(R0,0);
- jit_jne(label_skip2);
- jit_call(alloc_int,"alloc_int");
- jit_label(label_skip2);
- }
-
- break;
- }
- case BUILTIN_DO: {
- Cell* arg;
- args = orig_args;
- if (!car(args)) {
- printf("<empty (do) not allowed>\r\n");
- return 0;
- }
-
- while ((arg = car(args))) {
- Cell* compiled_type;
- if (car(cdr(args))) {
- // discard all returns except for the last one
- compiled_type = compile_expr(arg, frame, prototype_void);
- } else {
- compiled_type = compile_expr(arg, frame, return_type);
- }
-
- if (!compiled_type) return 0;
- args = cdr(args);
- }
- break;
- }
- case BUILTIN_LIST: {
- Cell* arg;
- int n = 0, i;
- args = orig_args;
- while ((arg = car(args))) {
- Cell* compiled_type = compile_expr(arg, frame, prototype_any);
- if (!compiled_type) return 0;
- jit_push(R0,R0);
- frame->sp++;
- args = cdr(args);
- n++;
- }
- jit_call(alloc_nil, "list:alloc_nil");
- jit_movr(ARGR1,R0);
- for (i=0; i<n; i++) {
- jit_pop(ARGR0,ARGR0);
- frame->sp--;
- jit_call2(alloc_cons, "list:alloc_cons");
- jit_movr(ARGR1,R0);
- }
- break; // FIXME
- }
- case BUILTIN_STRUCT: {
- Cell* key;
- Cell* arg;
- Cell* name_sym;
- int n = 0, i;
- args = cdr(orig_args);
- name_sym = car(orig_args);
- // struct knows its own name
- jit_lea(R0,name_sym);
- jit_push(R0,R0);
-
- while ((key = car(args))) {
- if (key->tag != TAG_SYM) {
- printf("<every second argument of struct following the struct'sname has to be a symbol>\r\n");
- return 0;
- }
- jit_lea(R0,key);
- jit_push(R0,R0);
- args = cdr(args);
- arg = car(args);
- if (!arg) return 0;
-
- args = cdr(args);
-
- Cell* compiled_type = compile_expr(arg, frame, prototype_any);
- if (!compiled_type) return 0;
-
- jit_push(R0,R0);
- frame->sp+=2;
- n+=2;
- }
- n++; // account for name
-
- jit_movi(ARGR0,n);
- jit_call(alloc_struct_def, "struct:alloc_struct_def");
- jit_movr(R1,R0);
- jit_ldr(R1); // load addr of cell array
- jit_addi(R1,n*PTRSZ);
- for (i=0; i<n; i++) {
- jit_addi(R1,-PTRSZ);
- jit_pop(R3,R3);
- frame->sp--;
- jit_stra(R1); // strw from r3
- }
- // load the struct name
- jit_lea(ARGR0,name_sym);
- jit_movr(ARGR1,R0);
- push_frame_regs(frame->f);
- jit_call2(insert_global_symbol, "insert_global_symbol");
- pop_frame_regs(frame->f);
-
- break;
- }
- case BUILTIN_NEW: {
- Cell* arg;
- if (orig_op) {
- // (struct-def …)
- arg = orig_op;
- } else {
- // (new struct-def …)
- arg = argdefs[0].env->cell;
- }
- //printf("[new] arg: %p\r\n",arg);
- //printf("[new] struct size %d\r\n",arg->dr.size/2);
- // arg points to struct definition which is TAG_VEC
- if (arg->tag != TAG_STRUCT_DEF) {
- printf("<(new) requires a struct definition>\r\n");
- return 0;
- }
- jit_lea(ARGR0,arg);
- jit_call(alloc_struct,"new:alloc_struct");
- compiled_type = alloc_struct(arg); // prototype
-
- break;
- }
- case BUILTIN_SGET: {
- Cell* struct_def;
- char* lookup_name = argdefs[1].cell->ar.addr;
- Cell** struct_elements;
- int num_fields;
- int found=0;
- if (argdefs[0].type == ARGT_ENV) {
- struct_def = argdefs[0].env->cell;
- struct_def = car(car(struct_def));
- }
- else if (argdefs[0].type_name) {
- //printf("[sget] arg type name %s\r\n",argdefs[0].type_name);
- env_entry* type_env = lookup_global_symbol(argdefs[0].type_name);
-
- struct_def = type_env->cell;
- //printf("[sget] struct_def %p\r\n",struct_def);
- }
- else {
- printf("<untyped value passed to sget (field %s)>\r\n",lookup_name);
- return 0;
- }
- // arg points to struct definition which is TAG_VEC
- if (struct_def->tag != TAG_STRUCT_DEF) {
- printf("<(sget) requires a struct>\r\n");
- return 0;
- }
- num_fields = struct_def->dr.size/2;
- struct_elements = (Cell**)(struct_def->ar.addr);
-
- //printf("[sget] struct_elements %p\r\n",struct_elements);
- //printf("[sget] lookup %s\r\n",lookup_name);
- for (int i=0; i<num_fields; i++) {
- if (!strcmp(lookup_name,(char*)struct_elements[1+i*2]->ar.addr)) {
- //printf("field found at index %d\r\n",i);
- load_cell(R0,argdefs[0],frame);
- jit_ldr(R0);
- jit_addi(R0,(i+1)*PTRSZ);
- jit_ldr(R0);
- found = 1;
- // extract and return the field type (prototype)
- compiled_type = struct_elements[1+i*2+1];
- if (compiled_type->tag != TAG_STRUCT) {
- compiled_type = prototype_any; // FIXME
- }
-
- break;
- }
- }
- if (!found) {
- printf("<sget field %s not found!>\r\n",lookup_name);
- jit_movi(R0,0);
- return 0;
- }
-
- break;
- }
- case BUILTIN_SPUT: {
- Cell* struct_def;
- char* lookup_name = argdefs[1].cell->ar.addr;
- Cell** struct_elements;
- int num_fields;
- int found=0;
- if (argdefs[0].type == ARGT_ENV) {
- struct_def = argdefs[0].env->cell;
- struct_def = car(car(struct_def));
- } else if (argdefs[0].type_name) {
- env_entry* type_env = lookup_global_symbol(argdefs[0].type_name);
- if (type_env) {
- struct_def = type_env->cell;
- } else {
- printf("<sput: struct type %s not found.>\r\n",argdefs[0].type_name);
- return 0;
- }
- } else {
- printf("<indirect struct field access not yet implemented.>");
- return 0;
- }
- // arg points to struct definition which is TAG_VEC
- if (struct_def->tag != TAG_STRUCT_DEF) {
- printf("<(sput) requires a struct>\r\n");
- return 0;
- }
- num_fields = struct_def->dr.size/2;
- struct_elements = (Cell**)(struct_def->ar.addr);
- //printf("[sput] lookup %s\r\n",lookup_name);
- for (int i=0; i<num_fields; i++) {
- if (!strcmp(lookup_name,(char*)struct_elements[1+i*2]->ar.addr)) {
- //printf("[sput] field found at index %d\r\n",i);
- load_cell(R2,argdefs[0],frame);
- jit_movr(R0,R2);
- jit_ldr(R2);
- jit_addi(R2,(i+1)*PTRSZ);
- load_cell(R3,argdefs[2],frame); // TODO type check!
- jit_stra(R2);
- found = 1;
- break;
- }
- }
- if (!found) {
- printf("<sput field %s not found!>\r\n",lookup_name);
- jit_movi(R0,0);
- return 0;
- }
-
- break;
- }
- case BUILTIN_QUOTE: {
- Cell* arg;
- args = orig_args;
- if (!car(args)) {
- printf("<empty (quote) not allowed>\r\n");
- return 0;
- }
-
- arg = car(args);
- jit_lea(R0,arg);
- break;
- }
- case BUILTIN_CAR: {
- load_cell(R0,argdefs[0], frame);
-
- // type check -------------------
- jit_movr(R1,R0);
- jit_addi(R1,2*PTRSZ);
- jit_ldr(R1);
- jit_lea(R2,consed_type_error);
- jit_cmpi(R1,TAG_CONS);
- jit_movne(R0,R2);
- // ------------------------------
-
- jit_ldr(R0);
- jit_lea(R2,prototype_nil);
- jit_cmpi(R0,0); // check for null cell
- jit_moveq(R0,R2);
- break;
- }
- case BUILTIN_CDR: {
- load_cell(R0,argdefs[0], frame);
- jit_addi(R0,PTRSZ);
- // type check -------------------
- jit_movr(R1,R0);
- jit_addi(R1,PTRSZ); // because already added PTRSZ
- jit_ldr(R1);
- jit_lea(R2,consed_type_error);
- jit_cmpi(R1,TAG_CONS);
- jit_movne(R0,R2);
- // ------------------------------
- jit_ldr(R0);
- jit_lea(R2,prototype_nil);
- jit_cmpi(R0,0); // check for null cell
- jit_moveq(R0,R2);
- break;
- }
- case BUILTIN_CONS: {
- load_cell(ARGR0,argdefs[0], frame);
- load_cell(ARGR1,argdefs[1], frame);
- jit_call2(alloc_cons,"alloc_cons");
- break;
- }
- case BUILTIN_CONCAT: {
- load_cell(ARGR0,argdefs[0], frame);
- load_cell(ARGR1,argdefs[1], frame);
- jit_call2(alloc_concat,"alloc_concat");
- break;
- }
- case BUILTIN_SUBSTR: {
- load_cell(ARGR0,argdefs[0], frame);
- load_int(ARGR1,argdefs[1], frame);
- load_int(ARGR2,argdefs[2], frame);
- jit_call3(alloc_substr,"alloc_substr");
- break;
- }
- case BUILTIN_GET8: {
- char label_skip[64];
- char label_ok[64];
- sprintf(label_skip,"Lskip_%d",++label_skip_count);
- sprintf(label_ok,"Lok_%d",label_skip_count);
-
- load_cell(R1,argdefs[0], frame);
- load_int(R2,argdefs[1], frame); // offset -> R2
- jit_movr(R0,R1); // save original cell in r0
- // todo: compile-time checking would be much more awesome
- // type check
- jit_addi(R1,2*PTRSZ);
- jit_ldr(R1);
- jit_cmpi(R1,TAG_BYTES); // todo: better perf with mask?
- jit_je(label_ok);
- jit_cmpi(R1,TAG_STR);
- jit_je(label_ok);
- // wrong type
- jit_movi(R3, 0);
- jit_jmp(label_skip);
- // good type
- jit_label(label_ok);
- jit_movr(R1,R0); // get original cell from r3
- #ifdef CHECK_BOUNDS
- // bounds check -----
- jit_movr(R1,R0);
- jit_addi(R1,PTRSZ);
- jit_ldr(R1);
- jit_cmpr(R2,R1);
- jit_jge(label_skip);
- // -------------------
- #endif
-
- jit_movr(R1,R0);
- jit_ldr(R1); // string address
- jit_addr(R1,R2);
- jit_movi(R3, 0);
- jit_ldrb(R1); // data in r3
- jit_label(label_skip);
-
- jit_movr(ARGR0, R3);
-
- if (return_type->tag == TAG_ANY) jit_call(alloc_int, "alloc_int");
- else {
- compiled_type = prototype_int;
- jit_movr(R0,ARGR0);
- }
- break;
- }
- case BUILTIN_GET16: {
- char label_skip[64];
- char label_ok[64];
- sprintf(label_skip,"Lskip_%d",++label_skip_count);
- sprintf(label_ok,"Lok_%d",label_skip_count);
-
- load_cell(R1,argdefs[0], frame);
- load_int(R2,argdefs[1], frame); // offset -> R2
- jit_movr(R0,R1); // save original cell in r0
- // todo: compile-time checking would be much more awesome
- // type check
- jit_addi(R1,2*PTRSZ);
- jit_ldr(R1);
- jit_cmpi(R1,TAG_BYTES); // todo: better perf with mask?
- jit_je(label_ok);
- jit_cmpi(R1,TAG_STR);
- jit_je(label_ok);
- // wrong type
- jit_movi(R3, 0);
- jit_jmp(label_skip);
- // good type
- jit_label(label_ok);
- jit_movr(R1,R0); // get original cell from r3
- #ifdef CHECK_BOUNDS
- // bounds check -----
- jit_movr(R1,R0);
- jit_addi(R1,PTRSZ);
- jit_ldr(R1);
- jit_cmpr(R2,R1);
- jit_jge(label_skip);
- // -------------------
- #endif
-
- jit_movr(R1,R0);
- jit_ldr(R1); // string address
- jit_addr(R1,R2);
- jit_movi(R3, 0);
- jit_ldrs(R1); // data in r3
- jit_label(label_skip);
-
- jit_movr(ARGR0, R3);
-
- if (return_type->tag == TAG_ANY) jit_call(alloc_int, "alloc_int");
- else {
- compiled_type = prototype_int;
- jit_movr(R0,ARGR0);
- }
- break;
- }
- case BUILTIN_PUT8: {
- char label_skip[64];
- sprintf(label_skip,"Lskip_%d",++label_skip_count);
-
- load_cell(R0,argdefs[0], frame);
- load_int(R2,argdefs[1], frame); // offset -> R2
- load_int(R3,argdefs[2], frame); // byte to store -> R3
- #ifdef CHECK_BOUNDS
- // bounds check -----
- jit_movr(R1,R0);
- jit_addi(R1,PTRSZ);
- jit_ldr(R1);
- jit_cmpr(R2,R1);
- jit_jge(label_skip);
- // -------------------
- #endif
- jit_movr(R1,R0);
- jit_ldr(R1); // string address
- jit_addr(R1,R2);
- jit_strb(R1); // address is in r1, data in r3
- jit_label(label_skip);
-
- break;
- }
- case BUILTIN_PUT16: {
- char label_skip[64];
- sprintf(label_skip,"Lskip_%d",++label_skip_count);
-
- load_cell(R0,argdefs[0], frame);
- load_int(R2,argdefs[1], frame); // offset -> R2
- load_int(R3,argdefs[2], frame); // byte to store -> R3
- #ifdef CHECK_BOUNDS
- // bounds check -----
- jit_movr(R1,R0);
- jit_addi(R1,PTRSZ);
- jit_ldr(R1);
- jit_cmpr(R2,R1);
- jit_jge(label_skip);
- // -------------------
- #endif
- jit_movr(R1,R0);
- jit_ldr(R1); // string address
- jit_addr(R1,R2);
- jit_strs(R1); // address is in r1, data in r3
- jit_label(label_skip);
-
- break;
- }
- case BUILTIN_GET32: {
- load_int(R2,argdefs[1], frame); // offset -> R2
- load_cell(R3,argdefs[0], frame);
- jit_ldr(R3); // string address
- jit_movi(R1,2); // offset * 4
- jit_shlr(R2,R1);
- jit_addr(R3,R2);
- jit_ldrw(R3); // load to r3
-
- jit_movr(ARGR0, R3); // FIXME
- jit_call(alloc_int,"alloc_int");
-
- break;
- }
- case BUILTIN_PUT32: {
- char label_skip[64];
- sprintf(label_skip,"Lskip_%d",++label_skip_count);
-
- load_cell(R1,argdefs[0], frame);
- load_int(R2,argdefs[1], frame); // offset -> R2
- load_int(R3,argdefs[2], frame); // word to store -> R3
- #ifdef CHECK_BOUNDS
- // bounds check -----
- jit_movr(R1,R0);
- jit_addi(R1,PTRSZ);
- jit_ldr(R1);
- jit_cmpr(R2,R1);
- jit_jge(label_skip);
- // -------------------
- #endif
- // TODO: 32-bit align
-
- jit_movr(R1,R0);
- jit_ldr(R1); // string address
- jit_addr(R1,R2);
- jit_strw(R1); // store from r3
-
- jit_label(label_skip);
- jit_movr(R0,R1);
- jit_call(alloc_int,"debug");
-
- break;
- }
- case BUILTIN_ALLOC: {
- load_int(ARGR0,argdefs[0], frame);
- jit_call(alloc_num_bytes,"alloc_bytes");
- break;
- }
- case BUILTIN_ALLOC_STR: {
- load_int(ARGR0,argdefs[0], frame);
- jit_call(alloc_num_string,"alloc_string");
- break;
- }
- case BUILTIN_BYTES_TO_STR: {
- load_cell(ARGR0,argdefs[0], frame);
- jit_call(alloc_string_from_bytes,"alloc_string_to_bytes");
- break;
- }
- case BUILTIN_WRITE: {
- load_cell(ARGR0,argdefs[0], frame);
- load_cell(ARGR1,argdefs[1], frame);
- jit_host_call_enter();
- jit_call2(lisp_write_to_cell,"lisp_write_to_cell");
- jit_host_call_exit();
- break;
- }
- case BUILTIN_READ: {
- load_cell(ARGR0,argdefs[0], frame);
- jit_host_call_enter();
- jit_call(read_string_cell,"read_string_cell");
- jit_host_call_exit();
- break;
- }
- case BUILTIN_EVAL: {
- load_cell(ARGR0,argdefs[0], frame);
- jit_host_call_enter();
- jit_call(platform_eval,"platform_eval");
- jit_host_call_exit();
- break;
- }
- case BUILTIN_SIZE: {
- load_cell(ARGR0,argdefs[0], frame);
- jit_addi(ARGR0,PTRSZ); // fetch size -> R0
- jit_ldr(ARGR0);
- if (return_type->tag == TAG_ANY) {
- jit_call(alloc_int, "alloc_int");
- } else if (return_type->tag == TAG_INT) {
- jit_movr(R0,ARGR0);
- compiled_type = prototype_int;
- }
-
- break;
- }
- case BUILTIN_GC: {
- push_frame_regs(frame->f);
- jit_lea(ARGR0,global_env);
- jit_movi(ARGR1,(jit_word_t)frame->stack_end);
- jit_movr(ARGR2,RSP);
- jit_call3(collect_garbage,"collect_garbage");
- pop_frame_regs(frame->f);
- break;
- }
- case BUILTIN_SYMBOLS: {
- jit_lea(ARGR0,global_env);
- jit_call(list_symbols,"list_symbols");
- break;
- }
- case BUILTIN_DEBUG: {
- //jit_call(platform_debug,"platform_debug");
- break;
- }
- case BUILTIN_PRINT: {
- load_cell(ARGR0,argdefs[0], frame);
- push_frame_regs(frame->f);
- jit_host_call_enter();
- jit_call(lisp_print,"lisp_print");
- jit_host_call_exit();
- pop_frame_regs(frame->f);
- break;
- }
- case BUILTIN_MOUNT: {
- load_cell(ARGR0,argdefs[0], frame);
- load_cell(ARGR1,argdefs[1], frame);
- jit_host_call_enter();
- jit_call2(fs_mount,"fs_mount");
- jit_host_call_exit();
- break;
- }
- case BUILTIN_MMAP: {
- load_cell(ARGR0,argdefs[0], frame);
- jit_host_call_enter();
- jit_call(fs_mmap,"fs_mmap");
- jit_host_call_exit();
- break;
- }
- case BUILTIN_OPEN: {
- load_cell(ARGR0,argdefs[0], frame);
- push_frame_regs(frame->f);
- jit_host_call_enter();
- jit_call(fs_open,"fs_open");
- jit_host_call_exit();
- pop_frame_regs(frame->f);
- break;
- }
- case BUILTIN_RECV: {
- load_cell(ARGR0,argdefs[0], frame);
- push_frame_regs(frame->f);
- jit_host_call_enter();
- jit_call(stream_read,"stream_read");
- jit_host_call_exit();
- pop_frame_regs(frame->f);
- break;
- }
- case BUILTIN_SEND: {
- load_cell(ARGR0,argdefs[0], frame);
- load_cell(ARGR1,argdefs[1], frame);
- push_frame_regs(frame->f);
- jit_host_call_enter();
- jit_call2(stream_write,"stream_write");
- jit_host_call_exit();
- pop_frame_regs(frame->f);
- break;
- }
- }
- } else {
- // λλλ lambda call λλλ
- int spo_adjust = 0, j;
-
- // save our args
- int pushed = push_frame_regs(frame->f);
- frame->sp+=pushed;
-
- for (j=argi-2; j>=0; j--) {
- if (j>=ARG_SPILLOVER) {
- // pass arg on stack
- load_cell(R0, argdefs[j], frame);
- jit_push(R0,R0);
- spo_adjust++;
- frame->sp++;
- } else {
- // pass arg in reg (LBDREG + slot)
-
- if (argdefs[j].type == ARGT_REG) {
- // FIXME kludge?
- if (1 || argdefs[j].slot<j+LBDREG) {
- int offset = ((pushed+spo_adjust) - (argdefs[j].slot-LBDREG) - 1);
- // register already clobbered, load from stack
- //printf("-- loading clobbered reg %d from stack offset %d to reg %d\n",argdefs[j].slot,offset,LBDREG+j);
- jit_ldr_stack(LBDREG+j, offset*PTRSZ);
- } else {
- // no need to move a reg into itself
- if (argdefs[j].slot!=j) {
- load_cell(LBDREG+j, argdefs[j], frame);
- }
- }
- }
- else {
- load_cell(LBDREG+j, argdefs[j], frame);
- }
- }
- }
-
- jit_lea(R0,op_env);
- jit_ldr(R0); // load cell
- jit_addi(R0,PTRSZ); // &cell->dr.next
- jit_ldr(R0); // cell->dr.next
- jit_callr(R0); // the call!
-
- if (spo_adjust) {
- jit_inc_stack(spo_adjust*PTRSZ);
- frame->sp-=spo_adjust;
- }
- pop_frame_regs(frame->f);
- frame->sp-=pushed;
- }
- #ifdef CPU_X64
- fflush(jit_out);
- #endif
- // at this point, registers R1-R6 are filled, execute
- return clean_return(args_pushed, frame, compiled_type);
- }
- env_t* get_global_env() {
- return global_env;
- }
- void init_compiler() {
- Cell** signature = malloc(sizeof(Cell*)*3);
- //printf("[compiler] creating global env hash table\r\n");
- global_env = sm_new(1000);
- //printf("[compiler] init_allocator\r\n");
- init_allocator();
- prototype_nil = alloc_nil();
- prototype_type_error = alloc_error(ERR_INVALID_PARAM_TYPE);
- consed_type_error = alloc_cons(prototype_type_error,prototype_nil);
- prototype_any = alloc_int(0);
- prototype_any->tag = TAG_ANY;
- prototype_void = alloc_int(0);
- prototype_void->tag = TAG_VOID;
- prototype_symbol = alloc_sym("symbol");
- prototype_int = alloc_int(0);
- prototype_struct = alloc_int(0);
- prototype_struct->tag = TAG_STRUCT;
- prototype_struct_def = alloc_int(0);
- prototype_struct_def->tag = TAG_STRUCT_DEF;
- prototype_stream = alloc_int(0);
- prototype_stream->tag = TAG_STREAM;
- prototype_string = alloc_string_copy("string");
- prototype_lambda = alloc_int(0);
- prototype_lambda->tag = TAG_LAMBDA;
- prototype_cons = alloc_cons(alloc_nil(),alloc_nil());
- insert_symbol(alloc_sym("nil"), prototype_nil, &global_env);
- insert_symbol(alloc_sym("type_error"), consed_type_error, &global_env);
-
- //printf("[compiler] inserting symbols\r\n");
- signature[0]=prototype_symbol; signature[1]=prototype_any;
- insert_symbol(alloc_sym("def"), alloc_builtin(BUILTIN_DEF, alloc_list(signature, 2)), &global_env);
- insert_symbol(alloc_sym("let"), alloc_builtin(BUILTIN_LET, alloc_list(signature, 2)), &global_env);
-
- signature[0]=prototype_struct_def; signature[1]=prototype_symbol; signature[2]=prototype_any;
- insert_symbol(alloc_sym("new"), alloc_builtin(BUILTIN_NEW, alloc_list(signature, 1)), &global_env);
- signature[0]=prototype_struct;
- insert_symbol(alloc_sym("sget"), alloc_builtin(BUILTIN_SGET, alloc_list(signature, 2)), &global_env);
- insert_symbol(alloc_sym("sput"), alloc_builtin(BUILTIN_SPUT, alloc_list(signature, 3)), &global_env);
- signature[0]=prototype_int; signature[1]=prototype_int;
- insert_symbol(alloc_sym("+"), alloc_builtin(BUILTIN_ADD, alloc_list(signature, 2)), &global_env);
- insert_symbol(alloc_sym("-"), alloc_builtin(BUILTIN_SUB, alloc_list(signature, 2)), &global_env);
- insert_symbol(alloc_sym("*"), alloc_builtin(BUILTIN_MUL, alloc_list(signature, 2)), &global_env);
- insert_symbol(alloc_sym("/"), alloc_builtin(BUILTIN_DIV, alloc_list(signature, 2)), &global_env);
- insert_symbol(alloc_sym("%"), alloc_builtin(BUILTIN_MOD, alloc_list(signature, 2)), &global_env);
- insert_symbol(alloc_sym("bitand"), alloc_builtin(BUILTIN_BITAND, alloc_list(signature, 2)), &global_env);
- insert_symbol(alloc_sym("bitor"), alloc_builtin(BUILTIN_BITOR, alloc_list(signature, 2)), &global_env);
- insert_symbol(alloc_sym("bitnot"), alloc_builtin(BUILTIN_BITNOT, alloc_list(signature, 1)), &global_env);
- insert_symbol(alloc_sym("bitxor"), alloc_builtin(BUILTIN_BITXOR, alloc_list(signature, 2)), &global_env);
- insert_symbol(alloc_sym("shl"), alloc_builtin(BUILTIN_SHL, alloc_list(signature, 2)), &global_env);
- insert_symbol(alloc_sym("shr"), alloc_builtin(BUILTIN_SHR, alloc_list(signature, 2)), &global_env);
-
- //printf("[compiler] arithmetic\r\n");
-
- insert_symbol(alloc_sym("lt"), alloc_builtin(BUILTIN_LT, alloc_list(signature, 2)), &global_env);
- insert_symbol(alloc_sym("gt"), alloc_builtin(BUILTIN_GT, alloc_list(signature, 2)), &global_env);
- insert_symbol(alloc_sym("eq"), alloc_builtin(BUILTIN_EQ, alloc_list(signature, 2)), &global_env);
-
- //printf("[compiler] compare\r\n");
-
- signature[0]=prototype_int; signature[1]=prototype_lambda; signature[2]=prototype_lambda;
- insert_symbol(alloc_sym("if"), alloc_builtin(BUILTIN_IF, alloc_list(signature, 3)), &global_env);
- insert_symbol(alloc_sym("fn"), alloc_builtin(BUILTIN_FN, NULL), &global_env);
- insert_symbol(alloc_sym("while"), alloc_builtin(BUILTIN_WHILE, NULL), &global_env);
- insert_symbol(alloc_sym("do"), alloc_builtin(BUILTIN_DO, NULL), &global_env);
-
- signature[0]=prototype_any;
- insert_symbol(alloc_sym("print"), alloc_builtin(BUILTIN_PRINT, alloc_list(signature, 1)), &global_env);
-
- //printf("[compiler] flow\r\n");
-
- signature[0]=prototype_cons;
- insert_symbol(alloc_sym("car"), alloc_builtin(BUILTIN_CAR, alloc_list(signature, 1)), &global_env);
- insert_symbol(alloc_sym("cdr"), alloc_builtin(BUILTIN_CDR, alloc_list(signature, 1)), &global_env);
-
- signature[0]=prototype_any; signature[1]=prototype_any;
- insert_symbol(alloc_sym("cons"), alloc_builtin(BUILTIN_CONS, alloc_list(signature, 2)), &global_env);
- insert_symbol(alloc_sym("list"), alloc_builtin(BUILTIN_LIST, NULL), &global_env);
- insert_symbol(alloc_sym("quote"), alloc_builtin(BUILTIN_QUOTE, NULL), &global_env);
- insert_symbol(alloc_sym("struct"), alloc_builtin(BUILTIN_STRUCT, NULL), &global_env);
- //insert_symbol(alloc_sym("map"), alloc_builtin(BUILTIN_MAP), &global_env);
- //printf("[compiler] lists\r\n");
-
- signature[0]=prototype_string;
- signature[1]=prototype_string;
- insert_symbol(alloc_sym("concat"), alloc_builtin(BUILTIN_CONCAT, alloc_list(signature, 2)), &global_env);
-
- signature[0]=prototype_string;
- signature[1]=prototype_int;
- signature[2]=prototype_int;
- insert_symbol(alloc_sym("substr"), alloc_builtin(BUILTIN_SUBSTR, alloc_list(signature, 3)), &global_env);
- insert_symbol(alloc_sym("put8"), alloc_builtin(BUILTIN_PUT8, alloc_list(signature, 3)), &global_env);
- insert_symbol(alloc_sym("get8"), alloc_builtin(BUILTIN_GET8, alloc_list(signature, 2)), &global_env);
- insert_symbol(alloc_sym("put16"), alloc_builtin(BUILTIN_PUT16, alloc_list(signature, 3)), &global_env);
- insert_symbol(alloc_sym("get16"), alloc_builtin(BUILTIN_GET16, alloc_list(signature, 2)), &global_env);
- insert_symbol(alloc_sym("get32"), alloc_builtin(BUILTIN_GET32, alloc_list(signature, 2)), &global_env);
- insert_symbol(alloc_sym("put32"), alloc_builtin(BUILTIN_PUT32, alloc_list(signature, 3)), &global_env);
- insert_symbol(alloc_sym("size"), alloc_builtin(BUILTIN_SIZE, alloc_list(signature, 1)), &global_env);
-
- signature[0]=prototype_int;
- insert_symbol(alloc_sym("alloc"), alloc_builtin(BUILTIN_ALLOC, alloc_list(signature, 1)), &global_env);
- insert_symbol(alloc_sym("alloc-str"), alloc_builtin(BUILTIN_ALLOC_STR, alloc_list(signature, 1)), &global_env);
- signature[0]=prototype_any;
- insert_symbol(alloc_sym("bytes->str"), alloc_builtin(BUILTIN_BYTES_TO_STR, alloc_list(signature, 1)), &global_env);
- //printf("[compiler] strings\r\n");
-
- signature[0]=prototype_any;
- signature[1]=prototype_string;
- insert_symbol(alloc_sym("write"), alloc_builtin(BUILTIN_WRITE, alloc_list(signature,2)), &global_env);
- insert_symbol(alloc_sym("eval"), alloc_builtin(BUILTIN_EVAL, alloc_list(signature,1)), &global_env);
- signature[0]=prototype_string;
- insert_symbol(alloc_sym("read"), alloc_builtin(BUILTIN_READ, alloc_list(signature,1)), &global_env);
- signature[0]=prototype_string;
- signature[1]=prototype_cons;
- insert_symbol(alloc_sym("mount"), alloc_builtin(BUILTIN_MOUNT, alloc_list(signature,2)), &global_env);
- insert_symbol(alloc_sym("open"), alloc_builtin(BUILTIN_OPEN, alloc_list(signature,1)), &global_env);
- insert_symbol(alloc_sym("mmap"), alloc_builtin(BUILTIN_MMAP, alloc_list(signature,1)), &global_env);
-
- signature[0]=prototype_stream;
- signature[1]=prototype_any;
- insert_symbol(alloc_sym("recv"), alloc_builtin(BUILTIN_RECV, alloc_list(signature,1)), &global_env);
- insert_symbol(alloc_sym("send"), alloc_builtin(BUILTIN_SEND, alloc_list(signature,2)), &global_env);
-
- //printf("[compiler] write/eval\r\n");
-
- insert_symbol(alloc_sym("gc"), alloc_builtin(BUILTIN_GC, NULL), &global_env);
- insert_symbol(alloc_sym("symbols"), alloc_builtin(BUILTIN_SYMBOLS, NULL), &global_env);
- insert_symbol(alloc_sym("debug"), alloc_builtin(BUILTIN_DEBUG, NULL), &global_env);
-
- printf("[compiler] interim knows %u symbols. enter (symbols) to see them.\r\n", sm_get_count(global_env));
- }
|