os

An operating system
git clone https://erai.gay/code/os/
Log | Files | Refs | README | LICENSE

riscv64.om (17588B)


      1 //x1 = link register
      2 //x2 = stack pointer
      3 //x3 = global pointer
      4 //x4 = thread pointer
      5 //x8 = frame pointer
      6 //x5-x7, x28-x31 = temporary
      7 //x8-x9, x18-x27 = callee-saved
      8 //x10-x17 = arguments
      9 
     10 // Use x31 to build far jumps and large constants
     11 
     12 //R = func7[31:25] rs2[24:20] rs1[19:15] func3[14:12] rd[11:7] op[6:0]
     13 func riscv64_emitr(c: *compiler, op: int, fn: int, rd: int, rs1: int, rs2: int) {
     14 	var x: int;
     15 	x = ((fn >> 3) << 25) + (rs2 << 20) + (rs1 << 15) + ((fn & 7) << 12) + (rd << 7) + op;
     16 	as_emit(c.s, x);
     17 	as_emit(c.s, x >> 8);
     18 	as_emit(c.s, x >> 16);
     19 	as_emit(c.s, x >> 24);
     20 }
     21 
     22 //I = imm12[31:20]            rs1[19:15] func3[14:12] rd[11:7] op[6:0]
     23 func riscv64_emiti(c: *compiler, op: int, fn: int, rd: int, rs1: int, imm: int) {
     24 	var x: int;
     25 
     26 	if imm < -(1 << 11) || imm >= (1 << 11) {
     27 		die("riscv64_emiti: immediate overflow");
     28 	}
     29 
     30 	x = (imm << 20) + (rs1 << 15) + (fn << 12) + (rd << 7) + op;
     31 	as_emit(c.s, x);
     32 	as_emit(c.s, x >> 8);
     33 	as_emit(c.s, x >> 16);
     34 	as_emit(c.s, x >> 24);
     35 }
     36 
     37 //S =  imm7[31:25] rs2[24:20] rs1[19:15] func3[14:12] i5[11:7] op[6:0]
     38 func riscv64_emits(c: *compiler, op: int, fn: int, rs1: int, rs2: int, imm: int) {
     39 	var x: int;
     40 
     41 	if imm < -(1 << 11) || imm >= (1 << 11) {
     42 		die("riscv64_emits immediate overflow");
     43 	}
     44 
     45 	x = ((imm >> 5) << 25) + (rs2 << 20) + (rs1 << 15) + (fn << 12) + ((imm & 31) << 7) + op;
     46 	as_emit(c.s, x);
     47 	as_emit(c.s, x >> 8);
     48 	as_emit(c.s, x >> 16);
     49 	as_emit(c.s, x >> 24);
     50 }
     51 
     52 func riscv64_lui(c: *compiler, rd: int, imm: int) {
     53 	var x: int;
     54 
     55 	if imm < -0x80000 || imm >= 0x80000 {
     56 		die("riscv64_lui immediate overflow");
     57 	}
     58 
     59 	x = (imm << 12) + (rd << 7) + 0b0110111;
     60 	as_emit(c.s, x);
     61 	as_emit(c.s, x >> 8);
     62 	as_emit(c.s, x >> 16);
     63 	as_emit(c.s, x >> 24);
     64 }
     65 
     66 func riscv64_li(c: *compiler, rd: int, imm: int) {
     67 	var x0: int;
     68 	var x1: int;
     69 	var x2: int;
     70 	var x3: int;
     71 	if imm >= -2048 && imm < 2048 {
     72 		riscv64_addi(c, rd, 0, imm);
     73 	} else {
     74 		x0 = -(imm & 0x800) | (imm & 0xfff);
     75 		imm = (imm - x0) >> 12;
     76 		x1 = -(imm & 0x80000) | (imm & 0xfffff);
     77 		imm = (imm - x1) >> 20;
     78 		x2 = -(imm & 0x800) | (imm & 0xfff);
     79 		imm = (imm - x2) >> 12;
     80 		x3 = -(imm & 0x80000) | (imm & 0xfffff);
     81 
     82 		riscv64_lui(c, 31, x3);
     83 		riscv64_addi(c, 31, 31, x2);
     84 		riscv64_slli(c, rd, 31, 32);
     85 		riscv64_lui(c, 31, x1);
     86 		riscv64_addi(c, 31, 31, x0);
     87 		riscv64_add(c, rd, rd, 31);
     88 	}
     89 }
     90 
     91 func riscv64_addli(c: *compiler, rd: int, rs: int, imm: int) {
     92 	if rs == 0 {
     93 		riscv64_li(c, rd, imm);
     94 	} else {
     95 		riscv64_li(c, 31, imm);
     96 		riscv64_add(c, rd, rs, 31);
     97 	}
     98 }
     99 
    100 func riscv64_addi(c: *compiler, rd: int, rs: int, imm: int) {
    101 	riscv64_emiti(c, 0b0010011, 0b000, rd, rs, imm);
    102 }
    103 
    104 func riscv64_ld(c: *compiler, rd: int, rs: int, imm: int) {
    105 	riscv64_emiti(c, 0b0000011, 0b011, rd, rs, imm);
    106 }
    107 
    108 func riscv64_lbu(c: *compiler, rd: int, rs: int, imm: int) {
    109 	riscv64_emiti(c, 0b0000011, 0b100, rd, rs, imm);
    110 }
    111 
    112 func riscv64_sd(c: *compiler, rs: int, rd: int, imm: int) {
    113 	riscv64_emits(c, 0b0100011, 0b011, rd, rs, imm);
    114 }
    115 
    116 func riscv64_sb(c: *compiler, rs: int, rd: int, imm: int) {
    117 	riscv64_emits(c, 0b0100011, 0b000, rd, rs, imm);
    118 }
    119 
    120 func riscv64_nop(c: *compiler) {
    121 	riscv64_emiti(c, 0b0010011, 0b000, 0, 0, 0);
    122 }
    123 
    124 func riscv64_ecall(c: *compiler) {
    125 	riscv64_emiti(c, 0b1110011, 0b000, 0, 0, 0);
    126 }
    127 
    128 func riscv64_ebreak(c: *compiler) {
    129 	riscv64_emiti(c, 0b1110011, 0b000, 0, 0, 1);
    130 }
    131 
    132 func riscv64_unimp(c: *compiler) {
    133 	riscv64_emiti(c, 0b1110011, 0b001, 0, 0, 3072);
    134 }
    135 
    136 func riscv64_mv(c: *compiler, rd: int, rs: int) {
    137 	riscv64_emiti(c, 0b0010011, 0b000, rd, rs, 0);
    138 }
    139 
    140 func riscv64_jalr(c: *compiler, rd: int, rs: int) {
    141 	riscv64_emiti(c, 0b1100111, 0b000, rd, rs, 0);
    142 }
    143 
    144 func riscv64_ret(c: *compiler) {
    145 	riscv64_emiti(c, 0b1100111, 0b000, 0, 1, 0);
    146 }
    147 
    148 func riscv64_slli(c: *compiler, rd: int, rs: int, shift: int) {
    149 	riscv64_emiti(c, 0b0010011, 0b001, rd, rs, shift);
    150 }
    151 
    152 func riscv64_add(c: *compiler, rd: int, rs1: int, rs2: int) {
    153 	riscv64_emitr(c, 0b0110011, 0b000, rd, rs1, rs2);
    154 }
    155 
    156 func riscv64_sub(c: *compiler, rd: int, rs1: int, rs2: int) {
    157 	riscv64_emitr(c, 0b0110011, 0b0100000000, rd, rs1, rs2);
    158 }
    159 
    160 func riscv64_and(c: *compiler, rd: int, rs1: int, rs2: int) {
    161 	riscv64_emitr(c, 0b0110011, 0b0000000111, rd, rs1, rs2);
    162 }
    163 
    164 func riscv64_or(c: *compiler, rd: int, rs1: int, rs2: int) {
    165 	riscv64_emitr(c, 0b0110011, 0b0000000110, rd, rs1, rs2);
    166 }
    167 
    168 func riscv64_xor(c: *compiler, rd: int, rs1: int, rs2: int) {
    169 	riscv64_emitr(c, 0b0110011, 0b0000000100, rd, rs1, rs2);
    170 }
    171 
    172 func riscv64_not(c: *compiler, rd: int, rs1: int) {
    173 	riscv64_emiti(c, 0b0010011, 0b100, rd, rs1, -1);
    174 }
    175 
    176 func riscv64_xor1(c: *compiler, rd: int, rs1: int) {
    177 	riscv64_emiti(c, 0b0010011, 0b100, rd, rs1, 1);
    178 }
    179 
    180 func riscv64_sll(c: *compiler, rd: int, rs1: int, rs2: int) {
    181 	riscv64_emitr(c, 0b0110011, 0b0000000001, rd, rs1, rs2);
    182 }
    183 
    184 func riscv64_srl(c: *compiler, rd: int, rs1: int, rs2: int) {
    185 	riscv64_emitr(c, 0b0110011, 0b0000000101, rd, rs1, rs2);
    186 }
    187 
    188 func riscv64_slt(c: *compiler, rd: int, rs1: int, rs2: int) {
    189 	riscv64_emitr(c, 0b0110011, 0b0000000010, rd, rs1, rs2);
    190 }
    191 
    192 func riscv64_sltu(c: *compiler, rd: int, rs1: int, rs2: int) {
    193 	riscv64_emitr(c, 0b0110011, 0b0000000011, rd, rs1, rs2);
    194 }
    195 
    196 func riscv64_seqz(c: *compiler, rd: int, rs1: int) {
    197 	riscv64_emiti(c, 0b0010011, 0b0000000011, rd, rs1, 1);
    198 }
    199 
    200 func riscv64_div(c: *compiler, rd: int, rs1: int, rs2: int) {
    201 	riscv64_emitr(c, 0b0110011, 0b0000001100, rd, rs1, rs2);
    202 }
    203 
    204 func riscv64_rem(c: *compiler, rd: int, rs1: int, rs2: int) {
    205 	riscv64_emitr(c, 0b0110011, 0b0000001110, rd, rs1, rs2);
    206 }
    207 
    208 func riscv64_mul(c: *compiler, rd: int, rs1: int, rs2: int) {
    209 	riscv64_emitr(c, 0b0110011, 0b0000001000, rd, rs1, rs2);
    210 }
    211 
    212 func riscv64_j(c: *compiler, target: *label) {
    213 	reserve(c.s, 16);
    214 	riscv64_ebreak(c);
    215 	riscv64_nop(c);
    216 	addfixup(c.s, target, FIXUP_RISCV_J);
    217 }
    218 
    219 func riscv64_bz(c: *compiler, rs: int, target: *label) {
    220 	riscv64_emits(c, 0b1100011, 0b001, rs, 0, 12);
    221 	riscv64_j(c, target);
    222 }
    223 
    224 func riscv64_push(c: *compiler, rs: int) {
    225 	riscv64_addi(c, 2, 2, -8);
    226 	riscv64_sd(c, rs, 2, 0);
    227 }
    228 
    229 func riscv64_pop(c: *compiler, rd: int) {
    230 	riscv64_ld(c, rd, 2, 0);
    231 	riscv64_addi(c, 2, 2, 8);
    232 }
    233 
    234 func riscv64_pcrel(c: *compiler, rd: int, target: *label) {
    235 	reserve(c.s, 16);
    236 	riscv64_ebreak(c);
    237 	riscv64_addi(c, 5, 5, 0);
    238 	addfixup(c.s, target, FIXUP_RISCV_AUIPC);
    239 }
    240 
    241 func riscv64_builtin(c: *compiler) {
    242 	var d: *decl;
    243 
    244 	d = find(c, "syscall", nil, 1);
    245 	if (d.func_defined && !d.func_label.fixed) {
    246 		fixup_label(c.s, d.func_label);
    247 		add_symbol(c.s, d.name, d.func_label);
    248 		riscv64_mv(c, 17, 10);
    249 		riscv64_mv(c, 10, 11);
    250 		riscv64_mv(c, 11, 12);
    251 		riscv64_mv(c, 12, 13);
    252 		riscv64_mv(c, 13, 14);
    253 		riscv64_mv(c, 14, 15);
    254 		riscv64_mv(c, 15, 16);
    255 		riscv64_ecall(c);
    256 		riscv64_ret(c);
    257 	}
    258 
    259 	d = find(c, "_restorer", nil, 1);
    260 	if (d.func_defined && !d.func_label.fixed) {
    261 		fixup_label(c.s, d.func_label);
    262 		add_symbol(c.s, d.name, d.func_label);
    263 		riscv64_addi(c, 17, 0, 139);
    264 		riscv64_ecall(c);
    265 	}
    266 }
    267 
    268 func riscv64_output_ir(c: *compiler, d: *decl) {
    269 	var ic: *irfunc;
    270 
    271 	ic = d.func_ir;
    272 
    273 	ic.c.filename = ic.filename;
    274 	ic.c.lineno = ic.lineno;
    275 	ic.c.colno = ic.colno;
    276 	ic.s.filename = ic.filename;
    277 	ic.s.lineno = ic.lineno;
    278 
    279 	fixup_label(c.s, d.func_label);
    280 	add_symbol(c.s, d.name, d.func_label);
    281 
    282 	if strcmp(d.name, "_start") == 0 {
    283 		riscv64_ld(c, 10, 2, 0);
    284 		riscv64_addi(c, 11, 2, 8);
    285 		riscv64_slli(c, 12, 10, 3);
    286 		riscv64_addi(c, 12, 12, 8);
    287 		riscv64_add(c, 12, 11, 12);
    288 	} else if strcmp(d.name, "_kstart") == 0 {
    289 		die("unimplemented kstart on arm");
    290 	}
    291 
    292 	// Allocate local variables
    293 	riscv64_output_irvars(c, ic);
    294 
    295 	// Output all blocks
    296 	riscv64_output_irblock(c, ic, ic.blocks[0]);
    297 
    298 	// Clear the marks
    299 	irreset(ic.blocks[0]);
    300 }
    301 
    302 func riscv64_output_irvars(c: *compiler, ic: *irfunc) {
    303 	var offset: int;
    304 	var total: int;
    305 	var size: int;
    306 	var i: int;
    307 	var j: int;
    308 	var v: *irvar;
    309 
    310 	// Allocate local variables
    311 	offset = 16;
    312 	i = 0;
    313 	loop {
    314 		if i == ic.vars_len {
    315 			break;
    316 		}
    317 
    318 		v = ic.vars[i];
    319 
    320 		if v.dead {
    321 			i = i + 1;
    322 			continue;
    323 		}
    324 
    325 		if v.t && v.t.kind != TY_VOID {
    326 			size = type_sizeof(ic.c, v.t);
    327 		} else {
    328 			size = sizeof(i);
    329 		}
    330 
    331 		size = (size + 7) & -8;
    332 
    333 		v.offset = offset;
    334 
    335 		offset = offset + size;
    336 		i = i + 1;
    337 	}
    338 
    339 	offset = (offset + 15) & -16;
    340 	total = offset;
    341 	ic.frame_size = total;
    342 
    343 	// Setup the frame
    344 	riscv64_addli(c, 2, 2, -total);
    345 	riscv64_sd(c, 8, 2, 0);
    346 	riscv64_sd(c, 1, 2, 8);
    347 	riscv64_mv(c, 8, 2);
    348 
    349 	// Zero initialize local variables
    350 	offset = 16;
    351 	i = 0;
    352 	loop {
    353 		if i == ic.vars_len {
    354 			break;
    355 		}
    356 
    357 		v = ic.vars[i];
    358 
    359 		if v.dead {
    360 			i = i + 1;
    361 			continue;
    362 		}
    363 
    364 		if v.t && v.t.kind != TY_VOID {
    365 			size = type_sizeof(ic.c, v.t);
    366 		} else {
    367 			size = sizeof(i);
    368 		}
    369 
    370 		size = (size + 7) & -8;
    371 
    372 		if i < ic.arg_count && i < 8 {
    373 			riscv64_addli(c, 6, 8, offset);
    374 			riscv64_sd(c, 10 + i, 6, 0);
    375 		} else if i < ic.arg_count {
    376 			riscv64_addli(c, 6, 8, total + (i - 8));
    377 			riscv64_ld(c, 5, 6, 0);
    378 			riscv64_addli(c, 6, 8, offset);
    379 			riscv64_sd(c, 5, 6, 0);
    380 		} else {
    381 			j = 0;
    382 			loop {
    383 				if j >= size {
    384 					break;
    385 				}
    386 				riscv64_addli(c, 6, 8, offset + j);
    387 				riscv64_sd(c, 0, 6, 0);
    388 				j = j + 8;
    389 			}
    390 		}
    391 
    392 		offset = offset + size;
    393 		i = i + 1;
    394 	}
    395 }
    396 
    397 func riscv64_output_irblock(c: *compiler, ic: *irfunc, b: *irblock) {
    398 	var op: *irop;
    399 	var i: int;
    400 
    401 	b.mark = 1;
    402 
    403 	if !b.done {
    404 		cdie(ic.c, "no return in function");
    405 	}
    406 
    407 	fixup_label(ic.s, b.label);
    408 
    409 	i = 0;
    410 	loop {
    411 		if i == b.ops_len {
    412 			break;
    413 		}
    414 
    415 		op = b.ops[i];
    416 
    417 		riscv64_output_irstmt(c, ic, b, op);
    418 
    419 		i = i + 1;
    420 	}
    421 }
    422 
    423 func riscv64_output_irstmt(c: *compiler, ic: *irfunc, b: *irblock, o: *irop) {
    424 	var kind: int;
    425 
    426 	ic.c.filename = o.filename;
    427 	ic.c.lineno = o.lineno;
    428 	ic.c.colno = o.colno;
    429 	ic.s.filename = o.filename;
    430 	ic.s.lineno = o.lineno;
    431 
    432 	kind = o.kind;
    433 	if kind == IOP_STORE {
    434 		// Evaluate the address
    435 		if o.a.kind == IOP_LOAD {
    436 			riscv64_output_irexpr(c, ic, b, o.a.a);
    437 		} else if o.a.kind == IOP_VAR {
    438 			riscv64_addli(c, 5, 8, ic.vars[o.a.n].offset);
    439 		} else {
    440 			die("invalid store");
    441 		}
    442 
    443 		riscv64_push(c, 5);
    444 
    445 		// Evaluate the value
    446 		riscv64_output_irexpr(c, ic, b, o.b);
    447 
    448 		riscv64_pop(c, 6);
    449 
    450 		// Execute the store
    451 		if o.t.kind == TY_BYTE {
    452 			riscv64_sb(c, 5, 6, 0);
    453 		} else if type_isprim(o.t) {
    454 			riscv64_sd(c, 5, 6, 0);
    455 		} else {
    456 			cdie(ic.c, "invalid store");
    457 		}
    458 	} else if kind == IOP_RETVAL {
    459 		// Do nothing
    460 	} else if kind == IOP_ARG {
    461 		// Do nothing
    462 	} else if kind == IOP_CALL {
    463 		// Allocate some space for the arguments
    464 		if o.n > 8 {
    465 			riscv64_addli(c, 2, 2, -((o.n + 1) & -2) * sizeof(kind));
    466 		}
    467 
    468 		// Setup arguments
    469 		riscv64_output_irargs(c, ic, b, o);
    470 
    471 		// Call the function
    472 		riscv64_output_ircall(c, ic, b, o.a);
    473 
    474 		// Release space reserved for the arguments
    475 		if o.n > 8 {
    476 			riscv64_addli(c, 2, 2, ((o.n + 1) & -2) * sizeof(kind));
    477 		}
    478 
    479 		// Save the return value
    480 		riscv64_output_irretval(c, ic, b, o);
    481 
    482 		if b.out.mark {
    483 			riscv64_j(c, b.out.label);
    484 		} else {
    485 			riscv64_output_irblock(c, ic, b.out);
    486 		}
    487 		return;
    488 	} else if kind == IOP_JUMP {
    489 		if b.out.mark {
    490 			// Jump to an already output block
    491 			riscv64_j(c, b.out.label);
    492 		} else {
    493 			// Output a new block
    494 			riscv64_output_irblock(c, ic, b.out);
    495 		}
    496 		return;
    497 	} else if kind == IOP_BRANCH {
    498 		// Evaluate the condition and branch if zero
    499 		riscv64_output_irexpr(c, ic, b, o.a);
    500 
    501 		riscv64_bz(c, 5, b.alt.label);
    502 
    503 		// Then jump to the output
    504 		if b.out.mark {
    505 			riscv64_j(c, b.out.label);
    506 		} else {
    507 			riscv64_output_irblock(c, ic, b.out);
    508 		}
    509 
    510 		// And if we haven't already, output the alt branch
    511 		if !b.alt.mark {
    512 			riscv64_output_irblock(c, ic, b.alt);
    513 		}
    514 
    515 		return;
    516 	} else if kind == IOP_RETURN {
    517 		// Evaluate the return expression and return
    518 		if o.a {
    519 			riscv64_output_irexpr(c, ic, b, o.a);
    520 		}
    521 
    522 		riscv64_mv(c, 10, 5);
    523 		riscv64_ld(c, 1, 8, 8);
    524 		riscv64_ld(c, 8, 8, 0);
    525 		riscv64_addli(c, 2, 2, ic.frame_size);
    526 		riscv64_ret(c);
    527 	} else {
    528 		// Evaluate and discard the result
    529 		riscv64_output_irexpr(c, ic, b, o);
    530 	}
    531 }
    532 
    533 func riscv64_output_irargs(c: *compiler, ic: *irfunc, b: *irblock, o: *irop) {
    534 	var i: int;
    535 	var op: *irop;
    536 
    537 	i = 0;
    538 	loop {
    539 		if i == b.ops_len {
    540 			return;
    541 		}
    542 
    543 		op = b.ops[i];
    544 		if op.kind == IOP_ARG {
    545 			// Compute the value
    546 			riscv64_output_irexpr(c, ic, b, op.a);
    547 
    548 			if op.n < 8 {
    549 				riscv64_mv(c, 10 + op.n, 5);
    550 			} else {
    551 				// Stack argument
    552 				riscv64_addli(c, 6, 2, (op.n - 8) * 8);
    553 				riscv64_sd(c, 5, 6, 0);
    554 			}
    555 		}
    556 
    557 		i = i + 1;
    558 	}
    559 }
    560 
    561 func riscv64_output_irretval(c: *compiler, ic: *irfunc, b: *irblock, o: *irop) {
    562 	var i: int;
    563 	var op: *irop;
    564 
    565 	// Find the retval place
    566 	op = nil;
    567 	i = 0;
    568 	loop {
    569 		if i == b.ops_len {
    570 			return;
    571 		}
    572 
    573 		op = b.ops[i];
    574 		if op.kind == IOP_RETVAL {
    575 			break;
    576 		}
    577 
    578 		i = i + 1;
    579 	}
    580 
    581 	// Do nothing if there was no return value
    582 	if op.t.kind == TY_VOID {
    583 		return;
    584 	}
    585 
    586 	// Compute the address
    587 	if op.a.kind == IOP_LOAD {
    588 		riscv64_output_irexpr(c, ic, b, op.a.a);
    589 	} else if op.a.kind == IOP_VAR {
    590 		riscv64_addli(c, 5, 8, ic.vars[op.a.n].offset);
    591 	} else {
    592 		die("invalid store");
    593 	}
    594 
    595 	// Execute the store
    596 	if op.t.kind == TY_BYTE {
    597 		riscv64_sb(c, 10, 5, 0);
    598 	} else if type_isprim(op.t) {
    599 		riscv64_sd(c, 10, 5, 0);
    600 	} else {
    601 		cdie(ic.c, "invalid store");
    602 	}
    603 }
    604 
    605 func riscv64_output_irstr(c: *compiler, ic: *irfunc, b: *irblock, o: *irop) {
    606 	var s: *label;
    607 	s = as_blob(ic.s, o.s, o.slen + 1);
    608 	riscv64_pcrel(c, 5, s);
    609 }
    610 
    611 func riscv64_output_irfuncptr(c: *compiler, ic: *irfunc, b: *irblock, o: *irop) {
    612 	var d: *decl;
    613 	d = find(ic.c, o.s, nil, 0);
    614 	if !d || !d.func_defined {
    615 		cdie(ic.c, "no such function");
    616 	}
    617 	riscv64_pcrel(c, 5, d.func_label);
    618 }
    619 
    620 func riscv64_output_ircall(c: *compiler, ic: *irfunc, b: *irblock, o: *irop) {
    621 	riscv64_output_irexpr(c, ic, b, o);
    622 	riscv64_jalr(c, 1, 5);
    623 }
    624 
    625 func riscv64_output_irexpr(c: *compiler, ic: *irfunc, b: *irblock, o: *irop) {
    626 	var kind: int;
    627 
    628 	if !o {
    629 		cdie(ic.c, "no expr");
    630 	}
    631 
    632 	kind = o.kind;
    633 	if kind == IOP_VAR {
    634 		riscv64_addli(c, 6, 8, ic.vars[o.n].offset);
    635 		riscv64_ld(c, 5, 6, 0);
    636 	} else if kind == IOP_VARREF {
    637 		riscv64_addli(c, 5, 8, ic.vars[o.n].offset);
    638 	} else if kind == IOP_FUNC {
    639 		riscv64_output_irfuncptr(c, ic, b, o);
    640 	} else if kind == IOP_CONST {
    641 		riscv64_addli(c, 5, 0, o.n);
    642 	} else if kind == IOP_STR {
    643 		riscv64_output_irstr(c, ic, b, o);
    644 	} else if kind == IOP_LOAD {
    645 		riscv64_output_irexpr(c, ic, b, o.a);
    646 		if o.t.kind == TY_BYTE {
    647 			riscv64_lbu(c, 5, 5, 0);
    648 		} else if type_isprim(o.t) {
    649 			riscv64_ld(c, 5, 5, 0);
    650 		} else {
    651 			cdie(ic.c, "invalid load");
    652 		}
    653 	} else if kind == IOP_NEG {
    654 		riscv64_output_irexpr(c, ic, b, o.a);
    655 		riscv64_sub(c, 5, 0, 5);
    656 	} else if kind == IOP_NOT {
    657 		riscv64_output_irexpr(c, ic, b, o.a);
    658 		riscv64_not(c, 5, 5);
    659 	} else if kind == IOP_ADD {
    660 		riscv64_output_irexpr(c, ic, b, o.b);
    661 		riscv64_push(c, 5);
    662 		riscv64_output_irexpr(c, ic, b, o.a);
    663 		riscv64_pop(c, 6);
    664 		riscv64_add(c, 5, 5, 6);
    665 	} else if kind == IOP_AND {
    666 		riscv64_output_irexpr(c, ic, b, o.b);
    667 		riscv64_push(c, 5);
    668 		riscv64_output_irexpr(c, ic, b, o.a);
    669 		riscv64_pop(c, 6);
    670 		riscv64_and(c, 5, 5, 6);
    671 	} else if kind == IOP_OR {
    672 		riscv64_output_irexpr(c, ic, b, o.b);
    673 		riscv64_push(c, 5);
    674 		riscv64_output_irexpr(c, ic, b, o.a);
    675 		riscv64_pop(c, 6);
    676 		riscv64_or(c, 5, 5, 6);
    677 	} else if kind == IOP_XOR {
    678 		riscv64_output_irexpr(c, ic, b, o.b);
    679 		riscv64_push(c, 5);
    680 		riscv64_output_irexpr(c, ic, b, o.a);
    681 		riscv64_pop(c, 6);
    682 		riscv64_xor(c, 5, 5, 6);
    683 	} else if kind == IOP_DIV {
    684 		riscv64_output_irexpr(c, ic, b, o.b);
    685 		riscv64_push(c, 5);
    686 		riscv64_output_irexpr(c, ic, b, o.a);
    687 		riscv64_pop(c, 6);
    688 		riscv64_div(c, 5, 5, 6);
    689 	} else if kind == IOP_MOD {
    690 		riscv64_output_irexpr(c, ic, b, o.b);
    691 		riscv64_push(c, 5);
    692 		riscv64_output_irexpr(c, ic, b, o.a);
    693 		riscv64_pop(c, 6);
    694 		riscv64_rem(c, 5, 5, 6);
    695 	} else if kind == IOP_LSH {
    696 		riscv64_output_irexpr(c, ic, b, o.b);
    697 		riscv64_push(c, 5);
    698 		riscv64_output_irexpr(c, ic, b, o.a);
    699 		riscv64_pop(c, 6);
    700 		riscv64_sll(c, 5, 5, 6);
    701 	} else if kind == IOP_RSH {
    702 		riscv64_output_irexpr(c, ic, b, o.b);
    703 		riscv64_push(c, 5);
    704 		riscv64_output_irexpr(c, ic, b, o.a);
    705 		riscv64_pop(c, 6);
    706 		riscv64_srl(c, 5, 5, 6);
    707 	} else if kind == IOP_MUL {
    708 		riscv64_output_irexpr(c, ic, b, o.b);
    709 		riscv64_push(c, 5);
    710 		riscv64_output_irexpr(c, ic, b, o.a);
    711 		riscv64_pop(c, 6);
    712 		riscv64_mul(c, 5, 5, 6);
    713 	} else if kind == IOP_SUB {
    714 		riscv64_output_irexpr(c, ic, b, o.b);
    715 		riscv64_push(c, 5);
    716 		riscv64_output_irexpr(c, ic, b, o.a);
    717 		riscv64_pop(c, 6);
    718 		riscv64_sub(c, 5, 5, 6);
    719 	} else if kind == IOP_EQ {
    720 		riscv64_output_irexpr(c, ic, b, o.b);
    721 		riscv64_push(c, 5);
    722 		riscv64_output_irexpr(c, ic, b, o.a);
    723 		riscv64_pop(c, 6);
    724 		riscv64_sub(c, 5, 5, 6);
    725 		riscv64_seqz(c, 5, 5);
    726 	} else if kind == IOP_NE {
    727 		riscv64_output_irexpr(c, ic, b, o.b);
    728 		riscv64_push(c, 5);
    729 		riscv64_output_irexpr(c, ic, b, o.a);
    730 		riscv64_pop(c, 6);
    731 		riscv64_sub(c, 5, 5, 6);
    732 		riscv64_sltu(c, 5, 0, 5);
    733 	} else if kind == IOP_GT {
    734 		riscv64_output_irexpr(c, ic, b, o.b);
    735 		riscv64_push(c, 5);
    736 		riscv64_output_irexpr(c, ic, b, o.a);
    737 		riscv64_pop(c, 6);
    738 		riscv64_slt(c, 5, 6, 5);
    739 	} else if kind == IOP_GE {
    740 		riscv64_output_irexpr(c, ic, b, o.b);
    741 		riscv64_push(c, 5);
    742 		riscv64_output_irexpr(c, ic, b, o.a);
    743 		riscv64_pop(c, 6);
    744 		riscv64_slt(c, 5, 5, 6);
    745 		riscv64_xor1(c, 5, 5);
    746 	} else if kind == IOP_LT {
    747 		riscv64_output_irexpr(c, ic, b, o.b);
    748 		riscv64_push(c, 5);
    749 		riscv64_output_irexpr(c, ic, b, o.a);
    750 		riscv64_pop(c, 6);
    751 		riscv64_slt(c, 5, 5, 6);
    752 	} else if kind == IOP_LE {
    753 		riscv64_output_irexpr(c, ic, b, o.b);
    754 		riscv64_push(c, 5);
    755 		riscv64_output_irexpr(c, ic, b, o.a);
    756 		riscv64_pop(c, 6);
    757 		riscv64_slt(c, 5, 6, 5);
    758 		riscv64_xor1(c, 5, 5);
    759 	} else {
    760 		cdie(ic.c, "invalid op");
    761 	}
    762 }