|  |  |  | @@ -25,17 +25,64 @@ | 
		
	
		
			
				|  |  |  |  | #include <janet.h> | 
		
	
		
			
				|  |  |  |  | #include "sysir.h" | 
		
	
		
			
				|  |  |  |  | #include "vector.h" | 
		
	
		
			
				|  |  |  |  | #include "util.h" | 
		
	
		
			
				|  |  |  |  | #endif | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | /* | 
		
	
		
			
				|  |  |  |  |  * Wrap stuff up in a context struct | 
		
	
		
			
				|  |  |  |  |  */ | 
		
	
		
			
				|  |  |  |  | static const char *register_names[] = { | 
		
	
		
			
				|  |  |  |  |     "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", | 
		
	
		
			
				|  |  |  |  |     "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" | 
		
	
		
			
				|  |  |  |  | }; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static uint32_t v2reg(JanetTable *assignments, uint32_t var) { | 
		
	
		
			
				|  |  |  |  |     return (uint32_t) janet_unwrap_number(janet_table_get(assignments, janet_wrap_number(var))); | 
		
	
		
			
				|  |  |  |  | /* Get the layout for types */ | 
		
	
		
			
				|  |  |  |  | JanetSysTypeLayout get_x64layout(JanetSysTypeInfo info) { | 
		
	
		
			
				|  |  |  |  |     JanetSysTypeLayout layout; | 
		
	
		
			
				|  |  |  |  |     switch (info.prim) { | 
		
	
		
			
				|  |  |  |  |         default: | 
		
	
		
			
				|  |  |  |  |             layout.size = 1; | 
		
	
		
			
				|  |  |  |  |             layout.alignment = 1; | 
		
	
		
			
				|  |  |  |  |             break; | 
		
	
		
			
				|  |  |  |  |         case JANET_PRIM_S8: | 
		
	
		
			
				|  |  |  |  |         case JANET_PRIM_U8: | 
		
	
		
			
				|  |  |  |  |         case JANET_PRIM_BOOLEAN: | 
		
	
		
			
				|  |  |  |  |             layout.size = 1; | 
		
	
		
			
				|  |  |  |  |             layout.alignment = 1; | 
		
	
		
			
				|  |  |  |  |             break; | 
		
	
		
			
				|  |  |  |  |         case JANET_PRIM_S16: | 
		
	
		
			
				|  |  |  |  |         case JANET_PRIM_U16: | 
		
	
		
			
				|  |  |  |  |             layout.size = 2; | 
		
	
		
			
				|  |  |  |  |             layout.alignment = 2; | 
		
	
		
			
				|  |  |  |  |             break; | 
		
	
		
			
				|  |  |  |  |         case JANET_PRIM_S32: | 
		
	
		
			
				|  |  |  |  |         case JANET_PRIM_U32: | 
		
	
		
			
				|  |  |  |  |             layout.size = 4; | 
		
	
		
			
				|  |  |  |  |             layout.alignment = 4; | 
		
	
		
			
				|  |  |  |  |             break; | 
		
	
		
			
				|  |  |  |  |         case JANET_PRIM_U64: | 
		
	
		
			
				|  |  |  |  |         case JANET_PRIM_S64: | 
		
	
		
			
				|  |  |  |  |         case JANET_PRIM_POINTER: | 
		
	
		
			
				|  |  |  |  |             layout.size = 8; | 
		
	
		
			
				|  |  |  |  |             layout.alignment = 8; | 
		
	
		
			
				|  |  |  |  |             break; | 
		
	
		
			
				|  |  |  |  |         case JANET_PRIM_F32: | 
		
	
		
			
				|  |  |  |  |         case JANET_PRIM_F64: | 
		
	
		
			
				|  |  |  |  |             layout.size = 8; | 
		
	
		
			
				|  |  |  |  |             layout.alignment = 8; | 
		
	
		
			
				|  |  |  |  |             break; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     return layout; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | JanetSysSpill *assign_registers(JanetSysIR *ir, JanetTable *assignments, | 
		
	
		
			
				|  |  |  |  | static uint32_t v2reg_dflt(JanetTable *assignments, uint32_t var, uint32_t dflt) { | 
		
	
		
			
				|  |  |  |  |     Janet check = janet_table_get(assignments, janet_wrap_number(var)); | 
		
	
		
			
				|  |  |  |  |     if (janet_checktype(check, JANET_NUMBER)) { | 
		
	
		
			
				|  |  |  |  |         return (uint32_t) janet_unwrap_number(check); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     return dflt; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | JanetSysSpill *assign_registers(JanetSysIR *ir, | 
		
	
		
			
				|  |  |  |  |         JanetSysTypeLayout *layouts, | 
		
	
		
			
				|  |  |  |  |         JanetTable *assignments, | 
		
	
		
			
				|  |  |  |  |         uint32_t max_reg) { | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     /* simplest register assignment algorithm - first n variables | 
		
	
	
		
			
				
					
					|  |  |  | @@ -48,13 +95,19 @@ JanetSysSpill *assign_registers(JanetSysIR *ir, JanetTable *assignments, | 
		
	
		
			
				|  |  |  |  |     for (uint32_t i = 0; i < ir->register_count; i++) { | 
		
	
		
			
				|  |  |  |  |         if (i < max_reg) { | 
		
	
		
			
				|  |  |  |  |             janet_table_put(assignments, janet_wrap_number(i), janet_wrap_number(i)); | 
		
	
		
			
				|  |  |  |  |         } else { | 
		
	
		
			
				|  |  |  |  |             janet_table_put(assignments, janet_wrap_number(i), janet_wrap_number(max_reg)); | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     // TODO - keep track of where we spill to. Simple idea would be to assign each variable | 
		
	
		
			
				|  |  |  |  |     // a stack location. | 
		
	
		
			
				|  |  |  |  |     /* Assign all slots a stack location */ | 
		
	
		
			
				|  |  |  |  |     /* TODO - be smarter about this */ | 
		
	
		
			
				|  |  |  |  |     uint32_t *stack_locations = janet_smalloc(ir->register_count * sizeof(uint32_t)); | 
		
	
		
			
				|  |  |  |  |     uint32_t next_loc = 0; | 
		
	
		
			
				|  |  |  |  |     for (uint32_t i = 0; i < ir->register_count; i++) { | 
		
	
		
			
				|  |  |  |  |         JanetSysTypeLayout layout = layouts[i]; | 
		
	
		
			
				|  |  |  |  |         next_loc = (next_loc + layout.alignment - 1) / layout.alignment * layout.alignment; | 
		
	
		
			
				|  |  |  |  |         stack_locations[i] = next_loc; | 
		
	
		
			
				|  |  |  |  |         next_loc += layout.size; | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     /* Generate spills. Spills occur iff using the temporary register (max_reg) */ | 
		
	
		
			
				|  |  |  |  |     JanetSysSpill *spills = NULL; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -89,20 +142,26 @@ JanetSysSpill *assign_registers(JanetSysIR *ir, JanetTable *assignments, | 
		
	
		
			
				|  |  |  |  |             case JANET_SYSOP_GTE: | 
		
	
		
			
				|  |  |  |  |             case JANET_SYSOP_POINTER_ADD: | 
		
	
		
			
				|  |  |  |  |             case JANET_SYSOP_POINTER_SUBTRACT: | 
		
	
		
			
				|  |  |  |  |                 rega = v2reg(assignments, instruction.three.dest); | 
		
	
		
			
				|  |  |  |  |                 regb = v2reg(assignments, instruction.three.lhs); | 
		
	
		
			
				|  |  |  |  |                 regc = v2reg(assignments, instruction.three.rhs); | 
		
	
		
			
				|  |  |  |  |                 if (rega == max_reg) { | 
		
	
		
			
				|  |  |  |  |                 rega = v2reg_dflt(assignments, instruction.three.dest, max_reg); | 
		
	
		
			
				|  |  |  |  |                 regb = v2reg_dflt(assignments, instruction.three.lhs, max_reg + 1); | 
		
	
		
			
				|  |  |  |  |                 regc = v2reg_dflt(assignments, instruction.three.rhs, max_reg + 2); | 
		
	
		
			
				|  |  |  |  |                 spill.regs[0] = rega; | 
		
	
		
			
				|  |  |  |  |                 spill.regs[1] = regb; | 
		
	
		
			
				|  |  |  |  |                 spill.regs[2] = regc; | 
		
	
		
			
				|  |  |  |  |                 if (rega >= max_reg) { | 
		
	
		
			
				|  |  |  |  |                     spill.spills[0] = JANET_SYS_SPILL_WRITE; | 
		
	
		
			
				|  |  |  |  |                     spill.regs[0] = instruction.three.dest; | 
		
	
		
			
				|  |  |  |  |                     spill.stack_offsets[0] = stack_locations[instruction.three.dest]; | 
		
	
		
			
				|  |  |  |  |                     spill.stack_sizes[0] = layouts[instruction.three.dest].size; | 
		
	
		
			
				|  |  |  |  |                 } | 
		
	
		
			
				|  |  |  |  |                 if (regb == max_reg) { | 
		
	
		
			
				|  |  |  |  |                 if (regb >= max_reg) { | 
		
	
		
			
				|  |  |  |  |                     spill.spills[1] = JANET_SYS_SPILL_READ; | 
		
	
		
			
				|  |  |  |  |                     spill.regs[1] = instruction.three.lhs; | 
		
	
		
			
				|  |  |  |  |                     spill.stack_offsets[1] = stack_locations[instruction.three.lhs]; | 
		
	
		
			
				|  |  |  |  |                     spill.stack_sizes[1] = layouts[instruction.three.lhs].size; | 
		
	
		
			
				|  |  |  |  |                 } | 
		
	
		
			
				|  |  |  |  |                 if (regc == max_reg) { | 
		
	
		
			
				|  |  |  |  |                 if (regc >= max_reg) { | 
		
	
		
			
				|  |  |  |  |                     spill.spills[2] = JANET_SYS_SPILL_READ; | 
		
	
		
			
				|  |  |  |  |                     spill.regs[2] = instruction.three.rhs; | 
		
	
		
			
				|  |  |  |  |                     spill.stack_offsets[2] = stack_locations[instruction.three.rhs]; | 
		
	
		
			
				|  |  |  |  |                     spill.stack_sizes[2] = layouts[instruction.three.rhs].size; | 
		
	
		
			
				|  |  |  |  |                 } | 
		
	
		
			
				|  |  |  |  |                 break; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
	
		
			
				
					
					|  |  |  | @@ -110,41 +169,51 @@ JanetSysSpill *assign_registers(JanetSysIR *ir, JanetTable *assignments, | 
		
	
		
			
				|  |  |  |  |             case JANET_SYSOP_MOVE: | 
		
	
		
			
				|  |  |  |  |             case JANET_SYSOP_CAST: | 
		
	
		
			
				|  |  |  |  |             case JANET_SYSOP_BNOT: | 
		
	
		
			
				|  |  |  |  |                 rega = v2reg(assignments, instruction.two.dest); | 
		
	
		
			
				|  |  |  |  |                 regb = v2reg(assignments, instruction.two.src); | 
		
	
		
			
				|  |  |  |  |                 if (rega == max_reg) { | 
		
	
		
			
				|  |  |  |  |                 rega = v2reg_dflt(assignments, instruction.two.dest, max_reg); | 
		
	
		
			
				|  |  |  |  |                 regb = v2reg_dflt(assignments, instruction.two.src, max_reg + 1); | 
		
	
		
			
				|  |  |  |  |                 spill.regs[0] = rega; | 
		
	
		
			
				|  |  |  |  |                 spill.regs[1] = regb; | 
		
	
		
			
				|  |  |  |  |                 if (rega >= max_reg) { | 
		
	
		
			
				|  |  |  |  |                     spill.spills[0] = JANET_SYS_SPILL_WRITE; | 
		
	
		
			
				|  |  |  |  |                     spill.regs[0] = instruction.two.dest; | 
		
	
		
			
				|  |  |  |  |                     spill.stack_offsets[0] = stack_locations[instruction.two.dest]; | 
		
	
		
			
				|  |  |  |  |                     spill.stack_sizes[0] = layouts[instruction.two.dest].size; | 
		
	
		
			
				|  |  |  |  |                 } | 
		
	
		
			
				|  |  |  |  |                 if (regb == max_reg) { | 
		
	
		
			
				|  |  |  |  |                 if (regb >= max_reg) { | 
		
	
		
			
				|  |  |  |  |                     spill.spills[1] = JANET_SYS_SPILL_READ; | 
		
	
		
			
				|  |  |  |  |                     spill.regs[1] = instruction.two.src; | 
		
	
		
			
				|  |  |  |  |                     spill.stack_offsets[1] = stack_locations[instruction.two.src]; | 
		
	
		
			
				|  |  |  |  |                     spill.stack_sizes[1] = layouts[instruction.two.src].size; | 
		
	
		
			
				|  |  |  |  |                 } | 
		
	
		
			
				|  |  |  |  |                 break; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |             /* branch COND */ | 
		
	
		
			
				|  |  |  |  |             case JANET_SYSOP_BRANCH: | 
		
	
		
			
				|  |  |  |  |             case JANET_SYSOP_BRANCH_NOT: | 
		
	
		
			
				|  |  |  |  |                 rega = v2reg(assignments, instruction.branch.cond); | 
		
	
		
			
				|  |  |  |  |                 if (rega == max_reg) { | 
		
	
		
			
				|  |  |  |  |                 rega = v2reg_dflt(assignments, instruction.branch.cond, max_reg); | 
		
	
		
			
				|  |  |  |  |                 spill.regs[0] = rega; | 
		
	
		
			
				|  |  |  |  |                 if (rega >= max_reg) { | 
		
	
		
			
				|  |  |  |  |                     spill.spills[0] = JANET_SYS_SPILL_READ; | 
		
	
		
			
				|  |  |  |  |                     spill.regs[0] = instruction.branch.cond; | 
		
	
		
			
				|  |  |  |  |                     spill.stack_offsets[0] = stack_locations[instruction.branch.cond]; | 
		
	
		
			
				|  |  |  |  |                     spill.stack_sizes[0] = layouts[instruction.branch.cond].size; | 
		
	
		
			
				|  |  |  |  |                 } | 
		
	
		
			
				|  |  |  |  |                 break; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |             case JANET_SYSOP_CONSTANT: | 
		
	
		
			
				|  |  |  |  |                 rega = v2reg(assignments, instruction.constant.dest); | 
		
	
		
			
				|  |  |  |  |                 if (rega == max_reg) { | 
		
	
		
			
				|  |  |  |  |                 rega = v2reg_dflt(assignments, instruction.constant.dest, max_reg); | 
		
	
		
			
				|  |  |  |  |                 spill.regs[0] = rega; | 
		
	
		
			
				|  |  |  |  |                 if (rega >= max_reg) { | 
		
	
		
			
				|  |  |  |  |                     spill.spills[0] = JANET_SYS_SPILL_WRITE; | 
		
	
		
			
				|  |  |  |  |                     spill.regs[0] = instruction.constant.dest; | 
		
	
		
			
				|  |  |  |  |                     spill.stack_offsets[0] = stack_locations[instruction.constant.dest]; | 
		
	
		
			
				|  |  |  |  |                     spill.stack_sizes[0] = layouts[instruction.constant.dest].size; | 
		
	
		
			
				|  |  |  |  |                 } | 
		
	
		
			
				|  |  |  |  |                 break; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |             case JANET_SYSOP_RETURN: | 
		
	
		
			
				|  |  |  |  |                 rega = v2reg(assignments, instruction.one.src); | 
		
	
		
			
				|  |  |  |  |                 if (rega == max_reg) { | 
		
	
		
			
				|  |  |  |  |                 rega = v2reg_dflt(assignments, instruction.one.src, max_reg); | 
		
	
		
			
				|  |  |  |  |                 spill.regs[0] = rega; | 
		
	
		
			
				|  |  |  |  |                 if (rega >= max_reg) { | 
		
	
		
			
				|  |  |  |  |                     spill.spills[0] = JANET_SYS_SPILL_READ; | 
		
	
		
			
				|  |  |  |  |                     spill.regs[0] = instruction.one.src; | 
		
	
		
			
				|  |  |  |  |                     spill.stack_offsets[0] = stack_locations[instruction.one.src]; | 
		
	
		
			
				|  |  |  |  |                     spill.stack_sizes[0] = layouts[instruction.one.src].size; | 
		
	
		
			
				|  |  |  |  |                 } | 
		
	
		
			
				|  |  |  |  |                 break; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
	
		
			
				
					
					|  |  |  | @@ -152,10 +221,12 @@ JanetSysSpill *assign_registers(JanetSysIR *ir, JanetTable *assignments, | 
		
	
		
			
				|  |  |  |  |             case JANET_SYSOP_ARG: | 
		
	
		
			
				|  |  |  |  |                 for (int j = 0; j < 3; j++) { | 
		
	
		
			
				|  |  |  |  |                     uint32_t var = instruction.arg.args[j]; | 
		
	
		
			
				|  |  |  |  |                     rega = v2reg(assignments, var); | 
		
	
		
			
				|  |  |  |  |                     if (rega == max_reg) { | 
		
	
		
			
				|  |  |  |  |                     rega = v2reg_dflt(assignments, var, 0); | 
		
	
		
			
				|  |  |  |  |                     spill.regs[j] = rega; | 
		
	
		
			
				|  |  |  |  |                     if (rega >= max_reg) { /* Unused elements must be 0 */ | 
		
	
		
			
				|  |  |  |  |                         spill.spills[j] = JANET_SYS_SPILL_READ; | 
		
	
		
			
				|  |  |  |  |                         spill.regs[j] = var; | 
		
	
		
			
				|  |  |  |  |                         spill.stack_offsets[j] = stack_locations[instruction.arg.args[j]]; | 
		
	
		
			
				|  |  |  |  |                         spill.stack_sizes[j] = layouts[instruction.arg.args[j]].size; | 
		
	
		
			
				|  |  |  |  |                     } | 
		
	
		
			
				|  |  |  |  |                 } | 
		
	
		
			
				|  |  |  |  |                 break; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -163,46 +234,88 @@ JanetSysSpill *assign_registers(JanetSysIR *ir, JanetTable *assignments, | 
		
	
		
			
				|  |  |  |  |             /* Variable arg */ | 
		
	
		
			
				|  |  |  |  |             case JANET_SYSOP_CALL: | 
		
	
		
			
				|  |  |  |  |             case JANET_SYSOP_CALLK: | 
		
	
		
			
				|  |  |  |  |                 /* TODO */ | 
		
	
		
			
				|  |  |  |  |                 break; | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |         janet_v_push(spills, spill); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     janet_sfree(layouts); | 
		
	
		
			
				|  |  |  |  |     janet_sfree(stack_locations); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     return spills; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static void do_spills(JanetBuffer *buffer, JanetSysSpill *spills, uint32_t index) { | 
		
	
		
			
				|  |  |  |  | typedef struct { | 
		
	
		
			
				|  |  |  |  |     uint32_t temps[3]; | 
		
	
		
			
				|  |  |  |  | } JanetTempRegs; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static JanetTempRegs do_spills_read(JanetBuffer *buffer, JanetSysSpill *spills, uint32_t index) { | 
		
	
		
			
				|  |  |  |  |     JanetSysSpill spill = spills[index]; | 
		
	
		
			
				|  |  |  |  |     JanetTempRegs temps; | 
		
	
		
			
				|  |  |  |  |     for (int spi = 0; spi < 3; spi++) { | 
		
	
		
			
				|  |  |  |  |         uint32_t reg = spill.regs[spi]; | 
		
	
		
			
				|  |  |  |  |         temps.temps[spi] = reg; | 
		
	
		
			
				|  |  |  |  |         if (spill.spills[spi] == JANET_SYS_SPILL_READ || spill.spills[spi] == JANET_SYS_SPILL_BOTH) { | 
		
	
		
			
				|  |  |  |  |             // emit load | 
		
	
		
			
				|  |  |  |  |             uint32_t x = spill.stack_offsets[spi]; | 
		
	
		
			
				|  |  |  |  |             uint32_t s = spill.stack_sizes[spi]; | 
		
	
		
			
				|  |  |  |  |             janet_formatb(buffer, "load%u r%u from stack[%u] ; SPILL\n", s, reg, x); | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     return temps; | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | static void do_spills_write(JanetBuffer *buffer, JanetSysSpill *spills, uint32_t index) { | 
		
	
		
			
				|  |  |  |  |     JanetSysSpill spill = spills[index]; | 
		
	
		
			
				|  |  |  |  |     for (int spi = 0; spi < 3; spi++) { | 
		
	
		
			
				|  |  |  |  |         if (spill.spills[spi] == JANET_SYS_SPILL_WRITE || spill.spills[spi] == JANET_SYS_SPILL_BOTH) { | 
		
	
		
			
				|  |  |  |  |             // emit store | 
		
	
		
			
				|  |  |  |  |             uint32_t reg = spill.regs[spi]; | 
		
	
		
			
				|  |  |  |  |             void *x = (void *) 0x123456; | 
		
	
		
			
				|  |  |  |  |             janet_formatb(buffer, "store r%u to %v ; SPILL\n", reg, janet_wrap_pointer(x)); | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |         if (spill.spills[spi] == JANET_SYS_SPILL_READ || spill.spills[spi] == JANET_SYS_SPILL_BOTH) { | 
		
	
		
			
				|  |  |  |  |             // emit load | 
		
	
		
			
				|  |  |  |  |             uint32_t reg = spill.regs[spi]; | 
		
	
		
			
				|  |  |  |  |             void *x = (void *) 0x123456; | 
		
	
		
			
				|  |  |  |  |             janet_formatb(buffer, "load r%u from %v ; SPILL\n", reg, janet_wrap_pointer(x)); | 
		
	
		
			
				|  |  |  |  |             uint32_t x = spill.stack_offsets[spi]; | 
		
	
		
			
				|  |  |  |  |             uint32_t s = spill.stack_sizes[spi]; | 
		
	
		
			
				|  |  |  |  |             janet_formatb(buffer, "store%u r%u to stack[%u] ; SPILL\n", s, reg, x); | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetBuffer *buffer) { | 
		
	
		
			
				|  |  |  |  |     /* For now, emit assembly for nasm. Eventually an assembler for use with Janet would be good. */ | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     JanetSysTypeLayout *all_layouts = janet_smalloc(linkage->type_def_count * sizeof(JanetSysTypeLayout)); | 
		
	
		
			
				|  |  |  |  |     for (uint32_t i = 0; i < linkage->type_def_count; i++) { | 
		
	
		
			
				|  |  |  |  |         all_layouts[i] = get_x64layout(linkage->type_defs[i]); | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     /* Emit prelude */ | 
		
	
		
			
				|  |  |  |  |     janet_formatb(buffer, "bits 64\ndefault rel\n\n"); | 
		
	
		
			
				|  |  |  |  |     janet_formatb(buffer, "segment .text\n"); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |     /* Do register allocation  */ | 
		
	
		
			
				|  |  |  |  |     for (int32_t i = 0; i < linkage->ir_ordered->count; i++) { | 
		
	
		
			
				|  |  |  |  |         JanetSysIR *ir = janet_unwrap_pointer(linkage->ir_ordered->data[i]); | 
		
	
		
			
				|  |  |  |  |         JanetTable *assignments = janet_table(0); | 
		
	
		
			
				|  |  |  |  |         /* 16 total 64 bit registers - 3 temp */ | 
		
	
		
			
				|  |  |  |  |         JanetSysSpill *spills = assign_registers(ir, assignments, 113); | 
		
	
		
			
				|  |  |  |  |         JanetTempRegs temps; | 
		
	
		
			
				|  |  |  |  |         /* Get type layouts */ | 
		
	
		
			
				|  |  |  |  |         JanetSysTypeLayout *layouts = janet_smalloc(ir->register_count * sizeof(JanetSysTypeLayout)); | 
		
	
		
			
				|  |  |  |  |         for (uint32_t i = 0; i < ir->register_count; i++) { | 
		
	
		
			
				|  |  |  |  |             layouts[i] = all_layouts[ir->types[i]]; | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |         JanetSysSpill *spills = assign_registers(ir, layouts, assignments, 13); | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |         /* Allow combining compare + branch instructions more easily */ | 
		
	
		
			
				|  |  |  |  |         int skip_branch = 0; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |         /* Emit constant strings */ | 
		
	
		
			
				|  |  |  |  |         for (int32_t j = 0; j < ir->constant_count; j++) { | 
		
	
		
			
				|  |  |  |  |             janet_formatb(buffer, ".CONST%u:\n  .string %p\n", j, ir->constants[j]); | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |         /* Emit prelude */ | 
		
	
		
			
				|  |  |  |  |         if (ir->link_name != NULL) { | 
		
	
		
			
				|  |  |  |  |             janet_formatb(buffer, ".%s\n", ir->link_name); | 
		
	
		
			
				|  |  |  |  |             janet_formatb(buffer, "\n%s:\n", ir->link_name); | 
		
	
		
			
				|  |  |  |  |         } else { | 
		
	
		
			
				|  |  |  |  |             janet_formatb(buffer, "._section_%d\n", i); | 
		
	
		
			
				|  |  |  |  |             janet_formatb(buffer, "\n_section_%d:\n", i); | 
		
	
		
			
				|  |  |  |  |         } | 
		
	
		
			
				|  |  |  |  |         for (uint32_t j = 0; j < ir->instruction_count; j++) { | 
		
	
		
			
				|  |  |  |  |             JanetSysInstruction instruction = ir->instructions[j]; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -225,34 +338,34 @@ void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetBuffer *buffer) | 
		
	
		
			
				|  |  |  |  |                 case JANET_SYSOP_SUBTRACT: | 
		
	
		
			
				|  |  |  |  |                 case JANET_SYSOP_MULTIPLY: | 
		
	
		
			
				|  |  |  |  |                 case JANET_SYSOP_DIVIDE: | 
		
	
		
			
				|  |  |  |  |                     do_spills(buffer, spills, j); | 
		
	
		
			
				|  |  |  |  |                     temps = do_spills_read(buffer, spills, j); | 
		
	
		
			
				|  |  |  |  |                     janet_formatb(buffer, "r%u = %s r%u, r%u\n", | 
		
	
		
			
				|  |  |  |  |                             v2reg(assignments, instruction.three.dest), | 
		
	
		
			
				|  |  |  |  |                             temps.temps[0], | 
		
	
		
			
				|  |  |  |  |                             janet_sysop_names[instruction.opcode], | 
		
	
		
			
				|  |  |  |  |                             v2reg(assignments, instruction.three.lhs), | 
		
	
		
			
				|  |  |  |  |                             v2reg(assignments, instruction.three.rhs)); | 
		
	
		
			
				|  |  |  |  |                             temps.temps[1], | 
		
	
		
			
				|  |  |  |  |                             temps.temps[2]); | 
		
	
		
			
				|  |  |  |  |                     do_spills_write(buffer, spills, j); | 
		
	
		
			
				|  |  |  |  |                     break; | 
		
	
		
			
				|  |  |  |  |                 case JANET_SYSOP_MOVE: | 
		
	
		
			
				|  |  |  |  |                     do_spills(buffer, spills, j); | 
		
	
		
			
				|  |  |  |  |                     janet_formatb(buffer, "r%u = r%u\n", | 
		
	
		
			
				|  |  |  |  |                             v2reg(assignments, instruction.two.dest), | 
		
	
		
			
				|  |  |  |  |                             v2reg(assignments, instruction.two.src)); | 
		
	
		
			
				|  |  |  |  |                     temps = do_spills_read(buffer, spills, j); | 
		
	
		
			
				|  |  |  |  |                     //janet_formatb(buffer, "r%u = r%u\n", temps.temps[0], temps.temps[1]); | 
		
	
		
			
				|  |  |  |  |                     janet_formatb(buffer, "mov %s, %s\n", | 
		
	
		
			
				|  |  |  |  |                             register_names[temps.temps[0]], | 
		
	
		
			
				|  |  |  |  |                             register_names[temps.temps[1]]); | 
		
	
		
			
				|  |  |  |  |                     do_spills_write(buffer, spills, j); | 
		
	
		
			
				|  |  |  |  |                     break; | 
		
	
		
			
				|  |  |  |  |                 case JANET_SYSOP_RETURN: | 
		
	
		
			
				|  |  |  |  |                     do_spills(buffer, spills, j); | 
		
	
		
			
				|  |  |  |  |                     janet_formatb(buffer, "return r%u\n", | 
		
	
		
			
				|  |  |  |  |                             v2reg(assignments, instruction.one.src)); | 
		
	
		
			
				|  |  |  |  |                     temps = do_spills_read(buffer, spills, j); | 
		
	
		
			
				|  |  |  |  |                     //janet_formatb(buffer, "return r%u\n", temps.temps[0]); | 
		
	
		
			
				|  |  |  |  |                     janet_formatb(buffer, "leave\n mov %s, rax\nret\n", register_names[temps.temps[0]]); | 
		
	
		
			
				|  |  |  |  |                     break; | 
		
	
		
			
				|  |  |  |  |                 case JANET_SYSOP_CONSTANT: | 
		
	
		
			
				|  |  |  |  |                     do_spills(buffer, spills, j); | 
		
	
		
			
				|  |  |  |  |                     janet_formatb(buffer, "r%u = constant $%v\n", | 
		
	
		
			
				|  |  |  |  |                             v2reg(assignments, instruction.constant.dest), | 
		
	
		
			
				|  |  |  |  |                             ir->constants[instruction.constant.constant]); | 
		
	
		
			
				|  |  |  |  |                     temps = do_spills_read(buffer, spills, j); | 
		
	
		
			
				|  |  |  |  |                     janet_formatb(buffer, "r%u = constant $%v\n", temps.temps[0], ir->constants[instruction.constant.constant]); | 
		
	
		
			
				|  |  |  |  |                     do_spills_write(buffer, spills, j); | 
		
	
		
			
				|  |  |  |  |                     break; | 
		
	
		
			
				|  |  |  |  |                 case JANET_SYSOP_LABEL: | 
		
	
		
			
				|  |  |  |  |                     do_spills(buffer, spills, j); | 
		
	
		
			
				|  |  |  |  |                     janet_formatb(buffer, "label_%u:\n", | 
		
	
		
			
				|  |  |  |  |                             v2reg(assignments, instruction.label.id)); | 
		
	
		
			
				|  |  |  |  |                     janet_formatb(buffer, "label_%u:\n", instruction.label.id); | 
		
	
		
			
				|  |  |  |  |                     break; | 
		
	
		
			
				|  |  |  |  |                 case JANET_SYSOP_EQ: | 
		
	
		
			
				|  |  |  |  |                 case JANET_SYSOP_NEQ: | 
		
	
	
		
			
				
					
					|  |  |  | @@ -260,19 +373,74 @@ void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetBuffer *buffer) | 
		
	
		
			
				|  |  |  |  |                 case JANET_SYSOP_LTE: | 
		
	
		
			
				|  |  |  |  |                 case JANET_SYSOP_GT: | 
		
	
		
			
				|  |  |  |  |                 case JANET_SYSOP_GTE: | 
		
	
		
			
				|  |  |  |  |                     do_spills(buffer, spills, j); | 
		
	
		
			
				|  |  |  |  |                     janet_formatb(buffer, "r%u = %s r%u, r%u\n", | 
		
	
		
			
				|  |  |  |  |                             v2reg(assignments, instruction.three.dest), | 
		
	
		
			
				|  |  |  |  |                             janet_sysop_names[instruction.opcode], | 
		
	
		
			
				|  |  |  |  |                             v2reg(assignments, instruction.three.lhs), | 
		
	
		
			
				|  |  |  |  |                             v2reg(assignments, instruction.three.rhs)); | 
		
	
		
			
				|  |  |  |  |                     temps = do_spills_read(buffer, spills, j); | 
		
	
		
			
				|  |  |  |  |                     JanetSysInstruction nexti = ir->instructions[j + 1]; | 
		
	
		
			
				|  |  |  |  |                     /* Combine compare and branch into one instruction */ | 
		
	
		
			
				|  |  |  |  |                     /* TODO - handle when lhs or rhs is 0 */ | 
		
	
		
			
				|  |  |  |  |                     /* TODO - handle floats */ | 
		
	
		
			
				|  |  |  |  |                     janet_formatb(buffer, "cmp %s, %s\n", register_names[temps.temps[1]], register_names[temps.temps[2]]); | 
		
	
		
			
				|  |  |  |  |                     if ((nexti.opcode == JANET_SYSOP_BRANCH || | 
		
	
		
			
				|  |  |  |  |                             nexti.opcode == JANET_SYSOP_BRANCH_NOT) | 
		
	
		
			
				|  |  |  |  |                             && nexti.branch.cond == instruction.three.dest) { | 
		
	
		
			
				|  |  |  |  |                         skip_branch = 1; | 
		
	
		
			
				|  |  |  |  |                         int invert = nexti.opcode == JANET_SYSOP_BRANCH_NOT; | 
		
	
		
			
				|  |  |  |  |                         if (instruction.opcode == JANET_SYSOP_EQ) { | 
		
	
		
			
				|  |  |  |  |                             janet_formatb(buffer, "%s label_%u\n", invert ? "jne" : "je", nexti.branch.to); | 
		
	
		
			
				|  |  |  |  |                         } else if (instruction.opcode == JANET_SYSOP_NEQ) { | 
		
	
		
			
				|  |  |  |  |                             janet_formatb(buffer, "%s label_%u\n", invert ? "je" : "jne", nexti.branch.to); | 
		
	
		
			
				|  |  |  |  |                         } else if (instruction.opcode == JANET_SYSOP_GT) { | 
		
	
		
			
				|  |  |  |  |                             janet_formatb(buffer, "%s label_%u\n", invert ? "jle" : "jg", nexti.branch.to); | 
		
	
		
			
				|  |  |  |  |                         } else if (instruction.opcode == JANET_SYSOP_GTE) { | 
		
	
		
			
				|  |  |  |  |                             janet_formatb(buffer, "%s label_%u\n", invert ? "jl" : "jge", nexti.branch.to); | 
		
	
		
			
				|  |  |  |  |                         } else if (instruction.opcode == JANET_SYSOP_LT) { | 
		
	
		
			
				|  |  |  |  |                             janet_formatb(buffer, "%s label_%u\n", invert ? "jge" : "jl", nexti.branch.to); | 
		
	
		
			
				|  |  |  |  |                         } else if (instruction.opcode == JANET_SYSOP_LTE) { | 
		
	
		
			
				|  |  |  |  |                             janet_formatb(buffer, "%s label_%u\n", invert ? "jg" : "jle", nexti.branch.to); | 
		
	
		
			
				|  |  |  |  |                         } else { | 
		
	
		
			
				|  |  |  |  |                             janet_panic("unreachable"); | 
		
	
		
			
				|  |  |  |  |                         } | 
		
	
		
			
				|  |  |  |  |                         do_spills_write(buffer, spills, j); | 
		
	
		
			
				|  |  |  |  |                         break; | 
		
	
		
			
				|  |  |  |  |                     } | 
		
	
		
			
				|  |  |  |  |                     /* Fallback to set* instructions */ | 
		
	
		
			
				|  |  |  |  |                     if (instruction.opcode == JANET_SYSOP_EQ) { | 
		
	
		
			
				|  |  |  |  |                         janet_formatb(buffer, "sete %s\n", register_names[temps.temps[0]]); | 
		
	
		
			
				|  |  |  |  |                     } else if (instruction.opcode == JANET_SYSOP_NEQ) { | 
		
	
		
			
				|  |  |  |  |                         janet_formatb(buffer, "setne %s\n", register_names[temps.temps[0]]); | 
		
	
		
			
				|  |  |  |  |                     } else if (instruction.opcode == JANET_SYSOP_GT) { | 
		
	
		
			
				|  |  |  |  |                         janet_formatb(buffer, "setg %s\n", register_names[temps.temps[0]]); | 
		
	
		
			
				|  |  |  |  |                     } else if (instruction.opcode == JANET_SYSOP_GTE) { | 
		
	
		
			
				|  |  |  |  |                         janet_formatb(buffer, "setge %s\n", register_names[temps.temps[0]]); | 
		
	
		
			
				|  |  |  |  |                     } else if (instruction.opcode == JANET_SYSOP_LT) { | 
		
	
		
			
				|  |  |  |  |                         janet_formatb(buffer, "setl %s\n", register_names[temps.temps[0]]); | 
		
	
		
			
				|  |  |  |  |                     } else if (instruction.opcode == JANET_SYSOP_LTE) { | 
		
	
		
			
				|  |  |  |  |                         janet_formatb(buffer, "setle %s\n", register_names[temps.temps[0]]); | 
		
	
		
			
				|  |  |  |  |                     } else { | 
		
	
		
			
				|  |  |  |  |                         janet_panic("unreachable"); | 
		
	
		
			
				|  |  |  |  |                     } | 
		
	
		
			
				|  |  |  |  |                     do_spills_write(buffer, spills, j); | 
		
	
		
			
				|  |  |  |  |                     break; | 
		
	
		
			
				|  |  |  |  |                 case JANET_SYSOP_BRANCH: | 
		
	
		
			
				|  |  |  |  |                 case JANET_SYSOP_BRANCH_NOT: | 
		
	
		
			
				|  |  |  |  |                     do_spills(buffer, spills, j); | 
		
	
		
			
				|  |  |  |  |                     janet_formatb(buffer, "branch label_%u if r%u\n", | 
		
	
		
			
				|  |  |  |  |                             instruction.branch.to, | 
		
	
		
			
				|  |  |  |  |                             v2reg(assignments, instruction.branch.cond)); | 
		
	
		
			
				|  |  |  |  |                     ; | 
		
	
		
			
				|  |  |  |  |                     if (skip_branch) { | 
		
	
		
			
				|  |  |  |  |                         skip_branch = 0; | 
		
	
		
			
				|  |  |  |  |                         break; | 
		
	
		
			
				|  |  |  |  |                     } | 
		
	
		
			
				|  |  |  |  |                     temps = do_spills_read(buffer, spills, j); | 
		
	
		
			
				|  |  |  |  |                     if (instruction.opcode == JANET_SYSOP_BRANCH) { | 
		
	
		
			
				|  |  |  |  |                         janet_formatb(buffer, "jnz %s label_%u\n", | 
		
	
		
			
				|  |  |  |  |                                 register_names[temps.temps[0]], | 
		
	
		
			
				|  |  |  |  |                                 instruction.branch.to); | 
		
	
		
			
				|  |  |  |  |                     } else { | 
		
	
		
			
				|  |  |  |  |                         janet_formatb(buffer, "jz %s label_%u\n", | 
		
	
		
			
				|  |  |  |  |                                 register_names[temps.temps[0]], | 
		
	
		
			
				|  |  |  |  |                                 instruction.branch.to); | 
		
	
		
			
				|  |  |  |  |                     } | 
		
	
		
			
				|  |  |  |  |                     break; | 
		
	
		
			
				|  |  |  |  |                 case JANET_SYSOP_JUMP: | 
		
	
		
			
				|  |  |  |  |                     janet_formatb(buffer, "jmp label_%u\n", | 
		
	
		
			
				|  |  |  |  |                             instruction.jump.to); | 
		
	
		
			
				|  |  |  |  |                     break; | 
		
	
		
			
				|  |  |  |  |                 case JANET_SYSOP_CALLK: | 
		
	
		
			
				|  |  |  |  |                 case JANET_SYSOP_CALL: | 
		
	
	
		
			
				
					
					|  |  |  | @@ -284,15 +452,15 @@ void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetBuffer *buffer) | 
		
	
		
			
				|  |  |  |  |                         while (offset * 3 + sub_count >= (int32_t) instruction.call.arg_count) { | 
		
	
		
			
				|  |  |  |  |                             sub_count--; | 
		
	
		
			
				|  |  |  |  |                         } | 
		
	
		
			
				|  |  |  |  |                         JanetSysInstruction arg_instruction = ir->instructions[j + offset]; | 
		
	
		
			
				|  |  |  |  |                         do_spills(buffer, spills, j + offset); | 
		
	
		
			
				|  |  |  |  |                         temps = do_spills_read(buffer, spills, j + offset); | 
		
	
		
			
				|  |  |  |  |                         for (int x = sub_count; x >= 0; x--) { | 
		
	
		
			
				|  |  |  |  |                             janet_formatb(buffer, "push r%u\n", v2reg(assignments, arg_instruction.arg.args[x])); | 
		
	
		
			
				|  |  |  |  |                             janet_formatb(buffer, "push r%u\n", temps.temps[x]); | 
		
	
		
			
				|  |  |  |  |                         } | 
		
	
		
			
				|  |  |  |  |                     } | 
		
	
		
			
				|  |  |  |  |                     temps = do_spills_read(buffer, spills, j); | 
		
	
		
			
				|  |  |  |  |                     if (instruction.opcode == JANET_SYSOP_CALLK) { | 
		
	
		
			
				|  |  |  |  |                         if (instruction.callk.has_dest) { | 
		
	
		
			
				|  |  |  |  |                             janet_formatb(buffer, "r%u = call %p\n", v2reg(assignments, instruction.callk.dest), | 
		
	
		
			
				|  |  |  |  |                             janet_formatb(buffer, "r%u = call %p\n", temps.temps[0], | 
		
	
		
			
				|  |  |  |  |                                     ir->constants[instruction.callk.constant]); | 
		
	
		
			
				|  |  |  |  |                         } else { | 
		
	
		
			
				|  |  |  |  |                             janet_formatb(buffer, "call %p\n", | 
		
	
	
		
			
				
					
					|  |  |  | @@ -300,13 +468,12 @@ void janet_sys_ir_lower_to_x64(JanetSysIRLinkage *linkage, JanetBuffer *buffer) | 
		
	
		
			
				|  |  |  |  |                         } | 
		
	
		
			
				|  |  |  |  |                     } else { | 
		
	
		
			
				|  |  |  |  |                         if (instruction.call.has_dest) { | 
		
	
		
			
				|  |  |  |  |                             janet_formatb(buffer, "r%u = call r%u\n", v2reg(assignments, instruction.call.dest), | 
		
	
		
			
				|  |  |  |  |                                     v2reg(assignments, instruction.call.callee)); | 
		
	
		
			
				|  |  |  |  |                             janet_formatb(buffer, "r%u = call r%u\n", temps.temps[0], temps.temps[1]); | 
		
	
		
			
				|  |  |  |  |                         } else { | 
		
	
		
			
				|  |  |  |  |                             janet_formatb(buffer, "call r%u\n", | 
		
	
		
			
				|  |  |  |  |                                     v2reg(assignments, instruction.call.callee)); | 
		
	
		
			
				|  |  |  |  |                             janet_formatb(buffer, "call r%u\n", temps.temps[0]); | 
		
	
		
			
				|  |  |  |  |                         } | 
		
	
		
			
				|  |  |  |  |                     } | 
		
	
		
			
				|  |  |  |  |                     do_spills_write(buffer, spills, j); | 
		
	
		
			
				|  |  |  |  |                     break; | 
		
	
		
			
				|  |  |  |  |                 // On a comparison, if next instruction is branch that reads from dest, combine into a single op. | 
		
	
		
			
				|  |  |  |  |             } | 
		
	
	
		
			
				
					
					|  |  |  |   |