ilist ins0(instruction ins, fncode fn) /* Effects: Adds instruction ins to code of 'fn'. Modifies: fn */ { switch (ins) { case OPmexec4 ... OPmexec4 + 15: adjust_depth(-(ins - OPmexec4), fn); break; case OPmset: adjust_depth(-2, fn); break; case OPmpop: case OPmeq: case OPmne: case OPmref: case OPmlt: case OPmle: case OPmgt: case OPmge: case OPmadd: case OPmsub: case OPmmultiply: case OPmdivide: case OPmremainder: case OPmbitand: case OPmbitor: case OPmbitxor: case OPmshiftleft: case OPmshiftright: adjust_depth(-1, fn); break; case OPmcst: case OPmundefined: case OPmint3 ... OPmint3 + 7: adjust_depth(1, fn); break; case OPmreturn: case OPmnegate: case OPmbitnot: case OPmnot: case OPmscheck4 ... OPmscheck4 + 15: break; default: fprintf(stderr, "unknown instruction %d\n", ins); assert(0); } return add_ins(ins, 0, fn); }
void insprim(instruction ins, int nargs, fncode fn) /* Effects: Adds instruction ins to code of 'fn'. Modifies: fn */ { adjust_depth(-(nargs - 1), fn); add_ins(ins, 0, fn); }
static void wexit_code(void *_data, fncode fn) { struct whiledata *wdata = _data; set_label(wdata->exitlab, fn); generate_component(component_undefined, fn); branch(op_branch1, wdata->endlab, fn); adjust_depth(-1, fn); }
static void iff_code(void *_data, fncode fn) { struct ifdata *data = _data; set_label(data->flab, fn); generate_component(data->failure, fn); branch(op_branch1, data->endlab, fn); adjust_depth(-1, fn); }
static void iff_code(void *_data, fncode fn) { struct ifdata *data = _data; set_label(data->flab, fn); generate_component(data->failure, NULL, data->discard, fn); branch(OPmba3, data->endlab, fn); if (!data->discard) adjust_depth(-1, fn); }
void ins2(instruction ins, int arg2, fncode fn) /* Effects: Adds instruction ins to code of 'fn'. The instruction has a two byte argument (arg2), stored in big-endian format. Modifies: fn */ { switch (ins) { case OPmreadg: adjust_depth(1, fn); break; case OPmwriteg: break; case OPmexecg4 ... OPmexecg4 + 15: adjust_depth(-(ins - OPmexecg4) + 1, fn); break; default: assert(0); } add_ins(ins, 2, fn)->arg = arg2; }
u8 *ins_closure(value code, u16 clen, fncode fn) /* Effects: Adds code for a 'clen' variable closure with function 'code' to 'fn' Returns: Pointer to area to add the closure variables */ { ilist cins = add_ins(OPmclosure, 1, fn); cins->arg = clen; cins->cst = add_constant(code, fn); cins->cvars = allocate(fnmemory(fn), clen * sizeof(*cins->cvars)); adjust_depth(1, fn); return cins->cvars; }
static void generate_if(component condition, component success, component failure, fncode fn) { struct ifdata ifdata; ifdata.slab = new_label(fn); ifdata.flab = new_label(fn); ifdata.endlab = new_label(fn); ifdata.success = success; ifdata.failure = failure; generate_condition(condition, ifdata.slab, ifs_code, &ifdata, ifdata.flab, iff_code, &ifdata, fn); set_label(ifdata.endlab, fn); adjust_depth(1, fn); }
static void generate_while(component condition, component iteration, fncode fn) { struct whiledata wdata; wdata.looplab = new_label(fn); wdata.mainlab = new_label(fn); wdata.exitlab = new_label(fn); wdata.endlab = new_label(fn); wdata.code = iteration; env_start_loop(); set_label(wdata.looplab, fn); generate_condition(condition, wdata.mainlab, wmain_code, &wdata, wdata.exitlab, wexit_code, &wdata, fn); set_label(wdata.endlab, fn); env_end_loop(); adjust_depth(1, fn); }
void branch(instruction abranch, label to, fncode fn) /* Effects: Adds a branch instruction to lavel 'to' to instruction list 'next'. A 1 byte offset is added at this stage. Requires: 'branch' be a 1 byte branch instruction. Modifies: fn */ { switch (abranch) { case OPmba3: break; case OPmbt3: case OPmbf3: adjust_depth(-1, fn); break; default: assert(0); } /* assume a small offset by default */ add_ins(abranch, 0, fn)->to = to; }
void ins1(instruction ins, int arg1, fncode fn) /* Effects: Adds instruction ins to code of 'fn'. The instruction has one argument, arg1. Modifies: fn */ { switch (ins) { case OPmreadl: case OPmreadc: case OPmclosure: adjust_depth(1, fn); break; case OPmexitn: case OPmclearl: case OPmwritel: case OPmwritec: case OPmvcheck4 ... OPmvcheck4 + 15: /* Note: OPmexitn *MUST NOT* modify stack depth */ break; default: assert(0); } add_ins(ins, 1, fn)->arg = arg1; }
void generate_if(component condition, component success, component failure, bool discard, fncode fn) { struct ifdata ifdata; ifdata.slab = new_label(fn); ifdata.flab = new_label(fn); ifdata.endlab = new_label(fn); ifdata.success = success; ifdata.failure = failure; ifdata.discard = discard; if (failure) generate_condition(condition, ifdata.slab, ifs_code, &ifdata, ifdata.flab, iff_code, &ifdata, fn); else generate_condition(condition, ifdata.slab, ifs_code, &ifdata, ifdata.endlab, NULL, NULL, fn); set_label(ifdata.endlab, fn); if (!discard) adjust_depth(1, fn); }
int main(int argc, char *argv[]) { coordinates coord; // Coodinates Structure depth depth; color colorsIn[2048]; // Colors array int numColors = 0; // Number of colors to use in color array float colorPower = .3; // Power exponent to use for color selection int colorStart = 0xFF0000, colorEnd = 0xFFFF00; // Default color gradient settings char *filename = "mandelbrot.png"; // Default PNG output name int i; // Misc variables bool noWindow = false; // Default flag for no-window mode // Set default coordinates before reading in args coord.x = -2; // Default Start Coordinates coord.y = 2; coord.xR = 4; // Default Range Coordinates coord.yR = 4; coord.width = -1; // Invalid pixel size, to be set later coord.height = -1; depth.d = 100; // Default Depth level of Mandelbrot Calculation depth.automatic = true; // Generate default gradient first genGradient(colorsIn, &numColors, colorStart, colorEnd); // Parse Arguments for (i=1; i<argc; i++) { if (strcmp(argv[i], "--width") == 0) { coord.width = arg_check_int(argc, argv, i, 1, 10); i++; } else if (strcmp(argv[i], "--height") == 0) { coord.height = arg_check_int(argc, argv, i, 1, 10); i++; } else if (strcmp(argv[i], "--depth") == 0) { depth.automatic = false; depth.d = arg_check_int(argc, argv, i, 1, 10); i++; } else if (strcmp(argv[i], "--coords") == 0) { coord.x = arg_check_float(argc, argv, i, 1); coord.y = arg_check_float(argc, argv, i, 2); coord.xR = arg_check_float(argc, argv, i, 3); coord.yR = arg_check_float(argc, argv, i, 4); i+=4; } else if (strcmp(argv[i], "--spectrum") == 0) { genSpectrum(colorsIn, &numColors); colorPower = .7; } else if (strcmp(argv[i], "--random") == 0) { genRandom(colorsIn, &numColors); colorPower = 1; } else if (strcmp(argv[i], "--gradient") == 0) { colorStart = arg_check_int(argc, argv, i, 1, 16); colorEnd = arg_check_int(argc, argv, i, 2, 16); genGradient(colorsIn, &numColors, colorStart, colorEnd); i+=2; } else if (strcmp(argv[i], "-o") == 0) { filename = argv[i+1]; i++; } else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0 ) { help(); } else if (strcmp(argv[i], "-nw") == 0 ) { noWindow = true; } else { errx(EXIT_FAILURE, "Unknown argument, \"%s\".", argv[i]); } } // Make proportional image if only one dimension is specified // Set to default width and height if not specified if (coord.height < 0 && coord.width > 0) coord.height = coord.width / coord.xR * coord.yR; else if (coord.height > 0 && coord.width < 0) coord.width = coord.height / coord.yR * coord.xR; else if (coord.height < 0 && coord.width < 0) coord.width = coord.height = 1024; coord.xS = coord.xR/coord.width; // X Step Value coord.yS = coord.yR/coord.height; // Y Step Value // Create final array of colors to use that is scaled to the depth that is selected color colors[2048]; scaleColor(colorsIn, colors, numColors, depth.d, colorPower); // If no window mode, just output file and exit if (noWindow) { generate_png(coord, depth.d, filename, colors, numColors); return 0; } // Set up SDL SDL_Init(SDL_INIT_VIDEO); SDL_Window* Main_Window; SDL_Renderer* Main_Renderer; Main_Window = SDL_CreateWindow("Mandelbrot", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, coord.width, coord.height, SDL_WINDOW_RESIZABLE); Main_Renderer = SDL_CreateRenderer(Main_Window, -1, SDL_RENDERER_ACCELERATED); SDL_Texture *texture = SDL_CreateTexture(Main_Renderer, SDL_PIXELFORMAT_RGBX8888, SDL_TEXTUREACCESS_STREAMING, coord.width, coord.height); int pitch; void *pixels; if (SDL_LockTexture(texture, NULL, &pixels, &pitch) != 0) errx(EXIT_FAILURE, "SDL_LockTexture: %s", SDL_GetError()); //uint32_t (*pixel)[coord.height][pitch/sizeof(uint32_t)] = pixels; // Set up struct for tracking mouse movement mouse mouseTracker; mouseTracker.down = false; //Main Loop int maxRender = 2; int needsRender = maxRender; while (1) { // Render Loop if (needsRender > 0) { uint32_t (*pixel)[coord.height][pitch/sizeof(uint32_t)] = pixels; //unsigned long long timer = utime(); //DEBUG - Start Timer float pixelSize = pow(2, --needsRender); //printf("%d %d\n", needsRender, pixelSize); coordinates scaledCoord; scaledCoord.width = coord.width / pixelSize; scaledCoord.height = coord.height / pixelSize; scaledCoord.x = coord.x; scaledCoord.xR = coord.xR; scaledCoord.xS = scaledCoord.xR/scaledCoord.width; scaledCoord.y = coord.y; scaledCoord.yR = coord.yR; scaledCoord.yS = scaledCoord.yR/scaledCoord.height; // y step value SDL_Rect srcrect = {0, 0, scaledCoord.width, scaledCoord.height}; for (int y=0; y<scaledCoord.height; y++) for (int x=0; x<scaledCoord.width; x++) { double xValue = scaledCoord.x + (x * scaledCoord.xS); double yValue = scaledCoord.y - (y * scaledCoord.yS); int result = mandel(xValue, yValue, depth.d); int finalColor = 0; if (result != -1) finalColor = colors[result].hex << 8; (*pixel)[y][x] = finalColor; } SDL_UnlockTexture(texture); SDL_RenderCopy(Main_Renderer, texture, &srcrect, NULL); //printf("%llu - Finish Render\n", utime()-timer); //DEBUG - End Timer SDL_RenderPresent(Main_Renderer); } SDL_Event e; //SDL_WaitEvent(&e); if (SDL_WaitEventTimeout(&e, 10) == 0) continue; if (e.type == SDL_MOUSEWHEEL) { if (e.wheel.y > 0) coord_zoom(&coord, 1); else coord_zoom(&coord, -1); if (depth.automatic == true) { adjust_depth(&coord, &depth); scaleColor(colorsIn, colors, numColors, depth.d, colorPower); } needsRender = maxRender; } if (e.type == SDL_WINDOWEVENT) if (e.window.event == SDL_WINDOWEVENT_RESIZED) { // Adjust view to new size coord.width = e.window.data1; coord.height = e.window.data2; coord.xR = coord.width * coord.xS; coord.yR = coord.height * coord.yS; // Destroy old texture SDL_DestroyTexture(texture); // Make New Texture texture = SDL_CreateTexture(Main_Renderer, SDL_PIXELFORMAT_RGBX8888, SDL_TEXTUREACCESS_STREAMING, coord.width, coord.height); // Lock with new texture if (SDL_LockTexture(texture, NULL, &pixels, &pitch) != 0) errx(EXIT_FAILURE, "SDL_LockTexture: %s", SDL_GetError()); // Rerender needsRender = maxRender; } if (e.type == SDL_MOUSEBUTTONDOWN) if (e.button.state == SDL_PRESSED) { mouseTracker.mouseX = e.motion.x; mouseTracker.mouseY = e.motion.y; mouseTracker.coordX = coord.x; mouseTracker.coordY = coord.y; mouseTracker.down = true; } if (e.type == SDL_MOUSEBUTTONUP) if (e.button.state == SDL_RELEASED) mouseTracker.down = false; if (e.type == SDL_MOUSEMOTION && mouseTracker.down == true) { coord.x = mouseTracker.coordX + ((mouseTracker.mouseX - e.motion.x) * coord.xS); coord.y = mouseTracker.coordY - ((mouseTracker.mouseY - e.motion.y) * coord.yS); needsRender = maxRender; } if (e.type == SDL_KEYUP) { if (e.key.keysym.sym == SDLK_p) print_coords(&coord, &depth); if (e.key.keysym.sym == SDLK_s) generate_png(coord, depth.d, filename, colors, numColors); if (e.key.keysym.sym == SDLK_EQUALS || e.key.keysym.sym == SDLK_MINUS) { depth.automatic = false; if (e.key.keysym.sym == SDLK_EQUALS) depth.d += 5; if (e.key.keysym.sym == SDLK_MINUS) if (depth.d > 5) depth.d -= 5; scaleColor(colorsIn, colors, numColors, depth.d, colorPower); needsRender = maxRender; } } if (e.type == SDL_QUIT) { SDL_Log("Program quit after %i ticks", e.quit.timestamp); break; } } return 0; }
static void negamax(struct node *node) { assert(node->alpha < node->beta); node_init(node); if (check_trivial_draw(node) == is_trivial_draw) return; ht_prefetch(node->tt, node->pos->zhash[0]); if (adjust_depth(node) == too_deep) return; if (handle_mate_search(node) == mate_search_handled) return; if (setup_bounds(node) == stand_pat_cutoff) return; if (setup_moves(node) == no_legal_moves) return; if (node->forced_pv == 0) { if (fetch_hash_value(node) == hash_cutoff) return; } else { int r = move_order_add_hint(node->mo, node->forced_pv, 0); (void) r; assert(r == 0); } if (try_null_move_prune(node) == prune_successfull) return; if (recheck_bounds(node) == alpha_beta_range_too_small) return; assert(node->beta > -max_value + 2); assert(node->alpha < max_value - 2); do { move_order_pick_next(node->mo); if (can_prune_moves(node)) break; move m = mo_current_move(node->mo); int LMR_factor; setup_child_node(node, m, &LMR_factor); int value = negamax_child(node); if (LMR_factor != 0) { if (value > node->alpha) { reset_child_after_lmr(node); value = negamax_child(node); } else { debug_trace_tree_pop_move(node); continue; } } value = handle_beta_extension(node, m, value); if (value > node->value) { node->value = value; if (value > node->alpha) { node->alpha = value; new_best_move(node, m); if (node->alpha >= node->beta) fail_high(node); else node->expected_type = PV_node; } } debug_trace_tree_pop_move(node); } while (search_more_moves(node)); ht_entry entry = hash_current_node_value(node); setup_best_move(node); assert(node->repetition_affected_any == 0 || !node->is_GHI_barrier); assert(node->repetition_affected_best == 0 || !node->is_GHI_barrier); if (node->depth > 0) { if (node->best_move != 0) entry = ht_set_move(entry, node->best_move); if (node->null_move_search_failed) entry = ht_set_no_null(entry); if (ht_value_type(entry) != 0 || node->best_move != 0) ht_pos_insert(node->tt, node->pos, entry); } if (node->value < node->lower_bound) node->value = node->lower_bound; node->forced_pv = 0; }
static void generate_component(component comp, fncode fn) { clist args; set_lineno(comp->lineno, fn); switch (comp->vclass) { case c_assign: { ulong offset; bool is_static; variable_class vclass = env_lookup(comp->u.assign.symbol, &offset, false, true, &is_static); component val = comp->u.assign.value; if (val->vclass == c_closure) { /* Defining a function, give it a name */ if (vclass == global_var) val->u.closure->varname = comp->u.assign.symbol; else { char *varname = allocate(fnmemory(fn), strlen(comp->u.assign.symbol) + 7); sprintf(varname, "local-%s", comp->u.assign.symbol); val->u.closure->varname = varname; } } if (is_static) { ins1(op_recall + vclass, offset, fn); generate_component(comp->u.assign.value, fn); mexecute(g_symbol_set, NULL, 2, fn); break; } generate_component(comp->u.assign.value, fn); set_lineno(comp->lineno, fn); if (vclass == global_var) massign(offset, comp->u.assign.symbol, fn); else ins1(op_assign + vclass, offset, fn); /* Note: varname becomes a dangling pointer when fnmemory(fn) is deallocated, but it is never used again so this does not cause a problem. */ break; } case c_vref: case c_recall: { bool is_vref = comp->vclass == c_vref; ulong offset; bool is_static; variable_class vclass = env_lookup(comp->u.recall, &offset, true, is_vref, &is_static); if (is_static) { assert(vclass != global_var); ins1(op_recall + vclass, offset, fn); ulong gidx = is_vref ? g_make_symbol_ref : g_symbol_get; mexecute(gidx, NULL, 1, fn); break; } if (vclass != global_var) ins1((is_vref ? op_vref : op_recall) + vclass, offset, fn); else if (is_vref) { if (!mwritable(offset, comp->u.recall)) return; ins_constant(makeint(offset), fn); } else mrecall(offset, comp->u.recall, fn); if (is_vref) mexecute(g_make_variable_ref, "make_variable_ref", 1, fn); break; } case c_constant: ins_constant(make_constant(comp->u.cst), fn); break; case c_closure: { uword idx; idx = add_constant(generate_function(comp->u.closure, false, fn), fn); if (idx < ARG1_MAX) ins1(op_closure_code1, idx, fn); else ins2(op_closure_code2, idx, fn); break; } case c_block: generate_block(comp->u.blk, fn); break; case c_labeled: start_block(comp->u.labeled.name, fn); generate_component(comp->u.labeled.expression, fn); end_block(fn); break; case c_exit: generate_component(comp->u.labeled.expression, fn); if (!exit_block(comp->u.labeled.name, fn)) { if (!comp->u.labeled.name) log_error("no loop to exit from"); else log_error("no block labeled %s", comp->u.labeled.name); } break; case c_execute: { uword count; generate_args(comp->u.execute->next, fn, &count); set_lineno(comp->lineno, fn); generate_execute(comp->u.execute->c, count, fn); break; } case c_builtin: args = comp->u.builtin.args; switch (comp->u.builtin.fn) { case b_if: { block cb = new_codeblock(fnmemory(fn), NULL, new_clist(fnmemory(fn), args->next->c, new_clist(fnmemory(fn), component_undefined, NULL)), NULL, NULL, -1); generate_if(args->c, new_component(fnmemory(fn), args->next->c->lineno, c_block, cb), component_undefined, fn); break; } case b_ifelse: generate_if(args->c, args->next->c, args->next->next->c, fn); break; case b_sc_and: case b_sc_or: generate_if(comp, component_true, component_false, fn); break; case b_while: generate_while(args->c, args->next->c, fn); break; case b_loop: { label loop = new_label(fn); env_start_loop(); set_label(loop, fn); start_block(NULL, fn); generate_component(args->c, fn); branch(op_loop1, loop, fn); end_block(fn); env_end_loop(); adjust_depth(1, fn); break; } case b_add: case b_subtract: case b_ref: case b_set: case b_bitor: case b_bitand: case b_not: case b_eq: case b_ne: case b_lt: case b_le: case b_ge: case b_gt: { uword count; assert(comp->u.builtin.fn < last_builtin); generate_args(args, fn, &count); set_lineno(comp->lineno, fn); ins0(builtin_ops[comp->u.builtin.fn], fn); break; } default: { uword count; assert(comp->u.builtin.fn < last_builtin); generate_args(args, fn, &count); set_lineno(comp->lineno, fn); mexecute(builtin_functions[comp->u.builtin.fn], NULL, count, fn); break; } } break; default: abort(); } }
void generate_component(component comp, const char *mlabel, bool discard, fncode fn) { clist args; switch (comp->vclass) { case c_assign: { u16 offset; mtype t; variable_class vclass = env_lookup(comp->l, comp->u.assign.symbol, &offset, &t, FALSE); component val = comp->u.assign.value; if (val->vclass == c_closure) { /* Defining a function, give it a name */ if (vclass == global_var) val->u.closure->varname = comp->u.assign.symbol; else { char *varname = allocate(fnmemory(fn), strlen(comp->u.assign.symbol) + 7); sprintf(varname, "local-%s", comp->u.assign.symbol); val->u.closure->varname = varname; } } generate_component(comp->u.assign.value, NULL, FALSE, fn); if (t != stype_any) ins0(OPmscheck4 + t, fn); if (vclass == global_var) massign(comp->l, offset, comp->u.assign.symbol, fn); else if (vclass == closure_var) ins1(OPmwritec, offset, fn); else ins1(OPmwritel, offset, fn); /* Note: varname becomes a dangling pointer when fnmemory(fn) is deallocated, but it is never used again so this does not cause a problem. */ break; } case c_recall: scompile_recall(comp->l, comp->u.recall, fn); break; case c_constant: ins_constant(make_constant(comp->u.cst, FALSE, fn), fn); break; case c_scheme: scheme_compile_mgc(comp->l, make_constant(comp->u.cst, TRUE, fn), discard, fn); discard = FALSE; break; case c_closure: generate_function(comp->u.closure, fn); break; case c_block: generate_block(comp->u.blk, discard, fn); discard = FALSE; break; case c_decl: { vlist decl, next; /* declare variables one at a time (any x = y, y = 2; is an error) */ for (decl = comp->u.decls; decl; decl = next) { next = decl->next; decl->next = NULL; env_declare(decl); generate_decls(decl, fn); } generate_component(component_undefined, NULL, FALSE, fn); break; } case c_labeled: { start_block(comp->u.labeled.name, FALSE, discard, fn); generate_component(comp->u.labeled.expression, comp->u.labeled.name, discard, fn); end_block(fn); discard = FALSE; break; } case c_exit: { bool discard_exit; label exitlab = exit_block(comp->u.labeled.name, FALSE, &discard_exit, fn); if (comp->u.labeled.expression != component_undefined && discard_exit) warning(comp->l, "break result is ignored"); generate_component(comp->u.labeled.expression, NULL, discard_exit, fn); if (exitlab) branch(OPmba3, exitlab, fn); else { if (!comp->u.labeled.name) log_error(comp->l, "No loop to exit from"); else log_error(comp->l, "No block labeled %s", comp->u.labeled.name); } /* Callers expect generate_component to increase stack depth by 1 */ if (discard_exit) adjust_depth(1, fn); break; } case c_continue: { bool discard_exit; /* Meaningless for continue blocks */ label exitlab = exit_block(comp->u.labeled.name, TRUE, &discard_exit, fn); if (exitlab) branch(OPmba3, exitlab, fn); else { if (comp->u.labeled.name[0] == '<') log_error(comp->l, "No loop to continue"); else log_error(comp->l, "No loop labeled %s", comp->u.labeled.name); } /* Callers expect generate_component to increase stack depth by 1 (*/ adjust_depth(1, fn); break; } case c_execute: { u16 count; generate_args(comp->u.execute->next, fn, &count); generate_execute(comp->u.execute->c, count, fn); break; } case c_builtin: args = comp->u.builtin.args; switch (comp->u.builtin.fn) { case b_if: generate_if(args->c, args->next->c, NULL, TRUE, fn); generate_component(component_undefined, NULL, FALSE, fn); break; case b_ifelse: generate_if(args->c, args->next->c, args->next->next->c, discard, fn); discard = FALSE; break; case b_sc_and: case b_sc_or: generate_if(comp, component_true, component_false, discard, fn); discard = FALSE; break; case b_while: enter_loop(fn); generate_while(args->c, args->next->c, mlabel, discard, fn); exit_loop(fn); discard = FALSE; break; case b_dowhile: enter_loop(fn); generate_dowhile(args->c, args->next->c, mlabel, discard, fn); exit_loop(fn); discard = FALSE; break; case b_for: enter_loop(fn); generate_for(args->c, args->next->c, args->next->next->c, args->next->next->next->c, mlabel, discard, fn); exit_loop(fn); discard = FALSE; break; default: { u16 count; assert(comp->u.builtin.fn < last_builtin); generate_args(args, fn, &count); ins0(builtin_ops[comp->u.builtin.fn], fn); break; } case b_cons: { u16 count; u16 goffset; mtype t; assert(comp->u.builtin.fn < last_builtin); generate_args(args, fn, &count); goffset = global_lookup(fnglobals(fn), builtin_functions[comp->u.builtin.fn], &t); mexecute(comp->l, goffset, NULL, count, fn); break; } } break; default: assert(0); } if (discard) ins0(OPmpop, fn); }