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;...@@ -34,7 +34,10 @@ const Register = bits.Register;
34const RegisterManager = abi.RegisterManager;34const RegisterManager = abi.RegisterManager;
35const RegisterLock = RegisterManager.RegisterLock;35const RegisterLock = RegisterManager.RegisterLock;
36const callee_preserved_regs = abi.callee_preserved_regs;36const callee_preserved_regs = abi.callee_preserved_regs;
37/// General Purpose
37const gp = abi.RegisterClass.gp;38const gp = abi.RegisterClass.gp;
39/// Function Args
40const fa = abi.RegisterClass.fa;
3841
39const InnerError = CodeGenError || error{OutOfRegisters};42const InnerError = CodeGenError || error{OutOfRegisters};
4043
...@@ -297,6 +300,7 @@ pub fn generate(...@@ -297,6 +300,7 @@ pub fn generate(
297 .prev_di_pc = 0,300 .prev_di_pc = 0,
298 .prev_di_line = func.lbrace_line,301 .prev_di_line = func.lbrace_line,
299 .prev_di_column = func.lbrace_column,302 .prev_di_column = func.lbrace_column,
303 .stack_size = @max(32, function.max_end_stack),
300 };304 };
301 defer emit.deinit();305 defer emit.deinit();
302306
...@@ -349,14 +353,9 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 {...@@ -349,14 +353,9 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 {
349}353}
350354
351fn gen(self: *Self) !void {355fn 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
357 _ = try self.addInst(.{356 _ = try self.addInst(.{
358 .tag = .psuedo_prologue,357 .tag = .psuedo_prologue,
359 .data = .{ .imm12 = 0 }, // Backpatched later.358 .data = .{ .nop = {} }, // Backpatched later.
360 });359 });
361360
362 _ = try self.addInst(.{361 _ = try self.addInst(.{
...@@ -366,32 +365,6 @@ fn gen(self: *Self) !void {...@@ -366,32 +365,6 @@ fn gen(self: *Self) !void {
366365
367 try self.genBody(self.air.getMainBody());366 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
395 // Drop them off at the rbrace.368 // Drop them off at the rbrace.
396 _ = try self.addInst(.{369 _ = try self.addInst(.{
397 .tag = .dbg_line,370 .tag = .dbg_line,
...@@ -501,7 +474,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -501,7 +474,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
501 .fpext => try self.airFpext(inst),474 .fpext => try self.airFpext(inst),
502 .intcast => try self.airIntCast(inst),475 .intcast => try self.airIntCast(inst),
503 .trunc => try self.airTrunc(inst),476 .trunc => try self.airTrunc(inst),
504 .int_from_bool => try self.airIntFromBool(inst),477 .int_from_bool => try self.airIntFromBool(inst),
505 .is_non_null => try self.airIsNonNull(inst),478 .is_non_null => try self.airIsNonNull(inst),
506 .is_non_null_ptr => try self.airIsNonNullPtr(inst),479 .is_non_null_ptr => try self.airIsNonNullPtr(inst),
507 .is_null => try self.airIsNull(inst),480 .is_null => try self.airIsNull(inst),
...@@ -513,17 +486,17 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -513,17 +486,17 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
513 .load => try self.airLoad(inst),486 .load => try self.airLoad(inst),
514 .loop => try self.airLoop(inst),487 .loop => try self.airLoop(inst),
515 .not => try self.airNot(inst),488 .not => try self.airNot(inst),
516 .int_from_ptr => try self.airIntFromPtr(inst),489 .int_from_ptr => try self.airIntFromPtr(inst),
517 .ret => try self.airRet(inst),490 .ret => try self.airRet(inst, false),
518 .ret_safe => try self.airRet(inst), // TODO491 .ret_safe => try self.airRet(inst, true),
519 .ret_load => try self.airRetLoad(inst),492 .ret_load => try self.airRetLoad(inst),
520 .store => try self.airStore(inst, false),493 .store => try self.airStore(inst, false),
521 .store_safe => try self.airStore(inst, true),494 .store_safe => try self.airStore(inst, true),
522 .struct_field_ptr=> try self.airStructFieldPtr(inst),495 .struct_field_ptr=> try self.airStructFieldPtr(inst),
523 .struct_field_val=> try self.airStructFieldVal(inst),496 .struct_field_val=> try self.airStructFieldVal(inst),
524 .array_to_slice => try self.airArrayToSlice(inst),497 .array_to_slice => try self.airArrayToSlice(inst),
525 .float_from_int => try self.airFloatFromInt(inst),498 .float_from_int => try self.airFloatFromInt(inst),
526 .int_from_float => try self.airIntFromFloat(inst),499 .int_from_float => try self.airIntFromFloat(inst),
527 .cmpxchg_strong => try self.airCmpxchg(inst),500 .cmpxchg_strong => try self.airCmpxchg(inst),
528 .cmpxchg_weak => try self.airCmpxchg(inst),501 .cmpxchg_weak => try self.airCmpxchg(inst),
529 .atomic_rmw => try self.airAtomicRmw(inst),502 .atomic_rmw => try self.airAtomicRmw(inst),
...@@ -792,6 +765,7 @@ fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCVa...@@ -792,6 +765,7 @@ fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCVa
792765
793fn airAlloc(self: *Self, inst: Air.Inst.Index) !void {766fn airAlloc(self: *Self, inst: Air.Inst.Index) !void {
794 const stack_offset = try self.allocMemPtr(inst);767 const stack_offset = try self.allocMemPtr(inst);
768 log.debug("airAlloc offset: {}", .{stack_offset});
795 return self.finishAir(inst, .{ .ptr_stack_offset = stack_offset }, .{ .none, .none, .none });769 return self.finishAir(inst, .{ .ptr_stack_offset = stack_offset }, .{ .none, .none, .none });
796}770}
797771
...@@ -1468,30 +1442,30 @@ fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_ind...@@ -1468,30 +1442,30 @@ fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_ind
1468 return true;1442 return true;
1469}1443}
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 {
1472 const mod = self.bin_file.comp.module.?;1446 const mod = self.bin_file.comp.module.?;
1473 const elem_ty = ptr_ty.childType(mod);1447 const elem_ty = ptr_ty.childType(mod);
14741448
1475 switch (ptr) {1449 switch (src_ptr) {
1476 .none => unreachable,1450 .none => unreachable,
1477 .undef => unreachable,1451 .undef => unreachable,
1478 .unreach => unreachable,1452 .unreach => unreachable,
1479 .dead => unreachable,1453 .dead => unreachable,
1480 .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }),1454 .immediate => |imm| try self.setValue(elem_ty, dst_mcv, .{ .memory = imm }),
1481 .ptr_stack_offset => |off| try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }),1455 .ptr_stack_offset => |off| try self.setValue(elem_ty, dst_mcv, .{ .stack_offset = off }),
1482 .register => |src_reg| try self.setRegOrMem(elem_ty, dst_mcv, .{ .register = src_reg }),1456 .register => try self.setValue(elem_ty, dst_mcv, src_ptr),
1483 .memory,1457 .memory,
1484 .stack_offset,1458 .stack_offset,
1485 => {1459 => {
1486 const reg = try self.register_manager.allocReg(null, gp);1460 const reg = try self.register_manager.allocReg(null, gp);
1487 const reg_lock = self.register_manager.lockRegAssumeUnused(reg);1461 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);
1491 try self.load(dst_mcv, .{ .register = reg }, ptr_ty);1465 try self.load(dst_mcv, .{ .register = reg }, ptr_ty);
1492 },1466 },
1493 .load_symbol => {1467 .load_symbol => {
1494 const reg = try self.copyToTmpRegister(ptr_ty, ptr);1468 const reg = try self.copyToTmpRegister(ptr_ty, src_ptr);
1495 try self.load(dst_mcv, .{ .register = reg }, ptr_ty);1469 try self.load(dst_mcv, .{ .register = reg }, ptr_ty);
1496 },1470 },
1497 }1471 }
...@@ -1524,34 +1498,18 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -1524,34 +1498,18 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
1524 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1498 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1525}1499}
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 {
1528 _ = ptr_ty;1502 _ = 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) {
1533 .none => unreachable,1507 .none => unreachable,
1534 .undef => unreachable,1508 .undef => unreachable,
1535 .unreach => unreachable,1509 .unreach => unreachable,
1536 .dead => unreachable,1510 .dead => unreachable,
1537 .immediate => |imm| {1511 .ptr_stack_offset => |off| try self.genSetStack(value_ty, off, src_val),
1538 try self.setRegOrMem(value_ty, .{ .memory = imm }, value);1512 else => return self.fail("TODO implement storing to MCValue.{s}", .{@tagName(dst_ptr)}),
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 },
1555 }1513 }
1556}1514}
15571515
...@@ -1629,29 +1587,32 @@ fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, mcv: MCValue) !void {...@@ -1629,29 +1587,32 @@ fn genArgDbgInfo(self: Self, inst: Air.Inst.Index, mcv: MCValue) !void {
1629}1587}
16301588
1631fn airArg(self: *Self, inst: Air.Inst.Index) !void {1589fn airArg(self: *Self, inst: Air.Inst.Index) !void {
1632 const arg_index = self.arg_index;1590 var arg_index = self.arg_index;
1633 self.arg_index += 1;
16341591
1635 const ty = self.typeOfIndex(inst);1592 // we skip over args that have no bits
1636 _ = ty;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];1596 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
1639 // TODO support stack-only arguments1597 const arg_ty = self.typeOfIndex(inst);
1640 // TODO Copy registers to the stack1598 _ = arg_ty;
1641 const mcv = result;1599 const src_mcv = self.args[arg_index];
1642 try self.genArgDbgInfo(inst, mcv);
16431600
1644 if (self.liveness.isUnused(inst))1601 const dst_mcv = switch (src_mcv) {
1645 return self.finishAirBookkeeping();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) {1611 try self.genArgDbgInfo(inst, src_mcv);
1648 .register => |reg| {1612 break :result dst_mcv;
1649 self.register_manager.getRegAssumeFree(reg, inst);1613 };
1650 },
1651 else => {},
1652 }
16531614
1654 return self.finishAir(inst, mcv, .{ .none, .none, .none });1615 return self.finishAir(inst, result, .{ .none, .none, .none });
1655}1616}
16561617
1657fn airTrap(self: *Self) !void {1618fn airTrap(self: *Self) !void {
...@@ -1704,26 +1665,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -1704,26 +1665,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
1704 const arg = args[arg_i];1665 const arg = args[arg_i];
1705 const arg_ty = self.typeOf(arg);1666 const arg_ty = self.typeOf(arg);
1706 const arg_mcv = try self.resolveInst(args[arg_i]);1667 const arg_mcv = try self.resolveInst(args[arg_i]);
17071668 try self.setValue(arg_ty, mc_arg, arg_mcv);
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 }
1727 }1669 }
17281670
1729 if (try self.air.value(callee, mod)) |func_value| {1671 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...@@ -1791,19 +1733,39 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
1791fn ret(self: *Self, mcv: MCValue) !void {1733fn ret(self: *Self, mcv: MCValue) !void {
1792 const mod = self.bin_file.comp.module.?;1734 const mod = self.bin_file.comp.module.?;
1793 const ret_ty = self.fn_type.fnReturnType(mod);1735 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
1795 // Just add space for an instruction, patch this later1738 // Just add space for an instruction, patch this later
1796 const index = try self.addInst(.{1739 const index = try self.addInst(.{
1797 .tag = .nop,1740 .tag = .ret,
1798 .data = .{ .nop = {} },1741 .data = .{ .nop = {} },
1799 });1742 });
1743
1800 try self.exitlude_jump_relocs.append(self.gpa, index);1744 try self.exitlude_jump_relocs.append(self.gpa, index);
1801}1745}
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
1804 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;1754 const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
1805 const operand = try self.resolveInst(un_op);1755 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
1806 try self.ret(operand);1767 try self.ret(operand);
1768
1807 return self.finishAir(inst, .dead, .{ un_op, .none, .none });1769 return self.finishAir(inst, .dead, .{ un_op, .none, .none });
1808}1770}
18091771
...@@ -1983,7 +1945,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1983,7 +1945,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
1983 log.debug("consolidating else_entry {d} {}=>{}", .{ else_key, else_value, canon_mcv });1945 log.debug("consolidating else_entry {d} {}=>{}", .{ else_key, else_value, canon_mcv });
1984 // TODO make sure the destination stack offset / register does not already have something1946 // TODO make sure the destination stack offset / register does not already have something
1985 // going on there.1947 // 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);
1987 // TODO track the new register / stack allocation1949 // TODO track the new register / stack allocation
1988 }1950 }
1989 try parent_branch.inst_table.ensureUnusedCapacity(self.gpa, saved_then_branch.inst_table.count());1951 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 {...@@ -2010,7 +1972,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
2010 log.debug("consolidating then_entry {d} {}=>{}", .{ then_key, parent_mcv, then_value });1972 log.debug("consolidating then_entry {d} {}=>{}", .{ then_key, parent_mcv, then_value });
2011 // TODO make sure the destination stack offset / register does not already have something1973 // TODO make sure the destination stack offset / register does not already have something
2012 // going on there.1974 // 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);
2014 // TODO track the new register / stack allocation1976 // TODO track the new register / stack allocation
2015 }1977 }
20161978
...@@ -2195,7 +2157,7 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {...@@ -2195,7 +2157,7 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) !void {
2195/// Send control flow to the `index` of `self.code`.2157/// Send control flow to the `index` of `self.code`.
2196fn jump(self: *Self, index: Mir.Inst.Index) !void {2158fn jump(self: *Self, index: Mir.Inst.Index) !void {
2197 _ = try self.addInst(.{2159 _ = try self.addInst(.{
2198 .tag = .psuedo_jump,2160 .tag = .j,
2199 .data = .{2161 .data = .{
2200 .inst = index,2162 .inst = index,
2201 },2163 },
...@@ -2270,7 +2232,7 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {...@@ -2270,7 +2232,7 @@ fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
2270 if (block_mcv == .none) {2232 if (block_mcv == .none) {
2271 block_data.mcv = operand_mcv;2233 block_data.mcv = operand_mcv;
2272 } else {2234 } else {
2273 try self.setRegOrMem(self.typeOfIndex(block), block_mcv, operand_mcv);2235 try self.setValue(self.typeOfIndex(block), block_mcv, operand_mcv);
2274 }2236 }
2275 }2237 }
2276 return self.brVoid(block);2238 return self.brVoid(block);
...@@ -2415,28 +2377,32 @@ fn iterateBigTomb(self: *Self, inst: Air.Inst.Index, operand_count: usize) !BigT...@@ -2415,28 +2377,32 @@ fn iterateBigTomb(self: *Self, inst: Air.Inst.Index, operand_count: usize) !BigT
2415}2377}
24162378
2417/// Sets the value without any modifications to register allocation metadata or stack allocation metadata.2379/// 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 {2380fn setValue(self: *Self, ty: Type, dst_val: MCValue, src_val: MCValue) !void {
2419 if (!loc.isMutable()) {2381 // There isn't anything to store
2420 return std.debug.panic("tried to setRegOrMem immutable: {s}", .{@tagName(loc)});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)});
2421 }2386 }
24222387
2423 switch (loc) {2388 switch (dst_val) {
2424 .none => return,2389 .register => |reg| return self.genSetReg(ty, reg, src_val),
2425 .register => |reg| return self.genSetReg(ty, reg, val),2390 .stack_offset => |off| return self.genSetStack(ty, off, src_val),
2426 .stack_offset => |off| return self.genSetStack(ty, off, val),2391 .memory => |addr| return self.genSetMem(ty, addr, src_val),
2427 else => return self.fail("TODO: setRegOrMem {s}", .{@tagName(loc)}),2392 else => return self.fail("TODO: setValue {s}", .{@tagName(dst_val)}),
2428 }2393 }
2429}2394}
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 {
2432 const mod = self.bin_file.comp.module.?;2398 const mod = self.bin_file.comp.module.?;
2433 const abi_size: u32 = @intCast(ty.abiSize(mod));2399 const abi_size: u32 = @intCast(ty.abiSize(mod));
24342400
2435 switch (mcv) {2401 switch (src_val) {
2436 .none => return,2402 .none => return,
2437 .dead => unreachable,2403 .dead => unreachable,
2438 .immediate => {2404 .immediate => {
2439 const reg = try self.copyToTmpRegister(ty, mcv);2405 const reg = try self.copyToTmpRegister(ty, src_val);
2440 return self.genSetStack(ty, stack_offset, .{ .register = reg });2406 return self.genSetStack(ty, stack_offset, .{ .register = reg });
2441 },2407 },
2442 .register => |reg| {2408 .register => |reg| {
...@@ -2456,8 +2422,10 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -2456,8 +2422,10 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
2456 .tag = tag,2422 .tag = tag,
2457 .data = .{ .i_type = .{2423 .data = .{ .i_type = .{
2458 .rd = reg,2424 .rd = reg,
2459 .rs1 = .sp,2425 .rs1 = .s0,
2460 .imm12 = @intCast(stack_offset),2426 .imm12 = math.cast(i12, stack_offset) orelse {
2427 return self.fail("TODO: genSetStack bigger stack values", .{});
2428 },
2461 } },2429 } },
2462 });2430 });
2463 },2431 },
...@@ -2466,7 +2434,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -2466,7 +2434,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
2466 },2434 },
2467 .stack_offset, .load_symbol => {2435 .stack_offset, .load_symbol => {
2468 if (abi_size <= 8) {2436 if (abi_size <= 8) {
2469 const reg = try self.copyToTmpRegister(ty, mcv);2437 const reg = try self.copyToTmpRegister(ty, src_val);
2470 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });2438 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
2471 }2439 }
24722440
...@@ -2485,7 +2453,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -2485,7 +2453,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
2485 const count_reg = regs[3];2453 const count_reg = regs[3];
2486 const tmp_reg = regs[4];2454 const tmp_reg = regs[4];
24872455
2488 switch (mcv) {2456 switch (src_val) {
2489 .stack_offset => |offset| {2457 .stack_offset => |offset| {
2490 if (offset == stack_offset) return;2458 if (offset == stack_offset) return;
2491 try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = offset });2459 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...@@ -2511,7 +2479,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
2511 },2479 },
2512 });2480 });
2513 },2481 },
2514 else => return self.fail("TODO: genSetStack unreachable {s}", .{@tagName(mcv)}),2482 else => return self.fail("TODO: genSetStack unreachable {s}", .{@tagName(src_val)}),
2515 }2483 }
25162484
2517 try self.genSetReg(ptr_ty, dst_reg, .{ .ptr_stack_offset = stack_offset });2485 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...@@ -2520,10 +2488,20 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
2520 // memcpy(src, dst, len)2488 // memcpy(src, dst, len)
2521 try self.genInlineMemcpy(src_reg, dst_reg, len_reg, count_reg, tmp_reg);2489 try self.genInlineMemcpy(src_reg, dst_reg, len_reg, count_reg, tmp_reg);
2522 },2490 },
2523 else => return self.fail("TODO: genSetStack {s}", .{@tagName(mcv)}),2491 else => return self.fail("TODO: genSetStack {s}", .{@tagName(src_val)}),
2524 }2492 }
2525}2493}
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
2527fn genInlineMemcpy(2505fn genInlineMemcpy(
2528 self: *Self,2506 self: *Self,
2529 src: Register,2507 src: Register,
...@@ -2541,11 +2519,12 @@ fn genInlineMemcpy(...@@ -2541,11 +2519,12 @@ fn genInlineMemcpy(
2541 return self.fail("TODO: genInlineMemcpy", .{});2519 return self.fail("TODO: genInlineMemcpy", .{});
2542}2520}
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 {
2545 const mod = self.bin_file.comp.module.?;2524 const mod = self.bin_file.comp.module.?;
2546 const abi_size: u32 = @intCast(ty.abiSize(mod));2525 const abi_size: u32 = @intCast(ty.abiSize(mod));
25472526
2548 switch (mcv) {2527 switch (src_val) {
2549 .dead => unreachable,2528 .dead => unreachable,
2550 .ptr_stack_offset => return self.fail("TODO genSetReg ptr_stack_offset", .{}),2529 .ptr_stack_offset => return self.fail("TODO genSetReg ptr_stack_offset", .{}),
2551 .unreach, .none => return, // Nothing to do.2530 .unreach, .none => return, // Nothing to do.
...@@ -2634,8 +2613,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -2634,8 +2613,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
2634 .tag = tag,2613 .tag = tag,
2635 .data = .{ .i_type = .{2614 .data = .{ .i_type = .{
2636 .rd = reg,2615 .rd = reg,
2637 .rs1 = .sp,2616 .rs1 = .s0,
2638 .imm12 = @intCast(off),2617 .imm12 = math.cast(i12, off) orelse {
2618 return self.fail("TODO: genSetReg support larger stack sizes", .{});
2619 },
2639 } },2620 } },
2640 });2621 });
2641 },2622 },
...@@ -2685,7 +2666,7 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {...@@ -2685,7 +2666,7 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {
2685 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);2666 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
26862667
2687 const dest = try self.allocRegOrMem(inst, true);2668 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);
2689 break :result dest;2670 break :result dest;
2690 };2671 };
2691 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });2672 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
...@@ -2912,7 +2893,6 @@ const CallMCValues = struct {...@@ -2912,7 +2893,6 @@ const CallMCValues = struct {
2912/// Caller must call `CallMCValues.deinit`.2893/// Caller must call `CallMCValues.deinit`.
2913fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {2894fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
2914 const mod = self.bin_file.comp.module.?;2895 const mod = self.bin_file.comp.module.?;
2915 const ip = &mod.intern_pool;
2916 const fn_info = mod.typeToFunc(fn_ty).?;2896 const fn_info = mod.typeToFunc(fn_ty).?;
2917 const cc = fn_info.cc;2897 const cc = fn_info.cc;
2918 var result: CallMCValues = .{2898 var result: CallMCValues = .{
...@@ -2935,21 +2915,20 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -2935,21 +2915,20 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
2935 return result;2915 return result;
2936 },2916 },
2937 .Unspecified, .C => {2917 .Unspecified, .C => {
2938 // LP64D ABI2918 if (result.args.len > 8) {
2939 //2919 return self.fail("TODO: support more than 8 function args", .{});
2940 // TODO make this generic with other ABIs, in particular2920 }
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));
29482921
2949 result_arg.* = .{ .stack_offset = stack_offset };2922 for (0..result.args.len) |i| {
2950 stack_offset += param_size;2923 const arg_reg = try self.register_manager.allocReg(null, fa);
2924 result.args[i] = .{ .register = arg_reg };
2951 }2925 }
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
2953 result.stack_byte_count = stack_offset;2932 result.stack_byte_count = stack_offset;
2954 result.stack_align = .@"16";2933 result.stack_align = .@"16";
2955 },2934 },
src/arch/riscv64/Emit.zig+69-27
...@@ -27,6 +27,8 @@ prev_di_column: u32,...@@ -27,6 +27,8 @@ prev_di_column: u32,
27/// Relative to the beginning of `code`.27/// Relative to the beginning of `code`.
28prev_di_pc: usize,28prev_di_pc: usize,
2929
30stack_size: u32,
31
30const log = std.log.scoped(.emit);32const log = std.log.scoped(.emit);
3133
32const InnerError = error{34const InnerError = error{
...@@ -39,10 +41,8 @@ pub fn emitMir(...@@ -39,10 +41,8 @@ pub fn emitMir(
39) InnerError!void {41) InnerError!void {
40 const mir_tags = emit.mir.instructions.items(.tag);42 const mir_tags = emit.mir.instructions.items(.tag);
4143
42 // TODO: compute branch offsets44 try emit.lowerMir();
43 // try emit.lowerMir();
4445
45 // Emit machine code
46 for (mir_tags, 0..) |tag, index| {46 for (mir_tags, 0..) |tag, index| {
47 const inst = @as(u32, @intCast(index));47 const inst = @as(u32, @intCast(index));
48 log.debug("emitMir: {s}", .{@tagName(tag)});48 log.debug("emitMir: {s}", .{@tagName(tag)});
...@@ -70,7 +70,9 @@ pub fn emitMir(...@@ -70,7 +70,9 @@ pub fn emitMir(
70 .dbg_epilogue_begin => try emit.mirDebugEpilogueBegin(),70 .dbg_epilogue_begin => try emit.mirDebugEpilogueBegin(),
7171
72 .psuedo_prologue => try emit.mirPsuedo(inst),72 .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
75 .mv => try emit.mirRR(inst),77 .mv => try emit.mirRR(inst),
7678
...@@ -80,13 +82,15 @@ pub fn emitMir(...@@ -80,13 +82,15 @@ pub fn emitMir(
80 .lui => try emit.mirUType(inst),82 .lui => try emit.mirUType(inst),
8183
82 .ld => try emit.mirIType(inst),84 .ld => try emit.mirIType(inst),
83 .sd => try emit.mirIType(inst),
84 .lw => try emit.mirIType(inst),85 .lw => try emit.mirIType(inst),
85 .sw => try emit.mirIType(inst),
86 .lh => try emit.mirIType(inst),86 .lh => try emit.mirIType(inst),
87 .sh => try emit.mirIType(inst),
88 .lb => try emit.mirIType(inst),87 .lb => try emit.mirIType(inst),
88
89 .sd => try emit.mirIType(inst),
90 .sw => try emit.mirIType(inst),
91 .sh => try emit.mirIType(inst),
89 .sb => try emit.mirIType(inst),92 .sb => try emit.mirIType(inst),
93
90 .ldr_ptr_stack => try emit.mirIType(inst),94 .ldr_ptr_stack => try emit.mirIType(inst),
9195
92 .load_symbol => try emit.mirLoadSymbol(inst),96 .load_symbol => try emit.mirLoadSymbol(inst),
...@@ -170,8 +174,6 @@ fn mirBType(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -170,8 +174,6 @@ fn mirBType(emit: *Emit, inst: Mir.Inst.Index) !void {
170 const tag = emit.mir.instructions.items(.tag)[inst];174 const tag = emit.mir.instructions.items(.tag)[inst];
171 const b_type = emit.mir.instructions.items(.data)[inst].b_type;175 const b_type = emit.mir.instructions.items(.data)[inst].b_type;
172176
173 // const inst = b_type.imm12;
174
175 switch (tag) {177 switch (tag) {
176 .beq => try emit.writeInstruction(Instruction.beq(b_type.rs1, b_type.rs2, b_type.imm12)),178 .beq => try emit.writeInstruction(Instruction.beq(b_type.rs1, b_type.rs2, b_type.imm12)),
177 else => unreachable,179 else => unreachable,
...@@ -187,12 +189,13 @@ fn mirIType(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -187,12 +189,13 @@ fn mirIType(emit: *Emit, inst: Mir.Inst.Index) !void {
187 .jalr => try emit.writeInstruction(Instruction.jalr(i_type.rd, i_type.imm12, i_type.rs1)),189 .jalr => try emit.writeInstruction(Instruction.jalr(i_type.rd, i_type.imm12, i_type.rs1)),
188190
189 .ld => try emit.writeInstruction(Instruction.ld(i_type.rd, i_type.imm12, i_type.rs1)),191 .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)),
191 .lw => try emit.writeInstruction(Instruction.lw(i_type.rd, i_type.imm12, i_type.rs1)),192 .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)),
193 .lh => try emit.writeInstruction(Instruction.lh(i_type.rd, i_type.imm12, i_type.rs1)),193 .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)),
195 .lb => try emit.writeInstruction(Instruction.lb(i_type.rd, i_type.imm12, i_type.rs1)),194 .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)),
196 .sb => try emit.writeInstruction(Instruction.sb(i_type.rd, i_type.imm12, i_type.rs1)),199 .sb => try emit.writeInstruction(Instruction.sb(i_type.rd, i_type.imm12, i_type.rs1)),
197200
198 .ldr_ptr_stack => try emit.writeInstruction(Instruction.add(i_type.rd, i_type.rs1, .sp)),201 .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 {...@@ -262,21 +265,44 @@ fn mirPsuedo(emit: *Emit, inst: Mir.Inst.Index) !void {
262265
263 switch (tag) {266 switch (tag) {
264 .psuedo_prologue => {267 .psuedo_prologue => {
265 const imm12 = data.imm12;268 const stack_size: i12 = math.cast(i12, emit.stack_size) orelse {
266 const stack_size: i12 = @max(32, imm12);269 return emit.fail("TODO: mirPsuedo support larger stack sizes", .{});
270 };
267271
272 // Decrement sp by num s registers + local var space
268 try emit.writeInstruction(Instruction.addi(.sp, .sp, -stack_size));273 try emit.writeInstruction(Instruction.addi(.sp, .sp, -stack_size));
274
275 // Spill ra
269 try emit.writeInstruction(Instruction.sd(.ra, stack_size - 8, .sp));276 try emit.writeInstruction(Instruction.sd(.ra, stack_size - 8, .sp));
277
278 // Spill s0
270 try emit.writeInstruction(Instruction.sd(.s0, stack_size - 16, .sp));279 try emit.writeInstruction(Instruction.sd(.s0, stack_size - 16, .sp));
280
281 // Setup s0
271 try emit.writeInstruction(Instruction.addi(.s0, .sp, stack_size));282 try emit.writeInstruction(Instruction.addi(.s0, .sp, stack_size));
272 },283 },
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 => {
275 const target = data.inst;300 const target = data.inst;
276 const offset: i12 = @intCast(emit.code.items.len);301 const offset: i12 = @intCast(emit.code.items.len);
277 _ = target;302 _ = target;
278303
279 try emit.writeInstruction(Instruction.jal(.s0, offset));304 try emit.writeInstruction(Instruction.jal(.s0, offset));
305 unreachable; // TODO: mirPsuedo j
280 },306 },
281307
282 else => unreachable,308 else => unreachable,
...@@ -348,27 +374,43 @@ fn mirLoadSymbol(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -348,27 +374,43 @@ fn mirLoadSymbol(emit: *Emit, inst: Mir.Inst.Index) !void {
348 }374 }
349}375}
350376
351fn isBranch(tag: Mir.Inst.Tag) bool {377fn isStore(tag: Mir.Inst.Tag) bool {
352 switch (tag) {378 return switch (tag) {
353 .psuedo_jump => true,379 .sb => true,
380 .sh => true,
381 .sw => true,
382 .sd => true,
354 else => false,383 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 };
356}395}
357396
358fn lowerMir(emit: *Emit) !void {397fn lowerMir(emit: *Emit) !void {
359 const comp = emit.bin_file.comp;
360 const gpa = comp.gpa;
361 const mir_tags = emit.mir.instructions.items(.tag);398 const mir_tags = emit.mir.instructions.items(.tag);
362399 const mir_datas = emit.mir.instructions.items(.data);
363 _ = gpa;
364400
365 for (mir_tags, 0..) |tag, index| {401 for (mir_tags, 0..) |tag, index| {
366 const inst: u32 = @intCast(index);402 const inst: u32 = @intCast(index);
367403
368 if (isBranch(tag)) {404 if (isStore(tag) or isLoad(tag)) {
369 const target_inst = emit.mir.instructions.items(.data)[inst].inst;405 const data = mir_datas[inst].i_type;
370406 // TODO: probably create a psuedo instruction for s0 loads/stores instead of this.
371 _ = target_inst;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 }
372 }414 }
373 }415 }
374}416}
src/arch/riscv64/Mir.zig+5-2
...@@ -39,6 +39,8 @@ pub const Inst = struct {...@@ -39,6 +39,8 @@ pub const Inst = struct {
39 sub,39 sub,
4040
41 jal,41 jal,
42 /// Jumps. Uses `inst` payload.
43 j,
4244
43 // TODO: Maybe create a special data for compares that includes the ops45 // TODO: Maybe create a special data for compares that includes the ops
44 /// Compare equal, uses r_type46 /// Compare equal, uses r_type
...@@ -81,8 +83,9 @@ pub const Inst = struct {...@@ -81,8 +83,9 @@ pub const Inst = struct {
81 /// Psuedo-instruction that will generate a backpatched83 /// Psuedo-instruction that will generate a backpatched
82 /// function prologue.84 /// function prologue.
83 psuedo_prologue,85 psuedo_prologue,
84 /// Jumps. Uses `inst` payload.86 /// Psuedo-instruction that will generate a backpatched
85 psuedo_jump,87 /// function epilogue
88 psuedo_epilogue,
8689
87 // TODO: add description90 // TODO: add description
88 load_symbol,91 load_symbol,
src/arch/riscv64/abi.zig+16-2
...@@ -92,10 +92,15 @@ pub fn classifyType(ty: Type, mod: *Module) Class {...@@ -92,10 +92,15 @@ pub fn classifyType(ty: Type, mod: *Module) Class {
92}92}
9393
94pub const callee_preserved_regs = [_]Register{94pub 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,
96};97};
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;
99pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_registers);104pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_registers);
100105
101// Register classes106// Register classes
...@@ -109,4 +114,13 @@ pub const RegisterClass = struct {...@@ -109,4 +114,13 @@ pub const RegisterClass = struct {
109 }, true);114 }, true);
110 break :blk set;115 break :blk set;
111 };116 };
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 };
112};126};