hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

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 };