gen.ha (6558B)
1 // License: GPL-3.0 2 // (c) 2022 Alexey Yerin <yyp@disroot.org> 3 // (c) 2021 Drew DeVault <sir@cmpwn.com> 4 // (c) 2021 Ember Sawady <ecs@d2evs.net> 5 use fmt; 6 use hare::ast; 7 use hare::lex; 8 use hare::module; 9 use hare::types; 10 use hare::types::{builtin}; 11 use hare::unit; 12 use hare::unit::{object_kind}; 13 use io; 14 use memio; 15 use os; 16 use strings; 17 18 fn gen(out: io::handle, store: *types::typestore, unit: *unit::unit) void = { 19 // TODO: context_init 20 let ctx = context { 21 out = out, 22 buf = memio::dynamic(), 23 store = store, 24 unit = unit, 25 arch = struct { 26 // TODO: Initialize these properly 27 ptr: *qtype = &qlong, 28 sz: *qtype = &qlong, 29 }, 30 ... 31 }; 32 defer io::close(&ctx.buf)!; 33 for (let i = 0z; i < len(unit.decls); i += 1) { 34 match (unit.decls[i].decl) { 35 case let func: unit::decl_func => 36 gen_func(&ctx, &unit.decls[i]); 37 case => abort(); // TODO 38 }; 39 }; 40 }; 41 42 fn gen_func(ctx: *context, decl: *unit::decl) void = { 43 // TODO: const fndecl = &decl.decl as *unit::decl_func; 44 const fndecl = decl.decl as unit::decl_func; 45 const body = match (fndecl.body) { 46 case let expr: *unit::expr => 47 yield expr; 48 case null => 49 return; // Prototype 50 }; 51 const fntype = fndecl.prototype.repr as types::func; 52 assert(fntype.flags == 0); 53 ctx.serial = 0; 54 55 const ident = module::identuscore(fndecl.ident); 56 defer free(ident); 57 fmt::fprintf(ctx.out, "{}section \".text.{}\" \"ax\" function", 58 if (decl.exported) "export " else "", ident)!; 59 const rtype = fntype.result; 60 const has_rval = 61 match (types::dealias(rtype).repr) { 62 case let bi: types::builtin => 63 yield bi != types::builtin::VOID; 64 case => 65 yield true; 66 }; 67 if (has_rval) { 68 const qrtype = qtype_lookup(ctx, rtype, false); 69 fmt::fprintf(ctx.out, " {}", qtype_repr(qrtype))!; 70 }; 71 fmt::fprintf(ctx.out, " ${}(", ident)!; 72 assert(len(fntype.params) == 0); // TODO 73 fmt::fprintln(ctx.out, ") {")!; 74 fmt::fprintln(ctx.out, mklabel(ctx, "start"))!; 75 76 // We use a dynamic buffer here so that we can emit alloc instructions 77 // on-demand at the start of the function, rather than spread out 78 // through the body. This is more reliable on qbe's ARM backend, and 79 // generates better IL besides. 80 memio::reset(&ctx.buf); 81 82 fmt::fprintln(&ctx.buf, mklabel(ctx, "body"))!; 83 84 const rval = gen_expr(ctx, body); 85 if (!body.terminates) { 86 if (has_rval) { 87 emit(&ctx.buf, void, qinstr::RET, rval); 88 } else { 89 emit(&ctx.buf, void, qinstr::RET); 90 }; 91 }; 92 93 io::writeall(ctx.out, memio::buffer(&ctx.buf))!; 94 fmt::fprintln(ctx.out, "}\n")!; 95 }; 96 97 fn gen_store(ctx: *context, object: value, value: value) void = { 98 match (types::dealias(object._type).repr) { 99 case let bi: types::builtin => 100 switch (bi) { 101 case builtin::STR => abort(); // TODO 102 case => void; 103 }; 104 case types::_struct => abort(); // TODO 105 case (types::array | types::slice | types::tagged | types::tuple) => 106 abort(); // TODO 107 case => void; // Handled below 108 }; 109 const instr = qinstr_store(ctx, object._type); 110 emit(&ctx.buf, void, instr, value, object); 111 }; 112 113 fn gen_load(ctx: *context, object: value) value = { 114 match (types::dealias(object._type).repr) { 115 case let bi: types::builtin => 116 switch (bi) { 117 case builtin::STR => abort(); // TODO 118 case => void; 119 }; 120 case types::_struct => abort(); // TODO 121 case (types::array | types::slice | types::tagged | types::tuple) => 122 abort(); // TODO 123 case => void; // Handled below 124 }; 125 const instr = qinstr_load(ctx, object._type); 126 const temp = mktemp(ctx); 127 const ty = qtype_lookup(ctx, object._type, false); 128 emit(&ctx.buf, (ty, temp), instr, object); 129 return value { 130 value = temp, 131 _type = object._type, 132 }; 133 }; 134 135 fn gen_expr(ctx: *context, expr: *unit::expr) value = { 136 match (expr.expr) { 137 case unit::access => 138 return gen_access(ctx, expr); 139 case unit::bindings => 140 return gen_binding(ctx, expr); 141 case unit::compound => 142 return gen_compound(ctx, expr); 143 case unit::constant => 144 return gen_const(ctx, expr); 145 case unit::_return => 146 return gen_return(ctx, expr); 147 }; 148 }; 149 150 fn gen_expr_at(ctx: *context, expr: *unit::expr, at: value) void = { 151 match (expr.expr) { 152 case => void; // TODO: Some functions will prefer _at 153 }; 154 const value = gen_expr(ctx, expr); 155 gen_store(ctx, at, value); 156 }; 157 158 fn gen_access_object(ctx: *context, object: *unit::object) value = { 159 switch (object.kind) { 160 case object_kind::CONST, object_kind::TYPE => abort(); 161 case object_kind::BIND => 162 const binding = binding_lookup(ctx, object); 163 return value { 164 value = binding.name, 165 _type = object._type, 166 }; 167 case object_kind::DECL => abort(); // TODO 168 }; 169 }; 170 171 fn gen_access_addr(ctx: *context, expr: *unit::expr) value = { 172 match (expr.expr as unit::access) { 173 case let ao: unit::access_object => 174 return gen_access_object(ctx, ao); 175 case let ai: unit::access_index => abort(); // TODO 176 case let af: unit::access_field => abort(); // TODO 177 case let at: unit::access_tuple => abort(); // TODO 178 }; 179 }; 180 181 fn gen_access(ctx: *context, expr: *unit::expr) value = { 182 const addr = gen_access_addr(ctx, expr); 183 return gen_load(ctx, addr); 184 }; 185 186 fn gen_binding(ctx: *context, expr: *unit::expr) value = { 187 const bindings = expr.expr as unit::bindings; 188 for (let i = 0z; i < len(bindings); i += 1) { 189 const item = bindings[i]; 190 const temp = mktemp(ctx); 191 append(ctx.bindings, binding { 192 object = item.object, 193 name = temp, 194 }); 195 const value = value { 196 value = temp, 197 _type = item.object._type, 198 }; 199 const instr = qinstr_alloc(value._type); 200 const lval = mklval(ctx, value); 201 emit(&ctx.buf, lval, instr, value._type.sz); 202 gen_expr_at(ctx, item.init, value); 203 }; 204 return vvoid; 205 }; 206 207 fn gen_compound(ctx: *context, expr: *unit::expr) value = { 208 const compound = expr.expr as unit::compound; 209 for (let i = 0z; i < len(compound); i += 1) { 210 gen_expr(ctx, compound[i]); 211 }; 212 return vvoid; // TODO 213 }; 214 215 fn gen_const(ctx: *context, expr: *unit::expr) value = { 216 const constexpr = expr.expr as unit::constant; 217 const val: qval = match (constexpr) { 218 case void => 219 return vvoid; 220 case let b: bool => 221 yield (if (b) 1u32 else 0u32): constant; 222 case ast::_null => 223 yield 0u64; // XXX: Arch 224 case let r: rune => 225 yield r: u32; 226 case let v: (u64 | f64) => 227 yield v; 228 case let i: i64 => 229 yield i: u64; 230 case let s: str => abort(); // TODO 231 // TODO: Aggregate types 232 }; 233 return value { 234 value = val, 235 _type = expr.result, 236 }; 237 }; 238 239 fn gen_return(ctx: *context, expr: *unit::expr) value = { 240 const rexpr = expr.expr as unit::_return; 241 match (rexpr) { 242 case null => 243 emit(&ctx.buf, void, qinstr::RET); 244 case let expr: *unit::expr => 245 emit(&ctx.buf, void, qinstr::RET, gen_expr(ctx, expr)); 246 }; 247 return vvoid; 248 };