ir_backend.c (6030B)
1 typedef struct { 2 void *loc; 3 void *end; 4 } Temp_allocator; 5 6 Temp_allocator temp_allocator = {0}; 7 8 void * 9 temp_alloc(size_t size) 10 { 11 if (!temp_allocator.loc) { 12 size_t allocator_size = 1024*1024; 13 temp_allocator.loc = malloc(allocator_size); 14 temp_allocator.end = temp_allocator.loc + allocator_size; 15 temp_allocator.loc = (void *)((intptr_t)(temp_allocator.loc + 0xF) & ~0xFul); 16 } 17 void *result = temp_allocator.loc; 18 temp_allocator.loc += (size + 0xF) & ~0xFul; 19 if (temp_allocator.loc >= temp_allocator.end) { 20 fprintf(stderr, "Error: Temp allocator out of memory\n"); 21 exit(1); 22 } 23 return result; 24 } 25 26 const char * 27 ir_arg_to_cstr(Ir_arg arg) 28 { 29 int len; 30 char *str; 31 if (arg.type == ARG_INT_LITERAL) { 32 len = snprintf(NULL, 0, "%li", arg.i64) + 1; 33 str = temp_alloc(len); 34 snprintf(str, len, "%li", arg.i64); 35 } else if (arg.type == ARG_TEMP_STORAGE) { 36 len = snprintf(NULL, 0, "%%%li", arg.temp_id) + 1; 37 str = temp_alloc(len); 38 snprintf(str, len, "%%%li", arg.temp_id); 39 } else if (arg.type == ARG_ADDRESS) { 40 len = snprintf(NULL, 0, "0x%p", arg.addr) + 1; 41 str = temp_alloc(len); 42 snprintf(str, len, "0x%p", arg.addr); 43 } else if (arg.type == ARG_CSTRING_LITERAL) { 44 len = strlen(arg.cstr); 45 str = temp_alloc(len + 3); 46 memcpy(str + 1, arg.cstr, len); 47 str[0] = '"'; 48 str[len + 1] = '"'; 49 str[len + 2] = '\0'; 50 } else { 51 assert(0 && "Invalid arg"); 52 } 53 return str; 54 } 55 56 const char * 57 ir_binop_to_cstr(enum Ir_binop binop) 58 { 59 const char *str; 60 switch (binop) { 61 case OP_ADD: str = "+"; break; 62 case OP_SUB: str = "-"; break; 63 case OP_MUL: str = "*"; break; 64 case OP_DIV: str = "/"; break; 65 case OP_LT: str = "<"; break; 66 case OP_GT: str = ">"; break; 67 case OP_EQ: str = "=="; break; 68 case OP_LEQ: str = "<="; break; 69 case OP_GEQ: str = "=>"; break; 70 default: assert(0 && "Unknown binop"); 71 } 72 return str; 73 } 74 75 const char * 76 ir_type_to_cstr(enum Ir_type type) 77 { 78 const char *str; 79 switch (type) { 80 case TYPE_VOID: str = "void"; break; 81 case TYPE_I8: str = "i8"; break; 82 case TYPE_U8: str = "u8"; break; 83 case TYPE_I16: str = "i16"; break; 84 case TYPE_U16: str = "u16"; break; 85 case TYPE_I32: str = "i32"; break; 86 case TYPE_U32: str = "u32"; break; 87 case TYPE_I64: str = "i64"; break; 88 case TYPE_U64: str = "u64"; break; 89 case TYPE_PTR: str = "ptr"; break; 90 case TYPE_F32: str = "f32"; break; 91 case TYPE_F64: str = "f64"; break; 92 default: assert(0 && "Unknown type"); 93 } 94 return str; 95 } 96 97 bool 98 ir_compile_body(Ir_list irs, string_builder *sb) 99 { 100 size_t i, j; 101 Ir ir; 102 Temp_allocator saved_allocator; 103 for (i = 0; i < irs.count; i++) { 104 saved_allocator = temp_allocator; 105 ir = irs.items[i]; 106 assert(ir.result.type == ARG_TEMP_STORAGE || ir.result.type == ARG_NONE); 107 sb_append_cstr(sb, " "); 108 switch (ir.type) { 109 case IR_LOAD: 110 assert(ir.result.type != ARG_NONE); 111 sb_printf(sb, " %s = load(%s)", ir_arg_to_cstr(ir.result), ir_arg_to_cstr(ir.load.loc)); 112 break; 113 case IR_STORE: 114 assert(ir.result.type == ARG_NONE); 115 sb_printf(sb, " store(%s, %s)", ir_arg_to_cstr(ir.store.loc), ir_arg_to_cstr(ir.store.data)); 116 break; 117 case IR_ASSIGN: 118 assert(ir.result.type != ARG_NONE); 119 sb_printf(sb, " %s = %s", ir_arg_to_cstr(ir.result), ir_arg_to_cstr(ir.assign)); 120 break; 121 case IR_BINOP: 122 assert(ir.result.type != ARG_NONE); 123 sb_printf(sb, " %s = %s %s %s", ir_arg_to_cstr(ir.result), ir_arg_to_cstr(ir.binop.left), ir_binop_to_cstr(ir.binop.op), ir_arg_to_cstr(ir.binop.right)); 124 break; 125 case IR_CALL: 126 assert(ir.result.type != ARG_NONE); 127 if (ir.call.indirect.type != ARG_NONE) { 128 sb_printf(sb, " %s = call %s (", ir_arg_to_cstr(ir.result), ir_arg_to_cstr(ir.call.indirect)); 129 } else { 130 sb_printf(sb, " %s = call %.*s (", ir_arg_to_cstr(ir.result), ir.call.name.count, ir.call.name.data); 131 } 132 for (j = 0; j < ir.call.args.count; j++) { 133 if (j) { 134 sb_append_cstr(sb, ", "); 135 } 136 sb_append_cstr(sb, ir_arg_to_cstr(ir.call.args.items[j])); 137 } 138 sb_append_char(sb, ')'); 139 break; 140 case IR_RETURN: 141 assert(ir.result.type == ARG_NONE); 142 sb_printf(sb, " return %s", ir_arg_to_cstr(ir.ret)); 143 break; 144 case IR_LABEL: 145 assert(ir.result.type == ARG_NONE); 146 sb_printf(sb, "#%.*s:", ir.label.count, ir.label.data); 147 break; 148 case IR_JUMP: 149 assert(ir.result.type == ARG_NONE); 150 sb_printf(sb, " jump #%.*s", ir.jump.label.count, ir.jump.label.data); 151 break; 152 case IR_JUMP_IF_NOT: 153 assert(ir.result.type == ARG_NONE); 154 sb_printf(sb, " jump_if_not %s #%.*s", ir_arg_to_cstr(ir.jump.cond), ir.jump.label.count, ir.jump.label.data); 155 break; 156 default: 157 fprintf(stderr, "Error: Unknown IR %lu\n", i); 158 temp_allocator = saved_allocator; 159 return false; 160 } 161 sb_append_char(sb, '\n'); 162 temp_allocator = saved_allocator; 163 } 164 return true; 165 } 166 167 bool 168 ir_compile(Ir_program prog, string_builder *sb) 169 { 170 size_t i, j; 171 Ir_function function; 172 Temp_allocator saved_allocator; 173 for (i = 0; i < prog.functions.count; i++) { 174 saved_allocator = temp_allocator; 175 if (i) { 176 sb_append_char(sb, '\n'); 177 } 178 function = prog.functions.items[i]; 179 sb_printf(sb, "$%.*s(", function.name.count, function.name.data); 180 for (j = 0; j < function.argument_types.count; j++) { 181 if (j) { 182 sb_append_cstr(sb, ", "); 183 } 184 sb_append_cstr(sb, ir_type_to_cstr(function.argument_types.items[j])); 185 } 186 sb_printf(sb, ") -> %s {\n", ir_type_to_cstr(function.return_type)); 187 if (!ir_compile_body(function.body, sb)) { 188 temp_allocator = saved_allocator; 189 return false; 190 } 191 sb_append_cstr(sb, "}\n"); 192 temp_allocator = saved_allocator; 193 } 194 return true; 195 }