qbe.ha (7815B)
1 // SPDX-License-Identifier: GPL-3.0-only 2 // (c) Hare authors <https://harelang.org> 3 4 use fmt; 5 use hare::types; 6 use hare::types::{builtin}; 7 use io; 8 9 type global = str; 10 type temporary = str; 11 type label = str; 12 type qvoid = void; 13 type constant = (u32 | u64 | f32 | f64 | str | qvoid); 14 type qval = (global | temporary | label | constant); 15 type qtypeval = (const *qtype, qval); 16 17 type value = struct { 18 value: qval, 19 _type: const *types::_type, 20 }; 21 22 const vvoid: value = value { 23 value = qvoid, 24 _type = &types::builtin_void, 25 }; 26 27 fn emit( 28 to: io::handle, 29 out: (qtypeval | void), 30 instr: qinstr, 31 args: (value | qval | qtype)... 32 ) void = { 33 fmt::fprintf(to, "\t")!; 34 match (out) { 35 case let val: qtypeval => 36 const ty = val.0, val = val.1; 37 qval_emit(to, val); 38 fmt::fprintf(to, " ={} ", qtype_repr(ty))!; 39 case void => void; 40 }; 41 // TODO: The langauge should provide a means of converting enums to 42 // strings without this 43 fmt::fprint(to, switch (instr) { 44 case qinstr::ADD => 45 yield "add"; 46 case qinstr::ALLOC16 => 47 yield "alloc16"; 48 case qinstr::ALLOC4 => 49 yield "alloc4"; 50 case qinstr::ALLOC8 => 51 yield "alloc8"; 52 case qinstr::AND => 53 yield "and"; 54 case qinstr::CALL => 55 yield "call"; 56 case qinstr::CAST => 57 yield "cast"; 58 case qinstr::CEQD => 59 yield "ceqd"; 60 case qinstr::CEQL => 61 yield "ceql"; 62 case qinstr::CEQS => 63 yield "ceqs"; 64 case qinstr::CEQW => 65 yield "ceqw"; 66 case qinstr::CGED => 67 yield "cged"; 68 case qinstr::CGES => 69 yield "cges"; 70 case qinstr::CGTD => 71 yield "cgtd"; 72 case qinstr::CGTS => 73 yield "cgts"; 74 case qinstr::CLED => 75 yield "cled"; 76 case qinstr::CLES => 77 yield "cles"; 78 case qinstr::CLTD => 79 yield "cltd"; 80 case qinstr::CLTS => 81 yield "clts"; 82 case qinstr::CNED => 83 yield "cned"; 84 case qinstr::CNEL => 85 yield "cnel"; 86 case qinstr::CNES => 87 yield "cnes"; 88 case qinstr::CNEW => 89 yield "cnew"; 90 case qinstr::COD => 91 yield "cod"; 92 case qinstr::COPY => 93 yield "copy"; 94 case qinstr::COS => 95 yield "cos"; 96 case qinstr::CSGEL => 97 yield "csgel"; 98 case qinstr::CSGEW => 99 yield "csgew"; 100 case qinstr::CSGTL => 101 yield "csgtl"; 102 case qinstr::CSGTW => 103 yield "csgtw"; 104 case qinstr::CSLEL => 105 yield "cslel"; 106 case qinstr::CSLEW => 107 yield "cslew"; 108 case qinstr::CSLTL => 109 yield "csltl"; 110 case qinstr::CSLTW => 111 yield "csltw"; 112 case qinstr::CUGEL => 113 yield "cugel"; 114 case qinstr::CUGEW => 115 yield "cugew"; 116 case qinstr::CUGTL => 117 yield "cugtl"; 118 case qinstr::CUGTW => 119 yield "cugtw"; 120 case qinstr::CULEL => 121 yield "culel"; 122 case qinstr::CULEW => 123 yield "culew"; 124 case qinstr::CULTL => 125 yield "cultl"; 126 case qinstr::CULTW => 127 yield "cultw"; 128 case qinstr::CUOD => 129 yield "cuod"; 130 case qinstr::CUOS => 131 yield "cuos"; 132 case qinstr::DIV => 133 yield "div"; 134 case qinstr::DTOSI => 135 yield "dtosi"; 136 case qinstr::EXTS => 137 yield "exts"; 138 case qinstr::EXTSB => 139 yield "extsb"; 140 case qinstr::EXTSH => 141 yield "extsh"; 142 case qinstr::EXTSW => 143 yield "extsw"; 144 case qinstr::EXTUB => 145 yield "extub"; 146 case qinstr::EXTUH => 147 yield "extuh"; 148 case qinstr::EXTUW => 149 yield "extuw"; 150 case qinstr::JMP => 151 yield "jmp"; 152 case qinstr::JNZ => 153 yield "jnz"; 154 case qinstr::LOADD => 155 yield "loadd"; 156 case qinstr::LOADL => 157 yield "loadl"; 158 case qinstr::LOADS => 159 yield "loads"; 160 case qinstr::LOADSB => 161 yield "loadsb"; 162 case qinstr::LOADSH => 163 yield "loadsh"; 164 case qinstr::LOADSW => 165 yield "loadsw"; 166 case qinstr::LOADUB => 167 yield "loadub"; 168 case qinstr::LOADUH => 169 yield "loaduh"; 170 case qinstr::LOADUW => 171 yield "loaduw"; 172 case qinstr::MUL => 173 yield "mul"; 174 case qinstr::OR => 175 yield "or"; 176 case qinstr::REM => 177 yield "rem"; 178 case qinstr::RET => 179 yield "ret"; 180 case qinstr::SAR => 181 yield "sar"; 182 case qinstr::SHL => 183 yield "shl"; 184 case qinstr::SHR => 185 yield "shr"; 186 case qinstr::SLTOF => 187 yield "sltof"; 188 case qinstr::STOREB => 189 yield "storeb"; 190 case qinstr::STORED => 191 yield "stored"; 192 case qinstr::STOREH => 193 yield "storeh"; 194 case qinstr::STOREL => 195 yield "storel"; 196 case qinstr::STORES => 197 yield "stores"; 198 case qinstr::STOREW => 199 yield "storew"; 200 case qinstr::STOSI => 201 yield "stosi"; 202 case qinstr::SUB => 203 yield "sub"; 204 case qinstr::SWTOF => 205 yield "swtof"; 206 case qinstr::TRUNCD => 207 yield "truncd"; 208 case qinstr::UDIV => 209 yield "udiv"; 210 case qinstr::UREM => 211 yield "urem"; 212 case qinstr::XOR => 213 yield "xor"; 214 })!; 215 for (let i = 0z; i < len(args); i += 1) { 216 const arg = match (args[i]) { 217 case let v: value => 218 yield v.value; 219 case => 220 yield args[i]; 221 }; 222 match (arg) { 223 case let v: value => abort(); // Invariant 224 case let qv: qval => 225 yield qval_emit(to, qv); 226 case let qt: qtype => 227 abort(); // TODO 228 }; 229 if (i + 1 < len(args)) { 230 fmt::fprint(to, ",")!; 231 }; 232 }; 233 fmt::fprintln(to)!; 234 }; 235 236 fn qval_emit(to: io::handle, qv: qval) void = { 237 match (qv) { 238 case let g: global => 239 fmt::fprintf(to, " ${}", g)!; 240 case let t: temporary => 241 fmt::fprintf(to, " %{}", t)!; 242 case let l: label => 243 fmt::fprintf(to, " @{}", l)!; 244 case let c: constant => 245 match (c) { 246 case qvoid => abort(); 247 case let v: (u32 | u64 | f32 | f64 | str) => 248 fmt::fprintf(to, " {}", v)!; 249 }; 250 }; 251 }; 252 253 fn qinstr_alloc(ty: *types::_type) qinstr = { 254 switch (ty._align) { 255 case 4 => 256 return qinstr::ALLOC4; 257 case 8 => 258 return qinstr::ALLOC8; 259 case 16 => 260 return qinstr::ALLOC16; 261 case => abort(); 262 }; 263 }; 264 265 fn qinstr_store( 266 ctx: *context, 267 ty: *types::_type, 268 ) qinstr = { 269 match (ty.repr) { 270 case let al: types::alias => 271 return qinstr_store(ctx, al.secondary: *types::_type); 272 case let bi: types::builtin => 273 switch (bi) { 274 case builtin::STR, builtin::VOID => abort(); 275 case builtin::F32 => 276 return qinstr::STORES; 277 case builtin::F64 => 278 return qinstr::STORED; 279 case => 280 switch (ty.sz) { 281 case 1 => 282 return qinstr::STOREB; 283 case 2 => 284 return qinstr::STOREH; 285 case 4 => 286 return qinstr::STOREW; 287 case 8 => 288 return qinstr::STOREL; 289 case => abort(); 290 }; 291 }; 292 case types::pointer => 293 if (ctx.arch.ptr == &qlong) { 294 return qinstr::STOREL; 295 } else if (ctx.arch.ptr == &qword) { 296 return qinstr::STOREW; 297 } else abort(); 298 case let en: types::_enum => abort(); // TODO 299 case => abort(); 300 }; 301 }; 302 303 fn qinstr_load( 304 ctx: *context, 305 ty: *types::_type, 306 ) qinstr = { 307 match (ty.repr) { 308 case let al: types::alias => 309 return qinstr_load(ctx, al.secondary: *types::_type); 310 case let bi: types::builtin => 311 switch (bi) { 312 case builtin::STR, builtin::VOID => abort(); 313 case builtin::F32 => 314 return qinstr::LOADS; 315 case builtin::F64 => 316 return qinstr::LOADD; 317 case => 318 switch (ty.sz) { 319 case 1 => 320 if (types::is_signed(ty)) { 321 return qinstr::LOADSB; 322 } else { 323 return qinstr::LOADUB; 324 }; 325 case 2 => 326 if (types::is_signed(ty)) { 327 return qinstr::LOADSH; 328 } else { 329 return qinstr::LOADUH; 330 }; 331 case 4 => 332 if (types::is_signed(ty)) { 333 return qinstr::LOADSW; 334 } else { 335 return qinstr::LOADUW; 336 }; 337 case 8 => 338 return qinstr::LOADL; 339 case => abort(); 340 }; 341 }; 342 case types::pointer => 343 if (ctx.arch.ptr == &qlong) { 344 return qinstr::LOADL; 345 } else if (ctx.arch.ptr == &qword) { 346 return qinstr::LOADUW; 347 } else abort(); 348 case let en: types::_enum => abort(); // TODO 349 case => abort(); 350 }; 351 }; 352 353 type qinstr = enum { 354 ADD, 355 ALLOC16, 356 ALLOC4, 357 ALLOC8, 358 AND, 359 CALL, 360 CAST, 361 CEQD, 362 CEQL, 363 CEQS, 364 CEQW, 365 CGED, 366 CGES, 367 CGTD, 368 CGTS, 369 CLED, 370 CLES, 371 CLTD, 372 CLTS, 373 CNED, 374 CNEL, 375 CNES, 376 CNEW, 377 COD, 378 COPY, 379 COS, 380 CSGEL, 381 CSGEW, 382 CSGTL, 383 CSGTW, 384 CSLEL, 385 CSLEW, 386 CSLTL, 387 CSLTW, 388 CUGEL, 389 CUGEW, 390 CUGTL, 391 CUGTW, 392 CULEL, 393 CULEW, 394 CULTL, 395 CULTW, 396 CUOD, 397 CUOS, 398 DIV, 399 DTOSI, 400 EXTS, 401 EXTSB, 402 EXTSH, 403 EXTSW, 404 EXTUB, 405 EXTUH, 406 EXTUW, 407 JMP, 408 JNZ, 409 LOADD, 410 LOADL, 411 LOADS, 412 LOADSB, 413 LOADSH, 414 LOADSW, 415 LOADUB, 416 LOADUH, 417 LOADUW, 418 MUL, 419 OR, 420 REM, 421 RET, 422 SAR, 423 SHL, 424 SHR, 425 SLTOF, 426 STOREB, 427 STORED, 428 STOREH, 429 STOREL, 430 STORES, 431 STOREW, 432 STOSI, 433 SUB, 434 SWTOF, 435 TRUNCD, 436 UDIV, 437 UREM, 438 XOR, 439 };