authorgravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-03-13 18:40:35-07:00
committergravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-05-11 02:17:11-07:00
log5e770407cf50ae8cd103644c8ca297da52adb5b8
tree62696d66694b492b9327f1241b8e699a17dc0b14
parentdceff2592f6a6305770916499c688071563ddf0d

riscv: basic function arguments

- rename setRegOrMem -> setValue - a naive method of passing arguments by register - gather the prologue and epilogue and generate them in Emit.zig. this is cleaner because we have the final stack size in the emit step. - define the "fa" register set, which contains the RISC-V calling convention defined function argument registers

4 files changed, 216 insertions(+), 178 deletions(-)

src/arch/riscv64/CodeGen.zig+126-147
......@@ -34,7 +34,10 @@ const Register = bits.Register;
3434const RegisterManager = abi.RegisterManager;
3535const RegisterLock = RegisterManager.RegisterLock;
3636const callee_preserved_regs = abi.callee_preserved_regs;
37/// General Purpose
3738const gp = abi.RegisterClass.gp;
39/// Function Args
40const fa = abi.RegisterClass.fa;
3841
3942const InnerError = CodeGenError || error{OutOfRegisters};
4043
......@@ -297,6 +300,7 @@ pub fn generate(
297300 .prev_di_pc = 0,
298301 .prev_di_line = func.lbrace_line,
299302 .prev_di_column = func.lbrace_column,
303 .stack_size = @max(32, function.max_end_stack),
300304 };
301305 defer emit.deinit();
302306
......@@ -349,14 +353,9 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 {
349353}
350354
351355fn gen(self: *Self) !void {
352 const mod = self.bin_file.comp.module.?;
353 const cc = self.fn_type.fnCallingConvention(mod);
354
355 if (cc == .Naked) return self.fail("TODO: gen support callconv(.{s})", .{@tagName(cc)});
356
357356 _ = try self.addInst(.{
358357 .tag = .psuedo_prologue,
359 .data = .{ .imm12 = 0 }, // Backpatched later.
358 .data = .{ .nop = {} }, // Backpatched later.
360359 });
361360
362361 _ = try self.addInst(.{
......@@ -366,32 +365,6 @@ fn gen(self: *Self) !void {
366365
367366 try self.genBody(self.air.getMainBody());
368367
369 // Backpatch prologue stack size
370 if (math.cast(i12, self.max_end_stack)) |casted_stack_size| {
371 self.mir_instructions.items(.data)[0].imm12 = casted_stack_size;
372 } else return self.fail("TODO support larger stack sizes, got {}", .{self.max_end_stack});
373
374 _ = try self.addInst(.{
375 .tag = .dbg_epilogue_begin,
376 .data = .{ .nop = {} },
377 });
378
379 // exitlude jumps
380 if (self.exitlude_jump_relocs.items.len > 0 and
381 self.exitlude_jump_relocs.items[self.exitlude_jump_relocs.items.len - 1] == self.mir_instructions.len - 2)
382 {
383 // If the last Mir instruction (apart from the
384 // dbg_epilogue_begin) is the last exitlude jump
385 // relocation (which would just jump one instruction
386 // further), it can be safely removed
387 self.mir_instructions.orderedRemove(self.exitlude_jump_relocs.pop());
388 }
389
390 for (self.exitlude_jump_relocs.items) |jmp_reloc| {
391 _ = jmp_reloc;
392 return self.fail("TODO add branches in RISCV64", .{});
393 }
394
395368 // Drop them off at the rbrace.
396369 _ = try self.addInst(.{
397370 .tag = .dbg_line,
......@@ -501,7 +474,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
501474 .fpext => try self.airFpext(inst),
502475 .intcast => try self.airIntCast(inst),
503476 .trunc => try self.airTrunc(inst),
504 .int_from_bool => try self.airIntFromBool(inst),
477 .int_from_bool => try self.airIntFromBool(inst),
505478 .is_non_null => try self.airIsNonNull(inst),
506479 .is_non_null_ptr => try self.airIsNonNullPtr(inst),
507480 .is_null => try self.airIsNull(inst),
......@@ -513,17 +486,17 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
513486 .load => try self.airLoad(inst),
514487 .loop => try self.airLoop(inst),
515488 .not => try self.airNot(inst),
516 .int_from_ptr => try self.airIntFromPtr(inst),
517 .ret => try self.airRet(inst),
518 .ret_safe => try self.airRet(inst), // TODO
489 .int_from_ptr => try self.airIntFromPtr(inst),
490 .ret => try self.airRet(inst, false),
491 .ret_safe => try self.airRet(inst, true),
519492 .ret_load => try self.airRetLoad(inst),
520493 .store => try self.airStore(inst, false),
521494 .store_safe => try self.airStore(inst, true),
522495 .struct_field_ptr=> try self.airStructFieldPtr(inst),
523496 .struct_field_val=> try self.airStructFieldVal(inst),
524497 .array_to_slice => try self.airArrayToSlice(inst),
525 .float_from_int => try self.airFloatFromInt(inst),
526 .int_from_float => try self.airIntFromFloat(inst),
498 .float_from_int => try self.airFloatFromInt(inst),
499 .int_from_float => try self.airIntFromFloat(inst),
527500 .cmpxchg_strong => try self.airCmpxchg(inst),
528501 .cmpxchg_weak => try self.airCmpxchg(inst),
529502 .atomic_rmw => try self.airAtomicRmw(inst),
......@@ -792,6 +765,7 @@ fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCVa
792765
793766fn airAlloc(self: *Self, inst: Air.Inst.Index) !void {
794767 const stack_offset = try self.allocMemPtr(inst);
768 log.debug("airAlloc offset: {}", .{stack_offset});
795769 return self.finishAir(inst, .{ .ptr_stack_offset = stack_offset }, .{ .none, .none, .none });
796770}
797771
......@@ -1468,30 +1442,30 @@ fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_ind
14681442 return true;
14691443}
14701444
1471fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!void {
1445fn load(self: *Self, dst_mcv: MCValue, src_ptr: MCValue, ptr_ty: Type) InnerError!void {
14721446 const mod = self.bin_file.comp.module.?;
14731447 const elem_ty = ptr_ty.childType(mod);
14741448
1475 switch (ptr) {
1449 switch (src_ptr) {
14761450 .none => unreachable,
14771451 .undef => unreachable,
14781452 .unreach => unreachable,
14791453 .dead => unreachable,
1480 .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }),
1481 .ptr_stack_offset => |off| try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }),
1482 .register => |src_reg| try self.setRegOrMem(elem_ty, dst_mcv, .{ .register = src_reg }),
1454 .immediate => |imm| try self.setValue(elem_ty, dst_mcv, .{ .memory = imm }),
1455 .ptr_stack_offset => |off| try self.setValue(elem_ty, dst_mcv, .{ .stack_offset = off }),
1456 .register => try self.setValue(elem_ty, dst_mcv, src_ptr),
14831457 .memory,
14841458 .stack_offset,
14851459 => {
14861460 const reg = try self.register_manager.allocReg(null, gp);
14871461 const reg_lock = self.register_manager.lockRegAssumeUnused(reg);
1488 defer self.register_manager.unlockReg(reg_lock);
1462 errdefer self.register_manager.unlockReg(reg_lock);
14891463
1490 try self.genSetReg(ptr_ty, reg, ptr);
1464 try self.genSetReg(ptr_ty, reg, src_ptr);
14911465 try self.load(dst_mcv, .{ .register = reg }, ptr_ty);
14921466 },
14931467 .load_symbol => {
1494 const reg = try self.copyToTmpRegister(ptr_ty, ptr);
1468 const reg = try self.copyToTmpRegister(ptr_ty, src_ptr);
14951469 try self.load(dst_mcv, .{ .register = reg }, ptr_ty);
14961470 },
14971471 }
......@@ -1524,34 +1498,18 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
15241498 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
15251499}
15261500
1527fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) !void {
1501fn store(self: *Self, dst_ptr: MCValue, src_val: MCValue, ptr_ty: Type, value_ty: Type) !void {
15281502 _ = ptr_ty;
15291503
1530 log.debug("storing {s}", .{@tagName(ptr)});
1504 log.debug("storing {s}", .{@tagName(dst_ptr)});
15311505
1532 switch (ptr) {
1506 switch (dst_ptr) {
15331507 .none => unreachable,
15341508 .undef => unreachable,
15351509 .unreach => unreachable,
15361510 .dead => unreachable,
1537 .immediate => |imm| {
1538 try self.setRegOrMem(value_ty, .{ .memory = imm }, value);
1539 },
1540 .ptr_stack_offset => |off| {
1541 try self.genSetStack(value_ty, off, value);
1542 },
1543 .register => {
1544 return self.fail("TODO implement storing to MCValue.register", .{});
1545 },
1546 .memory => {
1547 return self.fail("TODO implement storing to MCValue.memory", .{});
1548 },
1549 .stack_offset => {
1550 return self.fail("TODO implement storing to MCValue.stack_offset", .{});
1551 },
1552 .load_symbol => {
1553 return self.fail("TODO implement storing to MCValue.load_symbol", .{});
1554 },
1511 .ptr_stack_offset => |off| try self.genSetStack(value_ty, off, src_val),
1512 else => return self.fail("TODO implement storing to MCValue.{s}", .{@tagName(dst_ptr)}),
15551513 }
15561514}
15571515
......@@ -1629,29 +1587,32 @@ fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, mcv: MCValue) !void {
16291587}
16301588
16311589fn airArg(self: *Self, inst: Air.Inst.Index) !void {
1632 const arg_index = self.arg_index;
1633 self.arg_index += 1;
1590 var arg_index = self.arg_index;
16341591
1635 const ty = self.typeOfIndex(inst);
1636 _ = ty;
1592 // we skip over args that have no bits
1593 while (self.args[arg_index] == .none) arg_index += 1;
1594 self.arg_index = arg_index + 1;
16371595
1638 const result = self.args[arg_index];
1639 // TODO support stack-only arguments
1640 // TODO Copy registers to the stack
1641 const mcv = result;
1642 try self.genArgDbgInfo(inst, mcv);
1596 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
1597 const arg_ty = self.typeOfIndex(inst);
1598 _ = arg_ty;
1599 const src_mcv = self.args[arg_index];
16431600
1644 if (self.liveness.isUnused(inst))
1645 return self.finishAirBookkeeping();
1601 const dst_mcv = switch (src_mcv) {
1602 .register => |src_reg| dst: {
1603 self.register_manager.getRegAssumeFree(src_reg, inst);
1604 break :dst src_mcv;
1605 },
1606 // don't need to allocate anything, can just be used immediately.
1607 .stack_offset => src_mcv,
1608 else => return self.fail("TODO: airArg {s}", .{@tagName(src_mcv)}),
1609 };
16461610
1647 switch (mcv) {
1648 .register => |reg| {
1649 self.register_manager.getRegAssumeFree(reg, inst);
1650 },
1651 else => {},
1652 }
1611 try self.genArgDbgInfo(inst, src_mcv);
1612 break :result dst_mcv;
1613 };
16531614
1654 return self.finishAir(inst, mcv, .{ .none, .none, .none });
1615 return self.finishAir(inst, result, .{ .none, .none, .none });
16551616}
16561617
16571618fn airTrap(self: *Self) !void {
......@@ -1704,26 +1665,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
17041665 const arg = args[arg_i];
17051666 const arg_ty = self.typeOf(arg);
17061667 const arg_mcv = try self.resolveInst(args[arg_i]);
1707
1708 switch (mc_arg) {
1709 .none => continue,
1710 .undef => unreachable,
1711 .immediate => unreachable,
1712 .unreach => unreachable,
1713 .dead => unreachable,
1714 .memory => unreachable,
1715 .register => |reg| {
1716 try self.register_manager.getReg(reg, null);
1717 try self.genSetReg(arg_ty, reg, arg_mcv);
1718 },
1719 .stack_offset => |off| try self.genSetStack(arg_ty, off, arg_mcv),
1720 .ptr_stack_offset => {
1721 return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{});
1722 },
1723 .load_symbol => {
1724 return self.fail("TODO implement calling with MCValue.load_symbol", .{});
1725 },
1726 }
1668 try self.setValue(arg_ty, mc_arg, arg_mcv);
17271669 }
17281670
17291671 if (try self.air.value(callee, mod)) |func_value| {
......@@ -1791,19 +1733,39 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
17911733fn ret(self: *Self, mcv: MCValue) !void {
17921734 const mod = self.bin_file.comp.module.?;
17931735 const ret_ty = self.fn_type.fnReturnType(mod);
1794 try self.setRegOrMem(ret_ty, self.ret_mcv, mcv);
1736 try self.setValue(ret_ty, self.ret_mcv, mcv);
1737
17951738 // Just add space for an instruction, patch this later
17961739 const index = try self.addInst(.{
1797 .tag = .nop,
1740 .tag = .ret,
17981741 .data = .{ .nop = {} },
17991742 });
1743
18001744 try self.exitlude_jump_relocs.append(self.gpa, index);
18011745}
18021746
1803fn airRet(self: *Self, inst: Air.Inst.Index) !void {
1747fn airRet(self: *Self, inst: Air.Inst.Index, safety: bool) !void {
1748 if (safety) {
1749 // safe
1750 } else {
1751 // not safe
1752 }
1753
18041754 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
18051755 const operand = try self.resolveInst(un_op);
1756
1757 _ = try self.addInst(.{
1758 .tag = .dbg_epilogue_begin,
1759 .data = .{ .nop = {} },
1760 });
1761
1762 _ = try self.addInst(.{
1763 .tag = .psuedo_epilogue,
1764 .data = .{ .nop = {} },
1765 });
1766
18061767 try self.ret(operand);
1768
18071769 return self.finishAir(inst, .dead, .{ un_op, .none, .none });
18081770}
18091771
......@@ -1983,7 +1945,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
19831945 log.debug("consolidating else_entry {d} {}=>{}", .{ else_key, else_value, canon_mcv });
19841946 // TODO make sure the destination stack offset / register does not already have something
19851947 // going on there.
1986 try self.setRegOrMem(self.typeOfIndex(else_key), canon_mcv, else_value);
1948 try self.setValue(self.typeOfIndex(else_key), canon_mcv, else_value);
19871949 // TODO track the new register / stack allocation
19881950 }
19891951 try parent_branch.inst_table.ensureUnusedCapacity(self.gpa, saved_then_branch.inst_table.count());
......@@ -2010,7 +1972,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
20101972 log.debug("consolidating then_entry {d} {}=>{}", .{ then_key, parent_mcv, then_value });
20111973 // TODO make sure the destination stack offset / register does not already have something
20121974 // going on there.
2013 try self.setRegOrMem(self.typeOfIndex(then_key), parent_mcv, then_value);
1975 try self.setValue(self.typeOfIndex(then_key), parent_mcv, then_value);
20141976 // TODO track the new register / stack allocation
20151977 }
20161978
......@@ -2195,7 +2157,7 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {
21952157/// Send control flow to the `index` of `self.code`.
21962158fn jump(self: *Self, index: Mir.Inst.Index) !void {
21972159 _ = try self.addInst(.{
2198 .tag = .psuedo_jump,
2160 .tag = .j,
21992161 .data = .{
22002162 .inst = index,
22012163 },
......@@ -2270,7 +2232,7 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
22702232 if (block_mcv == .none) {
22712233 block_data.mcv = operand_mcv;
22722234 } else {
2273 try self.setRegOrMem(self.typeOfIndex(block), block_mcv, operand_mcv);
2235 try self.setValue(self.typeOfIndex(block), block_mcv, operand_mcv);
22742236 }
22752237 }
22762238 return self.brVoid(block);
......@@ -2415,28 +2377,32 @@ fn iterateBigTomb(self: *Self, inst: Air.Inst.Index, operand_count: usize) !BigT
24152377}
24162378
24172379/// Sets the value without any modifications to register allocation metadata or stack allocation metadata.
2418fn setRegOrMem(self: *Self, ty: Type, loc: MCValue, val: MCValue) !void {
2419 if (!loc.isMutable()) {
2420 return std.debug.panic("tried to setRegOrMem immutable: {s}", .{@tagName(loc)});
2380fn setValue(self: *Self, ty: Type, dst_val: MCValue, src_val: MCValue) !void {
2381 // There isn't anything to store
2382 if (dst_val == .none) return;
2383
2384 if (!dst_val.isMutable()) {
2385 return std.debug.panic("tried to setValue immutable: {s}", .{@tagName(dst_val)});
24212386 }
24222387
2423 switch (loc) {
2424 .none => return,
2425 .register => |reg| return self.genSetReg(ty, reg, val),
2426 .stack_offset => |off| return self.genSetStack(ty, off, val),
2427 else => return self.fail("TODO: setRegOrMem {s}", .{@tagName(loc)}),
2388 switch (dst_val) {
2389 .register => |reg| return self.genSetReg(ty, reg, src_val),
2390 .stack_offset => |off| return self.genSetStack(ty, off, src_val),
2391 .memory => |addr| return self.genSetMem(ty, addr, src_val),
2392 else => return self.fail("TODO: setValue {s}", .{@tagName(dst_val)}),
24282393 }
24292394}
24302395
2431fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerError!void {
2396/// Sets the value of `src_val` into stack memory at `stack_offset`.
2397fn genSetStack(self: *Self, ty: Type, stack_offset: u32, src_val: MCValue) InnerError!void {
24322398 const mod = self.bin_file.comp.module.?;
24332399 const abi_size: u32 = @intCast(ty.abiSize(mod));
24342400
2435 switch (mcv) {
2401 switch (src_val) {
24362402 .none => return,
24372403 .dead => unreachable,
24382404 .immediate => {
2439 const reg = try self.copyToTmpRegister(ty, mcv);
2405 const reg = try self.copyToTmpRegister(ty, src_val);
24402406 return self.genSetStack(ty, stack_offset, .{ .register = reg });
24412407 },
24422408 .register => |reg| {
......@@ -2456,8 +2422,10 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
24562422 .tag = tag,
24572423 .data = .{ .i_type = .{
24582424 .rd = reg,
2459 .rs1 = .sp,
2460 .imm12 = @intCast(stack_offset),
2425 .rs1 = .s0,
2426 .imm12 = math.cast(i12, stack_offset) orelse {
2427 return self.fail("TODO: genSetStack bigger stack values", .{});
2428 },
24612429 } },
24622430 });
24632431 },
......@@ -2466,7 +2434,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
24662434 },
24672435 .stack_offset, .load_symbol => {
24682436 if (abi_size <= 8) {
2469 const reg = try self.copyToTmpRegister(ty, mcv);
2437 const reg = try self.copyToTmpRegister(ty, src_val);
24702438 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
24712439 }
24722440
......@@ -2485,7 +2453,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
24852453 const count_reg = regs[3];
24862454 const tmp_reg = regs[4];
24872455
2488 switch (mcv) {
2456 switch (src_val) {
24892457 .stack_offset => |offset| {
24902458 if (offset == stack_offset) return;
24912459 try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = offset });
......@@ -2511,7 +2479,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
25112479 },
25122480 });
25132481 },
2514 else => return self.fail("TODO: genSetStack unreachable {s}", .{@tagName(mcv)}),
2482 else => return self.fail("TODO: genSetStack unreachable {s}", .{@tagName(src_val)}),
25152483 }
25162484
25172485 try self.genSetReg(ptr_ty, dst_reg, .{ .ptr_stack_offset = stack_offset });
......@@ -2520,10 +2488,20 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
25202488 // memcpy(src, dst, len)
25212489 try self.genInlineMemcpy(src_reg, dst_reg, len_reg, count_reg, tmp_reg);
25222490 },
2523 else => return self.fail("TODO: genSetStack {s}", .{@tagName(mcv)}),
2491 else => return self.fail("TODO: genSetStack {s}", .{@tagName(src_val)}),
25242492 }
25252493}
25262494
2495fn genSetMem(self: *Self, ty: Type, addr: u64, src_val: MCValue) InnerError!void {
2496 const mod = self.bin_file.comp.module.?;
2497 const abi_size: u32 = @intCast(ty.abiSize(mod));
2498 _ = abi_size;
2499 _ = addr;
2500 _ = src_val;
2501
2502 return self.fail("TODO: genSetMem", .{});
2503}
2504
25272505fn genInlineMemcpy(
25282506 self: *Self,
25292507 src: Register,
......@@ -2541,11 +2519,12 @@ fn genInlineMemcpy(
25412519 return self.fail("TODO: genInlineMemcpy", .{});
25422520}
25432521
2544fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {
2522/// Sets the value of `src_val` into `reg`. Assumes you have a lock on it.
2523fn genSetReg(self: *Self, ty: Type, reg: Register, src_val: MCValue) InnerError!void {
25452524 const mod = self.bin_file.comp.module.?;
25462525 const abi_size: u32 = @intCast(ty.abiSize(mod));
25472526
2548 switch (mcv) {
2527 switch (src_val) {
25492528 .dead => unreachable,
25502529 .ptr_stack_offset => return self.fail("TODO genSetReg ptr_stack_offset", .{}),
25512530 .unreach, .none => return, // Nothing to do.
......@@ -2634,8 +2613,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
26342613 .tag = tag,
26352614 .data = .{ .i_type = .{
26362615 .rd = reg,
2637 .rs1 = .sp,
2638 .imm12 = @intCast(off),
2616 .rs1 = .s0,
2617 .imm12 = math.cast(i12, off) orelse {
2618 return self.fail("TODO: genSetReg support larger stack sizes", .{});
2619 },
26392620 } },
26402621 });
26412622 },
......@@ -2685,7 +2666,7 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {
26852666 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
26862667
26872668 const dest = try self.allocRegOrMem(inst, true);
2688 try self.setRegOrMem(self.typeOfIndex(inst), dest, operand);
2669 try self.setValue(self.typeOfIndex(inst), dest, operand);
26892670 break :result dest;
26902671 };
26912672 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
......@@ -2912,7 +2893,6 @@ const CallMCValues = struct {
29122893/// Caller must call `CallMCValues.deinit`.
29132894fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
29142895 const mod = self.bin_file.comp.module.?;
2915 const ip = &mod.intern_pool;
29162896 const fn_info = mod.typeToFunc(fn_ty).?;
29172897 const cc = fn_info.cc;
29182898 var result: CallMCValues = .{
......@@ -2935,21 +2915,20 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
29352915 return result;
29362916 },
29372917 .Unspecified, .C => {
2938 // LP64D ABI
2939 //
2940 // TODO make this generic with other ABIs, in particular
2941 // with different hardware floating-point calling
2942 // conventions
2943 var stack_offset: u32 = 0;
2944
2945 for (fn_info.param_types.get(ip), result.args) |ty, *result_arg| {
2946 const param_type = Type.fromInterned(ty);
2947 const param_size: u32 = @intCast(param_type.abiSize(mod));
2918 if (result.args.len > 8) {
2919 return self.fail("TODO: support more than 8 function args", .{});
2920 }
29482921
2949 result_arg.* = .{ .stack_offset = stack_offset };
2950 stack_offset += param_size;
2922 for (0..result.args.len) |i| {
2923 const arg_reg = try self.register_manager.allocReg(null, fa);
2924 result.args[i] = .{ .register = arg_reg };
29512925 }
29522926
2927 // stack_offset = num s registers spilled + local var space
2928 var stack_offset: u32 = 0;
2929 _ = &stack_offset;
2930 // TODO: spill used s registers here
2931
29532932 result.stack_byte_count = stack_offset;
29542933 result.stack_align = .@"16";
29552934 },
src/arch/riscv64/Emit.zig+69-27
......@@ -27,6 +27,8 @@ prev_di_column: u32,
2727/// Relative to the beginning of `code`.
2828prev_di_pc: usize,
2929
30stack_size: u32,
31
3032const log = std.log.scoped(.emit);
3133
3234const InnerError = error{
......@@ -39,10 +41,8 @@ pub fn emitMir(
3941) InnerError!void {
4042 const mir_tags = emit.mir.instructions.items(.tag);
4143
42 // TODO: compute branch offsets
43 // try emit.lowerMir();
44 try emit.lowerMir();
4445
45 // Emit machine code
4646 for (mir_tags, 0..) |tag, index| {
4747 const inst = @as(u32, @intCast(index));
4848 log.debug("emitMir: {s}", .{@tagName(tag)});
......@@ -70,7 +70,9 @@ pub fn emitMir(
7070 .dbg_epilogue_begin => try emit.mirDebugEpilogueBegin(),
7171
7272 .psuedo_prologue => try emit.mirPsuedo(inst),
73 .psuedo_jump => try emit.mirPsuedo(inst),
73 .psuedo_epilogue => try emit.mirPsuedo(inst),
74
75 .j => try emit.mirPsuedo(inst),
7476
7577 .mv => try emit.mirRR(inst),
7678
......@@ -80,13 +82,15 @@ pub fn emitMir(
8082 .lui => try emit.mirUType(inst),
8183
8284 .ld => try emit.mirIType(inst),
83 .sd => try emit.mirIType(inst),
8485 .lw => try emit.mirIType(inst),
85 .sw => try emit.mirIType(inst),
8686 .lh => try emit.mirIType(inst),
87 .sh => try emit.mirIType(inst),
8887 .lb => try emit.mirIType(inst),
88
89 .sd => try emit.mirIType(inst),
90 .sw => try emit.mirIType(inst),
91 .sh => try emit.mirIType(inst),
8992 .sb => try emit.mirIType(inst),
93
9094 .ldr_ptr_stack => try emit.mirIType(inst),
9195
9296 .load_symbol => try emit.mirLoadSymbol(inst),
......@@ -170,8 +174,6 @@ fn mirBType(emit: *Emit, inst: Mir.Inst.Index) !void {
170174 const tag = emit.mir.instructions.items(.tag)[inst];
171175 const b_type = emit.mir.instructions.items(.data)[inst].b_type;
172176
173 // const inst = b_type.imm12;
174
175177 switch (tag) {
176178 .beq => try emit.writeInstruction(Instruction.beq(b_type.rs1, b_type.rs2, b_type.imm12)),
177179 else => unreachable,
......@@ -187,12 +189,13 @@ fn mirIType(emit: *Emit, inst: Mir.Inst.Index) !void {
187189 .jalr => try emit.writeInstruction(Instruction.jalr(i_type.rd, i_type.imm12, i_type.rs1)),
188190
189191 .ld => try emit.writeInstruction(Instruction.ld(i_type.rd, i_type.imm12, i_type.rs1)),
190 .sd => try emit.writeInstruction(Instruction.sd(i_type.rd, i_type.imm12, i_type.rs1)),
191192 .lw => try emit.writeInstruction(Instruction.lw(i_type.rd, i_type.imm12, i_type.rs1)),
192 .sw => try emit.writeInstruction(Instruction.sw(i_type.rd, i_type.imm12, i_type.rs1)),
193193 .lh => try emit.writeInstruction(Instruction.lh(i_type.rd, i_type.imm12, i_type.rs1)),
194 .sh => try emit.writeInstruction(Instruction.sh(i_type.rd, i_type.imm12, i_type.rs1)),
195194 .lb => try emit.writeInstruction(Instruction.lb(i_type.rd, i_type.imm12, i_type.rs1)),
195
196 .sd => try emit.writeInstruction(Instruction.sd(i_type.rd, i_type.imm12, i_type.rs1)),
197 .sw => try emit.writeInstruction(Instruction.sw(i_type.rd, i_type.imm12, i_type.rs1)),
198 .sh => try emit.writeInstruction(Instruction.sh(i_type.rd, i_type.imm12, i_type.rs1)),
196199 .sb => try emit.writeInstruction(Instruction.sb(i_type.rd, i_type.imm12, i_type.rs1)),
197200
198201 .ldr_ptr_stack => try emit.writeInstruction(Instruction.add(i_type.rd, i_type.rs1, .sp)),
......@@ -262,21 +265,44 @@ fn mirPsuedo(emit: *Emit, inst: Mir.Inst.Index) !void {
262265
263266 switch (tag) {
264267 .psuedo_prologue => {
265 const imm12 = data.imm12;
266 const stack_size: i12 = @max(32, imm12);
268 const stack_size: i12 = math.cast(i12, emit.stack_size) orelse {
269 return emit.fail("TODO: mirPsuedo support larger stack sizes", .{});
270 };
267271
272 // Decrement sp by num s registers + local var space
268273 try emit.writeInstruction(Instruction.addi(.sp, .sp, -stack_size));
274
275 // Spill ra
269276 try emit.writeInstruction(Instruction.sd(.ra, stack_size - 8, .sp));
277
278 // Spill s0
270279 try emit.writeInstruction(Instruction.sd(.s0, stack_size - 16, .sp));
280
281 // Setup s0
271282 try emit.writeInstruction(Instruction.addi(.s0, .sp, stack_size));
272283 },
284 .psuedo_epilogue => {
285 const stack_size: i12 = math.cast(i12, emit.stack_size) orelse {
286 return emit.fail("TODO: mirPsuedo support larger stack sizes", .{});
287 };
288
289 // Restore ra
290 try emit.writeInstruction(Instruction.ld(.ra, stack_size - 16, .sp));
273291
274 .psuedo_jump => {
292 // Restore s0
293 try emit.writeInstruction(Instruction.ld(.s0, stack_size - 16, .sp));
294
295 // Increment sp back to previous value
296 try emit.writeInstruction(Instruction.addi(.sp, .sp, stack_size));
297 },
298
299 .j => {
275300 const target = data.inst;
276301 const offset: i12 = @intCast(emit.code.items.len);
277302 _ = target;
278303
279304 try emit.writeInstruction(Instruction.jal(.s0, offset));
305 unreachable; // TODO: mirPsuedo j
280306 },
281307
282308 else => unreachable,
......@@ -348,27 +374,43 @@ fn mirLoadSymbol(emit: *Emit, inst: Mir.Inst.Index) !void {
348374 }
349375}
350376
351fn isBranch(tag: Mir.Inst.Tag) bool {
352 switch (tag) {
353 .psuedo_jump => true,
377fn isStore(tag: Mir.Inst.Tag) bool {
378 return switch (tag) {
379 .sb => true,
380 .sh => true,
381 .sw => true,
382 .sd => true,
354383 else => false,
355 }
384 };
385}
386
387fn isLoad(tag: Mir.Inst.Tag) bool {
388 return switch (tag) {
389 .lb => true,
390 .lh => true,
391 .lw => true,
392 .ld => true,
393 else => false,
394 };
356395}
357396
358397fn lowerMir(emit: *Emit) !void {
359 const comp = emit.bin_file.comp;
360 const gpa = comp.gpa;
361398 const mir_tags = emit.mir.instructions.items(.tag);
362
363 _ = gpa;
399 const mir_datas = emit.mir.instructions.items(.data);
364400
365401 for (mir_tags, 0..) |tag, index| {
366402 const inst: u32 = @intCast(index);
367403
368 if (isBranch(tag)) {
369 const target_inst = emit.mir.instructions.items(.data)[inst].inst;
370
371 _ = target_inst;
404 if (isStore(tag) or isLoad(tag)) {
405 const data = mir_datas[inst].i_type;
406 // TODO: probably create a psuedo instruction for s0 loads/stores instead of this.
407 if (data.rs1 == .s0) {
408 const casted_size = math.cast(i12, emit.stack_size) orelse {
409 return emit.fail("TODO: support bigger stack sizes lowerMir", .{});
410 };
411 const offset = mir_datas[inst].i_type.imm12;
412 mir_datas[inst].i_type.imm12 = -(casted_size - 12 - offset);
413 }
372414 }
373415 }
374416}
src/arch/riscv64/Mir.zig+5-2
......@@ -39,6 +39,8 @@ pub const Inst = struct {
3939 sub,
4040
4141 jal,
42 /// Jumps. Uses `inst` payload.
43 j,
4244
4345 // TODO: Maybe create a special data for compares that includes the ops
4446 /// Compare equal, uses r_type
......@@ -81,8 +83,9 @@ pub const Inst = struct {
8183 /// Psuedo-instruction that will generate a backpatched
8284 /// function prologue.
8385 psuedo_prologue,
84 /// Jumps. Uses `inst` payload.
85 psuedo_jump,
86 /// Psuedo-instruction that will generate a backpatched
87 /// function epilogue
88 psuedo_epilogue,
8689
8790 // TODO: add description
8891 load_symbol,
src/arch/riscv64/abi.zig+16-2
......@@ -92,10 +92,15 @@ pub fn classifyType(ty: Type, mod: *Module) Class {
9292}
9393
9494pub const callee_preserved_regs = [_]Register{
95 .s0, .s1, .s2, .s3, .s4, .s5, .s6, .s7, .s8, .s9, .s10, .s11,
95 // NOTE: we use s0 as a psuedo stack pointer, so it's not included.
96 .s1, .s2, .s3, .s4, .s5, .s6, .s7, .s8, .s9, .s10, .s11,
9697};
9798
98const allocatable_registers = callee_preserved_regs;
99pub const function_arg_regs = [_]Register{
100 .a0, .a1, .a2, .a3, .a4, .a5, .a6, .a7,
101};
102
103const allocatable_registers = callee_preserved_regs ++ function_arg_regs;
99104pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_registers);
100105
101106// Register classes
......@@ -109,4 +114,13 @@ pub const RegisterClass = struct {
109114 }, true);
110115 break :blk set;
111116 };
117
118 pub const fa: RegisterBitSet = blk: {
119 var set = RegisterBitSet.initEmpty();
120 set.setRangeValue(.{
121 .start = callee_preserved_regs.len,
122 .end = callee_preserved_regs.len + function_arg_regs.len,
123 }, true);
124 break :blk set;
125 };
112126};