backend.c (4690B)
1 #include <stdbool.h> 2 3 #define DLIB_IMPLEMENTATION 4 #include "dlib.h" 5 6 typedef struct Ir_program Ir_program; 7 typedef bool (*Compile_fn)(Ir_program, string_builder *); 8 9 typedef struct { 10 const char *name; 11 Compile_fn compile; 12 } Backend; 13 14 enum Ir_type { 15 TYPE_VOID, 16 TYPE_I8, 17 TYPE_U8, 18 TYPE_I16, 19 TYPE_U16, 20 TYPE_I32, 21 TYPE_U32, 22 TYPE_I64, 23 TYPE_U64, 24 TYPE_PTR, 25 TYPE_F32, 26 TYPE_F64, 27 }; 28 29 enum Ir_kind { 30 IR_LOAD, 31 IR_STORE, 32 IR_ASSIGN, 33 IR_BINOP, 34 IR_CALL, 35 IR_RETURN, 36 IR_LABEL, 37 IR_JUMP, 38 IR_JUMP_IF_NOT, 39 }; 40 41 enum Ir_arg_kind { 42 ARG_NONE, 43 ARG_INT_LITERAL, 44 /*ARG_FLOAT_LITERAL,*/ 45 ARG_CSTRING_LITERAL, 46 ARG_TEMP_STORAGE, 47 ARG_ADDRESS, 48 }; 49 50 enum Ir_binop { 51 OP_ADD, 52 OP_SUB, 53 OP_MUL, 54 OP_DIV, 55 OP_LT, 56 OP_GT, 57 OP_EQ, 58 OP_LEQ, 59 OP_GEQ, 60 }; 61 62 typedef struct { 63 enum Ir_arg_kind type; 64 union { 65 int64_t i64; 66 /* double f64; */ 67 ssize_t temp_id; 68 void *addr; 69 char *cstr; 70 }; 71 } Ir_arg; 72 73 typedef struct { 74 Ir_arg *items; 75 size_t count; 76 size_t capacity; 77 } Ir_arg_list; 78 79 typedef struct { 80 enum Ir_kind type; 81 Ir_arg result; 82 union { 83 struct { 84 enum Ir_binop op; 85 Ir_arg left; 86 Ir_arg right; 87 } binop; 88 struct { 89 Ir_arg loc; 90 } load; 91 struct { 92 Ir_arg loc; 93 Ir_arg data; 94 } store; 95 Ir_arg assign; 96 string_view label; 97 struct { 98 Ir_arg cond; 99 string_view label; 100 } jump; 101 Ir_arg ret; 102 struct { 103 Ir_arg indirect; 104 string_view name; 105 Ir_arg_list args; 106 } call; 107 }; 108 } Ir; 109 110 typedef struct { 111 Ir *items; 112 size_t count; 113 size_t capacity; 114 } Ir_list; 115 116 typedef struct { 117 enum Ir_type *items; 118 size_t count; 119 size_t capacity; 120 } Ir_type_list; 121 122 typedef struct { 123 enum Ir_type type; 124 union { 125 int8_t i8; 126 uint8_t u8; 127 int16_t i16; 128 uint16_t u16; 129 int32_t i32; 130 uint32_t u32; 131 int64_t i64; 132 uint64_t u64; 133 /* double f64; 134 float f32; */ 135 string_view str; 136 char *cstr; 137 }; 138 } Ir_data; 139 140 typedef struct { 141 string_view name; 142 Ir_data default_value; 143 } Ir_static_data; 144 145 typedef struct { 146 Ir_static_data *items; 147 size_t count; 148 size_t capacity; 149 } Ir_static_data_list; 150 151 typedef struct { 152 string_view name; 153 enum Ir_type return_type; 154 Ir_type_list argument_types; 155 Ir_list body; 156 } Ir_function; 157 158 typedef struct { 159 Ir_function *items; 160 size_t count; 161 size_t capacity; 162 } Ir_function_list; 163 164 struct Ir_program { 165 Ir_function_list functions; 166 Ir_static_data_list data; 167 }; 168 169 bool ir_compile(Ir_program, string_builder *); 170 171 Backend ir_backend = { 172 "IR Dump", 173 ir_compile, 174 }; 175 176 int 177 main(int argc, char **argv) 178 { 179 (void) argc; 180 (void) argv; 181 string_builder sb = {0}; 182 Ir_list ir_list = {0}; 183 da_append(&ir_list, ((Ir) { .type = IR_LABEL, .label = {.data = "start", .count = 5}})); 184 da_append(&ir_list, ((Ir) { .type = IR_ASSIGN, .result = { .type = ARG_TEMP_STORAGE, .temp_id = 0}, .assign = {.type = ARG_INT_LITERAL, .i64 = 0}})); 185 da_append(&ir_list, ((Ir) { .type = IR_LABEL, .label = {.data = "loop", .count = 4}})); 186 da_append(&ir_list, ((Ir) { .type = IR_BINOP, .result = { .type = ARG_TEMP_STORAGE, .temp_id = 1}, .binop = {.op = OP_LT, .left = {.type = ARG_TEMP_STORAGE, .temp_id = 0}, .right = {.type = ARG_INT_LITERAL, .i64 = 10}}})); 187 da_append(&ir_list, ((Ir) { .type = IR_JUMP_IF_NOT, .jump = {.cond = {.type = ARG_TEMP_STORAGE, .temp_id = 1}, .label = {.data = "loop_end", .count = 8}}})); 188 da_append(&ir_list, ((Ir) { .type = IR_CALL, .result = {.type = ARG_TEMP_STORAGE, .temp_id = 2}, .call = { .name = {.data = "printf", .count = 6}, .args = {0}}})); 189 da_append(&ir_list.items[ir_list.count - 1].call.args, ((Ir_arg) {.type = ARG_CSTRING_LITERAL, .cstr = "%i\\n"})); 190 da_append(&ir_list.items[ir_list.count - 1].call.args, ((Ir_arg) {.type = ARG_TEMP_STORAGE, .temp_id = 0})); 191 da_append(&ir_list, ((Ir) { .type = IR_BINOP, .result = { .type = ARG_TEMP_STORAGE, .temp_id = 0}, .binop = {.op = OP_ADD, .left = {.type = ARG_TEMP_STORAGE, .temp_id = 0}, .right = {.type = ARG_INT_LITERAL, .i64 = 1}}})); 192 da_append(&ir_list, ((Ir) { .type = IR_JUMP, .jump = {.label = {.data = "loop", .count = 4}}})); 193 da_append(&ir_list, ((Ir) { .type = IR_LABEL, .label = {.data = "loop_end", .count = 8}})); 194 da_append(&ir_list, ((Ir) { .type = IR_RETURN, .ret = {.type = ARG_INT_LITERAL, .i64 = 69}})); 195 Ir_program prog = {0}; 196 da_append(&prog.functions, ((Ir_function) {.name = {.data = "main", .count = 4}, .return_type = TYPE_I32, .body = ir_list})); 197 da_append(&prog.functions.items[0].argument_types, TYPE_I32); 198 da_append(&prog.functions.items[0].argument_types, TYPE_PTR); 199 200 if (!ir_backend.compile(prog, &sb)) { 201 return 1; 202 } 203 sb_write(1, sb); 204 return 0; 205 } 206 207 #include "ir_backend.c"