authorgravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-03-23 14:55:33-07:00
committergravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-05-11 02:17:11-07:00
logf1fe5c937e5587064dde4ab357e9efe277a5ea49
tree609c02e73d4409cd1da7f32d409518f33c3444b5
parent92293214009cbf5d8aede56a5f54f533173324d5

riscv: pointer work

lots of thinking later, ive begun to grasp my head around how the pointers should work. this commit allows basic pointer loading and storing to happen.

3 files changed, 88 insertions(+), 39 deletions(-)

src/arch/riscv64/CodeGen.zig+85-37
......@@ -1666,28 +1666,6 @@ fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_ind
16661666 return true;
16671667}
16681668
1669fn load(self: *Self, dst_mcv: MCValue, src_ptr: MCValue, ptr_ty: Type) InnerError!void {
1670 const mod = self.bin_file.comp.module.?;
1671 const elem_ty = ptr_ty.childType(mod);
1672
1673 switch (src_ptr) {
1674 .none => unreachable,
1675 .undef => unreachable,
1676 .unreach => unreachable,
1677 .dead => unreachable,
1678 .immediate => |imm| try self.setValue(elem_ty, dst_mcv, .{ .memory = imm }),
1679 .ptr_stack_offset => |off| try self.setValue(elem_ty, dst_mcv, .{ .stack_offset = off }),
1680 .stack_offset,
1681 .register,
1682 => try self.setValue(elem_ty, dst_mcv, src_ptr),
1683 .memory => return self.fail("TODO: load memory", .{}),
1684 .load_symbol => {
1685 const reg = try self.copyToTmpRegister(ptr_ty, src_ptr);
1686 try self.load(dst_mcv, .{ .register = reg }, ptr_ty);
1687 },
1688 }
1689}
1690
16911669fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
16921670 const mod = self.bin_file.comp.module.?;
16931671 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
......@@ -1706,8 +1684,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
17061684 // The MCValue that holds the pointer can be re-used as the value.
17071685 break :blk ptr;
17081686 } else {
1709 // TODO: set this to true, will need to implement register version of arrays and structs
1710 break :blk try self.allocRegOrMem(inst, false);
1687 break :blk try self.allocRegOrMem(inst, true);
17111688 }
17121689 };
17131690 try self.load(dst_mcv, ptr, self.typeOf(ty_op.operand));
......@@ -1716,18 +1693,27 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
17161693 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
17171694}
17181695
1719fn store(self: *Self, dst_ptr: MCValue, src_val: MCValue, ptr_ty: Type, value_ty: Type) !void {
1720 _ = ptr_ty;
1721
1722 log.debug("storing {s}", .{@tagName(dst_ptr)});
1696fn load(self: *Self, dst_mcv: MCValue, src_ptr: MCValue, ptr_ty: Type) InnerError!void {
1697 const mod = self.bin_file.comp.module.?;
1698 const elem_ty = ptr_ty.childType(mod);
17231699
1724 switch (dst_ptr) {
1700 switch (src_ptr) {
17251701 .none => unreachable,
17261702 .undef => unreachable,
17271703 .unreach => unreachable,
17281704 .dead => unreachable,
1729 .ptr_stack_offset => |off| try self.genSetStack(value_ty, off, src_val),
1730 else => return self.fail("TODO implement storing to MCValue.{s}", .{@tagName(dst_ptr)}),
1705 .immediate => |imm| try self.setValue(elem_ty, dst_mcv, .{ .memory = imm }),
1706 .ptr_stack_offset => |off| try self.setValue(elem_ty, dst_mcv, .{ .stack_offset = off }),
1707
1708 .stack_offset,
1709 .register,
1710 .memory,
1711 => try self.setValue(elem_ty, dst_mcv, src_ptr),
1712
1713 .load_symbol => {
1714 const reg = try self.copyToTmpRegister(ptr_ty, src_ptr);
1715 try self.load(dst_mcv, .{ .register = reg }, ptr_ty);
1716 },
17311717 }
17321718}
17331719
......@@ -1748,6 +1734,50 @@ fn airStore(self: *Self, inst: Air.Inst.Index, safety: bool) !void {
17481734 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
17491735}
17501736
1737/// Loads `value` into the "payload" of `pointer`.
1738fn store(self: *Self, pointer: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) !void {
1739 _ = ptr_ty;
1740 const mod = self.bin_file.comp.module.?;
1741 const value_size = value_ty.abiSize(mod);
1742
1743 log.debug("storing {s}", .{@tagName(pointer)});
1744
1745 switch (pointer) {
1746 .none => unreachable,
1747 .undef => unreachable,
1748 .unreach => unreachable,
1749 .dead => unreachable,
1750 .ptr_stack_offset => |off| try self.genSetStack(value_ty, off, value),
1751
1752 .register => |reg| {
1753 const value_reg = try self.copyToTmpRegister(value_ty, value);
1754
1755 switch (value_size) {
1756 1, 2, 4, 8 => {
1757 const tag: Mir.Inst.Tag = switch (value_size) {
1758 1 => .sb,
1759 2 => .sh,
1760 4 => .sw,
1761 8 => .sd,
1762 else => unreachable,
1763 };
1764
1765 _ = try self.addInst(.{
1766 .tag = tag,
1767 .data = .{ .i_type = .{
1768 .rd = value_reg,
1769 .rs1 = reg,
1770 .imm12 = 0,
1771 } },
1772 });
1773 },
1774 else => return self.fail("TODO: genSetStack for size={d}", .{value_size}),
1775 }
1776 },
1777 else => return self.fail("TODO implement storing to MCValue.{s}", .{@tagName(pointer)}),
1778 }
1779}
1780
17511781fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) !void {
17521782 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
17531783 const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;
......@@ -2693,10 +2723,14 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, src_val: MCValue) Inner
26932723 if (!self.wantSafety()) return;
26942724 try self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa });
26952725 },
2696 .immediate => {
2726 .immediate,
2727 .ptr_stack_offset,
2728 => {
2729 // TODO: remove this lock in favor of a copyToTmpRegister when we load 64 bit immediates with
2730 // a register allocation.
26972731 const reg = try self.register_manager.allocReg(null, gp);
2698 const reg_lock = self.register_manager.lockReg(reg);
2699 defer if (reg_lock) |lock| self.register_manager.unlockReg(lock);
2732 const reg_lock = self.register_manager.lockRegAssumeUnused(reg);
2733 defer self.register_manager.unlockReg(reg_lock);
27002734
27012735 try self.genSetReg(ty, reg, src_val);
27022736
......@@ -2849,7 +2883,18 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_val: MCValue) InnerError!
28492883
28502884 switch (src_val) {
28512885 .dead => unreachable,
2852 .ptr_stack_offset => |off| try self.genSetReg(ty, reg, .{ .stack_offset = off }),
2886 .ptr_stack_offset => |off| {
2887 _ = try self.addInst(.{
2888 .tag = .addi,
2889 .data = .{ .i_type = .{
2890 .rd = reg,
2891 .rs1 = .s0,
2892 .imm12 = math.cast(i12, off) orelse {
2893 return self.fail("TODO: bigger stack sizes", .{});
2894 },
2895 } },
2896 });
2897 },
28532898 .unreach, .none => return, // Nothing to do.
28542899 .undef => {
28552900 if (!self.wantSafety())
......@@ -3166,6 +3211,8 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {
31663211
31673212fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void {
31683213 const prefetch = self.air.instructions.items(.data)[@intFromEnum(inst)].prefetch;
3214 // TODO: RISC-V does have prefetch instruction variants.
3215 // see here: https://raw.githubusercontent.com/riscv/riscv-CMOs/master/specifications/cmobase-v1.0.1.pdf
31693216 return self.finishAir(inst, MCValue.dead, .{ prefetch.ptr, .none, .none });
31703217}
31713218
......@@ -3205,12 +3252,13 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue {
32053252
32063253fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
32073254 const mod = self.bin_file.comp.module.?;
3208 const mcv: MCValue = switch (try codegen.genTypedValue(
3255 const result = try codegen.genTypedValue(
32093256 self.bin_file,
32103257 self.src_loc,
32113258 val,
32123259 mod.funcOwnerDeclIndex(self.func_index),
3213 )) {
3260 );
3261 const mcv: MCValue = switch (result) {
32143262 .mcv => |mcv| switch (mcv) {
32153263 .none => .none,
32163264 .undef => .undef,
src/arch/riscv64/Emit.zig+1
......@@ -442,6 +442,7 @@ fn isStore(tag: Mir.Inst.Tag) bool {
442442 .sh => true,
443443 .sw => true,
444444 .sd => true,
445 .addi => true, // needed for ptr_stack_offset stores
445446 else => false,
446447 };
447448}
src/arch/riscv64/Mir.zig+2-2
......@@ -72,9 +72,9 @@ pub const Inst = struct {
7272 /// allocate a register for temporary use.
7373 cmp_imm_gte,
7474
75 /// Branch if equal Uses b_type
75 /// Branch if equal, Uses b_type
7676 beq,
77 /// Branch if not eql Uses b_type
77 /// Branch if not equal, Uses b_type
7878 bne,
7979
8080 nop,