os

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

aarch64.om (19311B)


      1 enum {
      2 	R_FP = 29,
      3 	R_LR = 30,
      4 	R_SP = 31,
      5 }
      6 
      7 enum {
      8 	COND_EQ = 0x0,
      9 	COND_NE = 0x1,
     10 	COND_GE = 0xa,
     11 	COND_LT = 0xb,
     12 	COND_GT = 0xc,
     13 	COND_LE = 0xd,
     14 }
     15 
     16 func aarch64_nop(c: *compiler) {
     17 	as_emit(c.s, 0x1f);
     18 	as_emit(c.s, 0x20);
     19 	as_emit(c.s, 0x03);
     20 	as_emit(c.s, 0xd5);
     21 }
     22 
     23 func aarch64_udf(c: *compiler) {
     24 	as_emit(c.s, 0x00);
     25 	as_emit(c.s, 0x00);
     26 	as_emit(c.s, 0x00);
     27 	as_emit(c.s, 0x00);
     28 }
     29 
     30 func aarch64_svc(c: *compiler) {
     31 	as_emit(c.s, 0x01);
     32 	as_emit(c.s, 0x00);
     33 	as_emit(c.s, 0x00);
     34 	as_emit(c.s, 0xd4);
     35 }
     36 
     37 func aarch64_ldr(c: *compiler, rd: int, rs: int, off: int) {
     38 	var x: int;
     39 	x = (0x1f2 << 23) + (1 << 22) + ((off & 0xfff) << 10) + (rs << 5) + rd;
     40 	as_emit(c.s, x);
     41 	as_emit(c.s, x >> 8);
     42 	as_emit(c.s, x >> 16);
     43 	as_emit(c.s, x >> 24);
     44 }
     45 
     46 func aarch64_str(c: *compiler, rd: int, rs: int, off: int) {
     47 	var x: int;
     48 	x = (0x1f2 << 23) + ((off & 0xfff) << 10) + (rs << 5) + rd;
     49 	as_emit(c.s, x);
     50 	as_emit(c.s, x >> 8);
     51 	as_emit(c.s, x >> 16);
     52 	as_emit(c.s, x >> 24);
     53 }
     54 
     55 func aarch64_mov(c: *compiler, rd: int, rs: int) {
     56 	var x: int;
     57 	if rd == R_SP || rs == R_SP {
     58 		x = (0x122 << 23) + (rs << 5) + rd;
     59 	} else {
     60 		x = (0x154 << 23) + (rs << 16) + (0x1f << 5) + rd;
     61 	}
     62 	as_emit(c.s, x);
     63 	as_emit(c.s, x >> 8);
     64 	as_emit(c.s, x >> 16);
     65 	as_emit(c.s, x >> 24);
     66 }
     67 
     68 func aarch64_movz(c: *compiler, rd: int, hw: int, x: int) {
     69 	x = (0x1a5 << 23) + ((hw & 3) << 21) + ((x & 0xffff) << 5) + rd;
     70 	as_emit(c.s, x);
     71 	as_emit(c.s, x >> 8);
     72 	as_emit(c.s, x >> 16);
     73 	as_emit(c.s, x >> 24);
     74 }
     75 
     76 func aarch64_movk(c: *compiler, rd: int, hw: int, x: int) {
     77 	x = (0x1e5 << 23) + ((hw & 3) << 21) + ((x & 0xffff) << 5) + rd;
     78 	as_emit(c.s, x);
     79 	as_emit(c.s, x >> 8);
     80 	as_emit(c.s, x >> 16);
     81 	as_emit(c.s, x >> 24);
     82 }
     83 
     84 func aarch64_addi(c: *compiler, rd: int, rs: int, imm: int) {
     85 	var x: int;
     86 	if imm >= 0 {
     87 		if imm < 0x1000 {
     88 			x = 0x91000000 + ((imm & 0xfff) << 10) + (rs << 5) + rd;
     89 			as_emit(c.s, x);
     90 			as_emit(c.s, x >> 8);
     91 			as_emit(c.s, x >> 16);
     92 			as_emit(c.s, x >> 24);
     93 		} else if imm < 0x1000000 {
     94 			x = 0x91000000 + ((imm & 0xfff) << 10) + (rs << 5) + rd;
     95 			as_emit(c.s, x);
     96 			as_emit(c.s, x >> 8);
     97 			as_emit(c.s, x >> 16);
     98 			as_emit(c.s, x >> 24);
     99 			x = 0x91400000 + (((imm >> 12) & 0xfff) << 10) + (rd << 5) + rd;
    100 			as_emit(c.s, x);
    101 			as_emit(c.s, x >> 8);
    102 			as_emit(c.s, x >> 16);
    103 			as_emit(c.s, x >> 24);
    104 		} else {
    105 			die("addi overflow");
    106 		}
    107 	} else {
    108 		if imm > -0x1000 {
    109 			imm = -imm;
    110 			x = 0xd1000000 + ((imm & 0xfff) << 10) + (rs << 5) + rd;
    111 			as_emit(c.s, x);
    112 			as_emit(c.s, x >> 8);
    113 			as_emit(c.s, x >> 16);
    114 			as_emit(c.s, x >> 24);
    115 		} else if imm > -0x1000000 {
    116 			imm = -imm;
    117 			x = 0xd1000000 + ((imm & 0xfff) << 10) + (rs << 5) + rd;
    118 			as_emit(c.s, x);
    119 			as_emit(c.s, x >> 8);
    120 			as_emit(c.s, x >> 16);
    121 			as_emit(c.s, x >> 24);
    122 			x = 0xd1400000 + (((imm >> 12) & 0xfff) << 10) + (rd << 5) + rd;
    123 			as_emit(c.s, x);
    124 			as_emit(c.s, x >> 8);
    125 			as_emit(c.s, x >> 16);
    126 			as_emit(c.s, x >> 24);
    127 		} else {
    128 			die("subi overflow");
    129 		}
    130 	}
    131 }
    132 
    133 func aarch64_addr(c: *compiler, rd: int, rn: int, rm: int, imm6: int) {
    134 	var x: int;
    135 	x = (0x116 << 23) + (rm << 16) + (imm6 << 10) + (rn << 5) + rd;
    136 	as_emit(c.s, x);
    137 	as_emit(c.s, x >> 8);
    138 	as_emit(c.s, x >> 16);
    139 	as_emit(c.s, x >> 24);
    140 }
    141 
    142 func aarch64_ldrb(c: *compiler, rt: int, rn: int) {
    143 	var x: int;
    144 	x = 0x39400000 + (rn << 5) + rt;
    145 	as_emit(c.s, x);
    146 	as_emit(c.s, x >> 8);
    147 	as_emit(c.s, x >> 16);
    148 	as_emit(c.s, x >> 24);
    149 }
    150 
    151 func aarch64_strb(c: *compiler, rt: int, rn: int) {
    152 	var x: int;
    153 	x = 0x39000000 + (rn << 5) + rt;
    154 	as_emit(c.s, x);
    155 	as_emit(c.s, x >> 8);
    156 	as_emit(c.s, x >> 16);
    157 	as_emit(c.s, x >> 24);
    158 }
    159 
    160 func aarch64_not(c: *compiler, rd: int, rm: int) {
    161 	var x: int;
    162 	x = 0xaa2003e0 + (rm << 16) + rd;
    163 	as_emit(c.s, x);
    164 	as_emit(c.s, x >> 8);
    165 	as_emit(c.s, x >> 16);
    166 	as_emit(c.s, x >> 24);
    167 }
    168 
    169 func aarch64_neg(c: *compiler, rd: int, rm: int) {
    170 	var x: int;
    171 	x = 0xcb0003e0 + (rm << 16) + rd;
    172 	as_emit(c.s, x);
    173 	as_emit(c.s, x >> 8);
    174 	as_emit(c.s, x >> 16);
    175 	as_emit(c.s, x >> 24);
    176 }
    177 
    178 func aarch64_sub(c: *compiler, rd: int, rn: int, rm: int) {
    179 	var x: int;
    180 	x = 0xcb000000 + (rm << 16) + (rn << 5) + rd;
    181 	as_emit(c.s, x);
    182 	as_emit(c.s, x >> 8);
    183 	as_emit(c.s, x >> 16);
    184 	as_emit(c.s, x >> 24);
    185 }
    186 
    187 func aarch64_or(c: *compiler, rd: int, rn: int, rm: int) {
    188 	var x: int;
    189 	x = 0xaa000000 + (rm << 16) + (rn << 5) + rd;
    190 	as_emit(c.s, x);
    191 	as_emit(c.s, x >> 8);
    192 	as_emit(c.s, x >> 16);
    193 	as_emit(c.s, x >> 24);
    194 }
    195 
    196 func aarch64_and(c: *compiler, rd: int, rn: int, rm: int) {
    197 	var x: int;
    198 	x = 0x8a000000 + (rm << 16) + (rn << 5) + rd;
    199 	as_emit(c.s, x);
    200 	as_emit(c.s, x >> 8);
    201 	as_emit(c.s, x >> 16);
    202 	as_emit(c.s, x >> 24);
    203 }
    204 
    205 func aarch64_xor(c: *compiler, rd: int, rn: int, rm: int) {
    206 	var x: int;
    207 	x = 0xca000000 + (rm << 16) + (rn << 5) + rd;
    208 	as_emit(c.s, x);
    209 	as_emit(c.s, x >> 8);
    210 	as_emit(c.s, x >> 16);
    211 	as_emit(c.s, x >> 24);
    212 }
    213 
    214 func aarch64_lsh(c: *compiler, rd: int, rn: int, rm: int) {
    215 	var x: int;
    216 	x = 0x9ac02000 + (rm << 16) + (rn << 5) + rd;
    217 	as_emit(c.s, x);
    218 	as_emit(c.s, x >> 8);
    219 	as_emit(c.s, x >> 16);
    220 	as_emit(c.s, x >> 24);
    221 }
    222 
    223 func aarch64_rsh(c: *compiler, rd: int, rn: int, rm: int) {
    224 	var x: int;
    225 	x = 0x9ac02400 + (rm << 16) + (rn << 5) + rd;
    226 	as_emit(c.s, x);
    227 	as_emit(c.s, x >> 8);
    228 	as_emit(c.s, x >> 16);
    229 	as_emit(c.s, x >> 24);
    230 }
    231 
    232 func aarch64_mul(c: *compiler, rd: int, rn: int, rm: int) {
    233 	var x: int;
    234 	x = 0x9b007c00 + (rm << 16) + (rn << 5) + rd;
    235 	as_emit(c.s, x);
    236 	as_emit(c.s, x >> 8);
    237 	as_emit(c.s, x >> 16);
    238 	as_emit(c.s, x >> 24);
    239 }
    240 
    241 func aarch64_sdiv(c: *compiler, rd: int, rn: int, rm: int) {
    242 	var x: int;
    243 	x = 0x9ac00c00 + (rm << 16) + (rn << 5) + rd;
    244 	as_emit(c.s, x);
    245 	as_emit(c.s, x >> 8);
    246 	as_emit(c.s, x >> 16);
    247 	as_emit(c.s, x >> 24);
    248 }
    249 
    250 func aarch64_msub(c: *compiler, rd: int, rn: int, rm: int, ra: int) {
    251 	var x: int;
    252 	x = 0x9b008000 + (rm << 16) + (ra << 10) + (rn << 5) + rd;
    253 	as_emit(c.s, x);
    254 	as_emit(c.s, x >> 8);
    255 	as_emit(c.s, x >> 16);
    256 	as_emit(c.s, x >> 24);
    257 }
    258 
    259 func aarch64_cmpi(c: *compiler, rn: int, imm12: int) {
    260 	var x: int;
    261 	x = 0xf100001f + ((imm12 & 0xfff) << 10) + (rn << 5);
    262 	as_emit(c.s, x);
    263 	as_emit(c.s, x >> 8);
    264 	as_emit(c.s, x >> 16);
    265 	as_emit(c.s, x >> 24);
    266 }
    267 
    268 func aarch64_cmp(c: *compiler, rn: int, rm: int) {
    269 	var x: int;
    270 	x = 0xeb00001f + (rm << 16) + (rn << 5);
    271 	as_emit(c.s, x);
    272 	as_emit(c.s, x >> 8);
    273 	as_emit(c.s, x >> 16);
    274 	as_emit(c.s, x >> 24);
    275 }
    276 
    277 func aarch64_cset(c: *compiler, rd: int, icond: int) {
    278 	var x: int;
    279 	x = 0x9a9f07e0 + (icond << 12) + rd;
    280 	as_emit(c.s, x);
    281 	as_emit(c.s, x >> 8);
    282 	as_emit(c.s, x >> 16);
    283 	as_emit(c.s, x >> 24);
    284 }
    285 
    286 func aarch64_bicond(c: *compiler, icond: int, target: *label) {
    287 	var x: int;
    288 	x = (0x54 << 24) + (2 << 5) + icond;
    289 	as_emit(c.s, x);
    290 	as_emit(c.s, x >> 8);
    291 	as_emit(c.s, x >> 16);
    292 	as_emit(c.s, x >> 24);
    293 	aarch64_udf(c);
    294 	addfixup(c.s, target, FIXUP_ARM_B);
    295 }
    296 
    297 func aarch64_push(c: *compiler, rs: int) {
    298 	aarch64_addi(c, R_SP, R_SP, -16);
    299 	aarch64_str(c, rs, R_SP, 0);
    300 }
    301 
    302 func aarch64_pop(c: *compiler, rd: int) {
    303 	aarch64_ldr(c, rd, R_SP, 0);
    304 	aarch64_addi(c, R_SP, R_SP, 16);
    305 }
    306 
    307 func aarch64_ret(c: *compiler) {
    308 	var x: int;
    309 	x = 0xd65f03c0;
    310 	as_emit(c.s, x);
    311 	as_emit(c.s, x >> 8);
    312 	as_emit(c.s, x >> 16);
    313 	as_emit(c.s, x >> 24);
    314 }
    315 
    316 func aarch64_jmp(c: *compiler, target: *label) {
    317 	reserve(c.s, 16);
    318 	aarch64_udf(c);
    319 	addfixup(c.s, target, FIXUP_ARM_B);
    320 }
    321 
    322 func aarch64_blr(c: *compiler, rs: int) {
    323 	var x: int;
    324 	x = 0xd63f0000 + (rs << 5);
    325 	as_emit(c.s, x);
    326 	as_emit(c.s, x >> 8);
    327 	as_emit(c.s, x >> 16);
    328 	as_emit(c.s, x >> 24);
    329 }
    330 
    331 func aarch64_adr(c: *compiler, target: *label) {
    332 	reserve(c.s, 16);
    333 	aarch64_udf(c);
    334 	aarch64_nop(c);
    335 	addfixup(c.s, target, FIXUP_ARM_ADR);
    336 }
    337 
    338 func aarch64_builtin(c: *compiler) {
    339 	var d: *decl;
    340 
    341 	d = find(c, "syscall", nil, 1);
    342 	if (d.func_defined && !d.func_label.fixed) {
    343 		fixup_label(c.s, d.func_label);
    344 		add_symbol(c.s, d.name, d.func_label);
    345 		aarch64_mov(c, 8, 0);
    346 		aarch64_mov(c, 0, 1);
    347 		aarch64_mov(c, 1, 2);
    348 		aarch64_mov(c, 2, 3);
    349 		aarch64_mov(c, 3, 4);
    350 		aarch64_mov(c, 4, 5);
    351 		aarch64_mov(c, 5, 6);
    352 		aarch64_svc(c);
    353 		aarch64_ret(c);
    354 	}
    355 
    356 	d = find(c, "_restorer", nil, 1);
    357 	if (d.func_defined && !d.func_label.fixed) {
    358 		fixup_label(c.s, d.func_label);
    359 		add_symbol(c.s, d.name, d.func_label);
    360 		aarch64_movz(c, 8, 0, 139);
    361 		aarch64_svc(c);
    362 	}
    363 }
    364 
    365 func aarch64_output_ir(c: *compiler, d: *decl) {
    366 	var ic: *irfunc;
    367 
    368 	ic = d.func_ir;
    369 
    370 	ic.c.filename = ic.filename;
    371 	ic.c.lineno = ic.lineno;
    372 	ic.c.colno = ic.colno;
    373 	ic.s.filename = ic.filename;
    374 	ic.s.lineno = ic.lineno;
    375 
    376 	fixup_label(c.s, d.func_label);
    377 	add_symbol(c.s, d.name, d.func_label);
    378 
    379 	if strcmp(d.name, "_start") == 0 {
    380 		aarch64_ldr(c, 0, 31, 0);
    381 		aarch64_addi(c, 1, 31, 8);
    382 		aarch64_addr(c, 2, 1, 0, 3);
    383 		aarch64_addi(c, 2, 2, 8);
    384 	} else if strcmp(d.name, "_kstart") == 0 {
    385 		die("unimplemented kstart on arm");
    386 	}
    387 
    388 	// Allocate local variables
    389 	aarch64_output_irvars(c, ic);
    390 
    391 	// Output all blocks
    392 	aarch64_output_irblock(c, ic, ic.blocks[0]);
    393 
    394 	// Clear the marks
    395 	irreset(ic.blocks[0]);
    396 }
    397 
    398 func aarch64_output_irvars(c: *compiler, ic: *irfunc) {
    399 	var offset: int;
    400 	var total: int;
    401 	var size: int;
    402 	var i: int;
    403 	var j: int;
    404 	var v: *irvar;
    405 
    406 	// Allocate local variables
    407 	offset = 16;
    408 	i = 0;
    409 	loop {
    410 		if i == ic.vars_len {
    411 			break;
    412 		}
    413 
    414 		v = ic.vars[i];
    415 
    416 		if v.dead {
    417 			i = i + 1;
    418 			continue;
    419 		}
    420 
    421 		if v.t && v.t.kind != TY_VOID {
    422 			size = type_sizeof(ic.c, v.t);
    423 		} else {
    424 			size = sizeof(i);
    425 		}
    426 
    427 		size = (size + 7) & -8;
    428 
    429 		v.offset = offset;
    430 
    431 		offset = offset + size;
    432 		i = i + 1;
    433 	}
    434 
    435 	offset = (offset + 15) & -16;
    436 	total = offset;
    437 	ic.frame_size = total;
    438 
    439 	// Setup the frame
    440 	aarch64_addi(c, R_SP, R_SP, -total);
    441 	aarch64_str(c, R_FP, R_SP, 0);
    442 	aarch64_str(c, R_LR, R_SP, 1);
    443 	aarch64_mov(c, R_FP, R_SP);
    444 
    445 	// Zero initialize local variables
    446 	aarch64_movz(c, 16, 0, 0);
    447 	offset = 16;
    448 	i = 0;
    449 	loop {
    450 		if i == ic.vars_len {
    451 			break;
    452 		}
    453 
    454 		v = ic.vars[i];
    455 
    456 		if v.dead {
    457 			i = i + 1;
    458 			continue;
    459 		}
    460 
    461 		if v.t && v.t.kind != TY_VOID {
    462 			size = type_sizeof(ic.c, v.t);
    463 		} else {
    464 			size = sizeof(i);
    465 		}
    466 
    467 		size = (size + 7) & -8;
    468 
    469 		if i < ic.arg_count && i < 8 {
    470 			aarch64_str(c, i, R_FP, offset >> 3);
    471 		} else if i < ic.arg_count {
    472 			aarch64_ldr(c, 17, 29, (total >> 3) + (i - 8));
    473 			aarch64_str(c, 17, 31, offset >> 3);
    474 		} else {
    475 			j = 0;
    476 			loop {
    477 				if j >= size {
    478 					break;
    479 				}
    480 				aarch64_str(c, 16, R_FP, (offset + j) >> 3);
    481 				j = j + 8;
    482 			}
    483 		}
    484 
    485 		offset = offset + size;
    486 		i = i + 1;
    487 	}
    488 
    489 }
    490 
    491 func aarch64_output_irblock(c: *compiler, ic: *irfunc, b: *irblock) {
    492 	var op: *irop;
    493 	var i: int;
    494 
    495 	b.mark = 1;
    496 
    497 	if !b.done {
    498 		cdie(ic.c, "no return in function");
    499 	}
    500 
    501 	fixup_label(ic.s, b.label);
    502 
    503 	i = 0;
    504 	loop {
    505 		if i == b.ops_len {
    506 			break;
    507 		}
    508 
    509 		op = b.ops[i];
    510 
    511 		aarch64_output_irstmt(c, ic, b, op);
    512 
    513 		i = i + 1;
    514 	}
    515 }
    516 
    517 func aarch64_output_irstmt(c: *compiler, ic: *irfunc, b: *irblock, o: *irop) {
    518 	var kind: int;
    519 
    520 	ic.c.filename = o.filename;
    521 	ic.c.lineno = o.lineno;
    522 	ic.c.colno = o.colno;
    523 	ic.s.filename = o.filename;
    524 	ic.s.lineno = o.lineno;
    525 
    526 	kind = o.kind;
    527 	if kind == IOP_STORE {
    528 		// Evaluate the address
    529 		if o.a.kind == IOP_LOAD {
    530 			aarch64_output_irexpr(c, ic, b, o.a.a);
    531 		} else if o.a.kind == IOP_VAR {
    532 			aarch64_addi(c, 16, R_FP, ic.vars[o.a.n].offset);
    533 		} else {
    534 			die("invalid store");
    535 		}
    536 
    537 		aarch64_push(c, 16);
    538 
    539 		// Evaluate the value
    540 		aarch64_output_irexpr(c, ic, b, o.b);
    541 
    542 		aarch64_pop(c, 17);
    543 
    544 		// Execute the store
    545 		if o.t.kind == TY_BYTE {
    546 			aarch64_strb(c, 16, 17);
    547 		} else if type_isprim(o.t) {
    548 			aarch64_str(c, 16, 17, 0);
    549 		} else {
    550 			cdie(ic.c, "invalid store");
    551 		}
    552 	} else if kind == IOP_RETVAL {
    553 		// Do nothing
    554 	} else if kind == IOP_ARG {
    555 		// Do nothing
    556 	} else if kind == IOP_CALL {
    557 		// Allocate some space for the arguments
    558 		if o.n > 8 {
    559 			aarch64_addi(c, R_SP, R_SP, -((o.n + 1) & -2) * sizeof(kind));
    560 		}
    561 
    562 		// Setup arguments
    563 		aarch64_output_irargs(c, ic, b, o);
    564 
    565 		// Call the function
    566 		aarch64_output_ircall(c, ic, b, o.a);
    567 
    568 		// Release space reserved for the arguments
    569 		if o.n > 8 {
    570 			aarch64_addi(c, R_SP, R_SP, ((o.n + 1) & -2) * sizeof(kind));
    571 		}
    572 
    573 		// Save the return value
    574 		aarch64_output_irretval(c, ic, b, o);
    575 
    576 		if b.out.mark {
    577 			aarch64_jmp(c, b.out.label);
    578 		} else {
    579 			aarch64_output_irblock(c, ic, b.out);
    580 		}
    581 		return;
    582 	} else if kind == IOP_JUMP {
    583 		if b.out.mark {
    584 			// Jump to an already output block
    585 			aarch64_jmp(c, b.out.label);
    586 		} else {
    587 			// Output a new block
    588 			aarch64_output_irblock(c, ic, b.out);
    589 		}
    590 		return;
    591 	} else if kind == IOP_BRANCH {
    592 		// Evaluate the condition and branch if zero
    593 		aarch64_output_irexpr(c, ic, b, o.a);
    594 
    595 		aarch64_cmpi(c, 16, 0);
    596 		aarch64_bicond(c, COND_NE, b.alt.label);
    597 
    598 		// Then jump to the output
    599 		if b.out.mark {
    600 			aarch64_jmp(c, b.out.label);
    601 		} else {
    602 			aarch64_output_irblock(c, ic, b.out);
    603 		}
    604 
    605 		// And if we haven't already, output the alt branch
    606 		if !b.alt.mark {
    607 			aarch64_output_irblock(c, ic, b.alt);
    608 		}
    609 
    610 		return;
    611 	} else if kind == IOP_RETURN {
    612 		// Evaluate the return expression and return
    613 		if o.a {
    614 			aarch64_output_irexpr(c, ic, b, o.a);
    615 		}
    616 
    617 		aarch64_mov(c, 0, 16);
    618 		aarch64_ldr(c, R_LR, R_FP, 1);
    619 		aarch64_ldr(c, R_FP, R_FP, 0);
    620 		aarch64_addi(c, R_SP, R_SP, ic.frame_size);
    621 		aarch64_ret(c);
    622 	} else {
    623 		// Evaluate and discard the result
    624 		aarch64_output_irexpr(c, ic, b, o);
    625 	}
    626 }
    627 
    628 func aarch64_output_irargs(c: *compiler, ic: *irfunc, b: *irblock, o: *irop) {
    629 	var i: int;
    630 	var op: *irop;
    631 
    632 	i = 0;
    633 	loop {
    634 		if i == b.ops_len {
    635 			return;
    636 		}
    637 
    638 		op = b.ops[i];
    639 		if op.kind == IOP_ARG {
    640 			// Compute the value
    641 			aarch64_output_irexpr(c, ic, b, op.a);
    642 
    643 			if op.n < 8 {
    644 				aarch64_mov(c, op.n, 16);
    645 			} else {
    646 				// Stack argument
    647 				aarch64_str(c, 16, R_SP,  op.n - 8);
    648 			}
    649 		}
    650 
    651 		i = i + 1;
    652 	}
    653 }
    654 
    655 func aarch64_output_irretval(c: *compiler, ic: *irfunc, b: *irblock, o: *irop) {
    656 	var i: int;
    657 	var op: *irop;
    658 
    659 	// Find the retval place
    660 	op = nil;
    661 	i = 0;
    662 	loop {
    663 		if i == b.ops_len {
    664 			return;
    665 		}
    666 
    667 		op = b.ops[i];
    668 		if op.kind == IOP_RETVAL {
    669 			break;
    670 		}
    671 
    672 		i = i + 1;
    673 	}
    674 
    675 	// Do nothing if there was no return value
    676 	if op.t.kind == TY_VOID {
    677 		return;
    678 	}
    679 
    680 	// Compute the address
    681 	if op.a.kind == IOP_LOAD {
    682 		aarch64_output_irexpr(c, ic, b, op.a.a);
    683 	} else if op.a.kind == IOP_VAR {
    684 		aarch64_addi(c, 16, R_FP, ic.vars[op.a.n].offset);
    685 	} else {
    686 		die("invalid store");
    687 	}
    688 
    689 	// Execute the store
    690 	if op.t.kind == TY_BYTE {
    691 		aarch64_strb(c, 0, 16);
    692 	} else if type_isprim(op.t) {
    693 		aarch64_str(c, 0, 16, 0);
    694 	} else {
    695 		cdie(ic.c, "invalid store");
    696 	}
    697 }
    698 
    699 func aarch64_output_irstr(c: *compiler, ic: *irfunc, b: *irblock, o: *irop) {
    700 	var s: *label;
    701 	s = as_blob(ic.s, o.s, o.slen + 1);
    702 	aarch64_adr(c, s);
    703 }
    704 
    705 func aarch64_output_irfuncptr(c: *compiler, ic: *irfunc, b: *irblock, o: *irop) {
    706 	var d: *decl;
    707 	d = find(ic.c, o.s, nil, 0);
    708 	if !d || !d.func_defined {
    709 		cdie(ic.c, "no such function");
    710 	}
    711 	aarch64_adr(c, d.func_label);
    712 }
    713 
    714 func aarch64_output_ircall(c: *compiler, ic: *irfunc, b: *irblock, o: *irop) {
    715 	aarch64_output_irexpr(c, ic, b, o);
    716 	aarch64_blr(c, 16);
    717 }
    718 
    719 func aarch64_output_irexpr(c: *compiler, ic: *irfunc, b: *irblock, o: *irop) {
    720 	var kind: int;
    721 
    722 	if !o {
    723 		cdie(ic.c, "no expr");
    724 	}
    725 
    726 	kind = o.kind;
    727 	if kind == IOP_VAR {
    728 		aarch64_ldr(c, 16, R_FP, ic.vars[o.n].offset >> 3);
    729 	} else if kind == IOP_VARREF {
    730 		aarch64_addi(c, 16, R_FP, ic.vars[o.n].offset);
    731 	} else if kind == IOP_FUNC {
    732 		aarch64_output_irfuncptr(c, ic, b, o);
    733 	} else if kind == IOP_CONST {
    734 		aarch64_movz(c, 16, 0, o.n);
    735 		if o.n < 0 || o.n >= (1 << 16) {
    736 			aarch64_movk(c, 16, 1, o.n >> 16);
    737 		}
    738 		if o.n < 0 || o.n >= (1 << 32) {
    739 			aarch64_movk(c, 16, 2, o.n >> 32);
    740 		}
    741 		if o.n < 0 || o.n >= (1 << 48) {
    742 			aarch64_movk(c, 16, 3, o.n >> 48);
    743 		}
    744 	} else if kind == IOP_STR {
    745 		aarch64_output_irstr(c, ic, b, o);
    746 	} else if kind == IOP_LOAD {
    747 		aarch64_output_irexpr(c, ic, b, o.a);
    748 		if o.t.kind == TY_BYTE {
    749 			aarch64_ldrb(c, 16, 16);
    750 		} else if type_isprim(o.t) {
    751 			aarch64_ldr(c, 16, 16, 0);
    752 		} else {
    753 			cdie(ic.c, "invalid load");
    754 		}
    755 	} else if kind == IOP_NEG {
    756 		aarch64_output_irexpr(c, ic, b, o.a);
    757 		aarch64_neg(c, 16, 16);
    758 	} else if kind == IOP_NOT {
    759 		aarch64_output_irexpr(c, ic, b, o.a);
    760 		aarch64_not(c, 16, 16);
    761 	} else if kind == IOP_ADD {
    762 		aarch64_output_irexpr(c, ic, b, o.b);
    763 		aarch64_push(c, 16);
    764 		aarch64_output_irexpr(c, ic, b, o.a);
    765 		aarch64_pop(c, 17);
    766 		aarch64_addr(c, 16, 17, 16, 0);
    767 	} else if kind == IOP_AND {
    768 		aarch64_output_irexpr(c, ic, b, o.b);
    769 		aarch64_push(c, 16);
    770 		aarch64_output_irexpr(c, ic, b, o.a);
    771 		aarch64_pop(c, 17);
    772 		aarch64_and(c, 16, 17, 16);
    773 	} else if kind == IOP_OR {
    774 		aarch64_output_irexpr(c, ic, b, o.b);
    775 		aarch64_push(c, 16);
    776 		aarch64_output_irexpr(c, ic, b, o.a);
    777 		aarch64_pop(c, 17);
    778 		aarch64_or(c, 16, 17, 16);
    779 	} else if kind == IOP_XOR {
    780 		aarch64_output_irexpr(c, ic, b, o.b);
    781 		aarch64_push(c, 16);
    782 		aarch64_output_irexpr(c, ic, b, o.a);
    783 		aarch64_pop(c, 17);
    784 		aarch64_xor(c, 16, 17, 16);
    785 	} else if kind == IOP_DIV {
    786 		aarch64_output_irexpr(c, ic, b, o.b);
    787 		aarch64_push(c, 16);
    788 		aarch64_output_irexpr(c, ic, b, o.a);
    789 		aarch64_pop(c, 17);
    790 		aarch64_sdiv(c, 16, 16, 17);
    791 	} else if kind == IOP_MOD {
    792 		aarch64_output_irexpr(c, ic, b, o.b);
    793 		aarch64_push(c, 16);
    794 		aarch64_output_irexpr(c, ic, b, o.a);
    795 		aarch64_pop(c, 17);
    796 		aarch64_sdiv(c, 9, 16, 17);
    797 		aarch64_msub(c, 16, 9, 17, 16);
    798 	} else if kind == IOP_LSH {
    799 		aarch64_output_irexpr(c, ic, b, o.b);
    800 		aarch64_push(c, 16);
    801 		aarch64_output_irexpr(c, ic, b, o.a);
    802 		aarch64_pop(c, 17);
    803 		aarch64_lsh(c, 16, 16, 17);
    804 	} else if kind == IOP_RSH {
    805 		aarch64_output_irexpr(c, ic, b, o.b);
    806 		aarch64_push(c, 16);
    807 		aarch64_output_irexpr(c, ic, b, o.a);
    808 		aarch64_pop(c, 17);
    809 		aarch64_rsh(c, 16, 16, 17);
    810 	} else if kind == IOP_MUL {
    811 		aarch64_output_irexpr(c, ic, b, o.b);
    812 		aarch64_push(c, 16);
    813 		aarch64_output_irexpr(c, ic, b, o.a);
    814 		aarch64_pop(c, 17);
    815 		aarch64_mul(c, 16, 17, 16);
    816 	} else if kind == IOP_SUB {
    817 		aarch64_output_irexpr(c, ic, b, o.b);
    818 		aarch64_push(c, 16);
    819 		aarch64_output_irexpr(c, ic, b, o.a);
    820 		aarch64_pop(c, 17);
    821 		aarch64_sub(c, 16, 16, 17);
    822 	} else if kind == IOP_EQ {
    823 		aarch64_output_irexpr(c, ic, b, o.b);
    824 		aarch64_push(c, 16);
    825 		aarch64_output_irexpr(c, ic, b, o.a);
    826 		aarch64_pop(c, 17);
    827 		aarch64_cmp(c, 16, 17);
    828 		aarch64_cset(c, 16, COND_NE);
    829 	} else if kind == IOP_NE {
    830 		aarch64_output_irexpr(c, ic, b, o.b);
    831 		aarch64_push(c, 16);
    832 		aarch64_output_irexpr(c, ic, b, o.a);
    833 		aarch64_pop(c, 17);
    834 		aarch64_cmp(c, 16, 17);
    835 		aarch64_cset(c, 16, COND_EQ);
    836 	} else if kind == IOP_GT {
    837 		aarch64_output_irexpr(c, ic, b, o.b);
    838 		aarch64_push(c, 16);
    839 		aarch64_output_irexpr(c, ic, b, o.a);
    840 		aarch64_pop(c, 17);
    841 		aarch64_cmp(c, 16, 17);
    842 		aarch64_cset(c, 16, COND_LE);
    843 	} else if kind == IOP_GE {
    844 		aarch64_output_irexpr(c, ic, b, o.b);
    845 		aarch64_push(c, 16);
    846 		aarch64_output_irexpr(c, ic, b, o.a);
    847 		aarch64_pop(c, 17);
    848 		aarch64_cmp(c, 16, 17);
    849 		aarch64_cset(c, 16, COND_LT);
    850 	} else if kind == IOP_LT {
    851 		aarch64_output_irexpr(c, ic, b, o.b);
    852 		aarch64_push(c, 16);
    853 		aarch64_output_irexpr(c, ic, b, o.a);
    854 		aarch64_pop(c, 17);
    855 		aarch64_cmp(c, 16, 17);
    856 		aarch64_cset(c, 16, COND_GE);
    857 	} else if kind == IOP_LE {
    858 		aarch64_output_irexpr(c, ic, b, o.b);
    859 		aarch64_push(c, 16);
    860 		aarch64_output_irexpr(c, ic, b, o.a);
    861 		aarch64_pop(c, 17);
    862 		aarch64_cmp(c, 16, 17);
    863 		aarch64_cset(c, 16, COND_GT);
    864 	} else {
    865 		cdie(ic.c, "invalid op");
    866 	}
    867 }