Commit f1fe5c937e

David Rubin <daviru007@icloud.com>
2024-03-23 22:55:33
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.
1 parent 9229321
Changed files (3)
src/arch/riscv64/CodeGen.zig
@@ -1666,28 +1666,6 @@ fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_ind
     return true;
 }
 
-fn load(self: *Self, dst_mcv: MCValue, src_ptr: MCValue, ptr_ty: Type) InnerError!void {
-    const mod = self.bin_file.comp.module.?;
-    const elem_ty = ptr_ty.childType(mod);
-
-    switch (src_ptr) {
-        .none => unreachable,
-        .undef => unreachable,
-        .unreach => unreachable,
-        .dead => unreachable,
-        .immediate => |imm| try self.setValue(elem_ty, dst_mcv, .{ .memory = imm }),
-        .ptr_stack_offset => |off| try self.setValue(elem_ty, dst_mcv, .{ .stack_offset = off }),
-        .stack_offset,
-        .register,
-        => try self.setValue(elem_ty, dst_mcv, src_ptr),
-        .memory => return self.fail("TODO: load memory", .{}),
-        .load_symbol => {
-            const reg = try self.copyToTmpRegister(ptr_ty, src_ptr);
-            try self.load(dst_mcv, .{ .register = reg }, ptr_ty);
-        },
-    }
-}
-
 fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
     const mod = self.bin_file.comp.module.?;
     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 {
                 // The MCValue that holds the pointer can be re-used as the value.
                 break :blk ptr;
             } else {
-                // TODO: set this to true, will need to implement register version of arrays and structs
-                break :blk try self.allocRegOrMem(inst, false);
+                break :blk try self.allocRegOrMem(inst, true);
             }
         };
         try self.load(dst_mcv, ptr, self.typeOf(ty_op.operand));
@@ -1716,18 +1693,27 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
 }
 
-fn store(self: *Self, dst_ptr: MCValue, src_val: MCValue, ptr_ty: Type, value_ty: Type) !void {
-    _ = ptr_ty;
-
-    log.debug("storing {s}", .{@tagName(dst_ptr)});
+fn load(self: *Self, dst_mcv: MCValue, src_ptr: MCValue, ptr_ty: Type) InnerError!void {
+    const mod = self.bin_file.comp.module.?;
+    const elem_ty = ptr_ty.childType(mod);
 
-    switch (dst_ptr) {
+    switch (src_ptr) {
         .none => unreachable,
         .undef => unreachable,
         .unreach => unreachable,
         .dead => unreachable,
-        .ptr_stack_offset => |off| try self.genSetStack(value_ty, off, src_val),
-        else => return self.fail("TODO implement storing to MCValue.{s}", .{@tagName(dst_ptr)}),
+        .immediate => |imm| try self.setValue(elem_ty, dst_mcv, .{ .memory = imm }),
+        .ptr_stack_offset => |off| try self.setValue(elem_ty, dst_mcv, .{ .stack_offset = off }),
+
+        .stack_offset,
+        .register,
+        .memory,
+        => try self.setValue(elem_ty, dst_mcv, src_ptr),
+
+        .load_symbol => {
+            const reg = try self.copyToTmpRegister(ptr_ty, src_ptr);
+            try self.load(dst_mcv, .{ .register = reg }, ptr_ty);
+        },
     }
 }
 
@@ -1748,6 +1734,50 @@ fn airStore(self: *Self, inst: Air.Inst.Index, safety: bool) !void {
     return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
 }
 
+/// Loads `value` into the "payload" of `pointer`.
+fn store(self: *Self, pointer: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) !void {
+    _ = ptr_ty;
+    const mod = self.bin_file.comp.module.?;
+    const value_size = value_ty.abiSize(mod);
+
+    log.debug("storing {s}", .{@tagName(pointer)});
+
+    switch (pointer) {
+        .none => unreachable,
+        .undef => unreachable,
+        .unreach => unreachable,
+        .dead => unreachable,
+        .ptr_stack_offset => |off| try self.genSetStack(value_ty, off, value),
+
+        .register => |reg| {
+            const value_reg = try self.copyToTmpRegister(value_ty, value);
+
+            switch (value_size) {
+                1, 2, 4, 8 => {
+                    const tag: Mir.Inst.Tag = switch (value_size) {
+                        1 => .sb,
+                        2 => .sh,
+                        4 => .sw,
+                        8 => .sd,
+                        else => unreachable,
+                    };
+
+                    _ = try self.addInst(.{
+                        .tag = tag,
+                        .data = .{ .i_type = .{
+                            .rd = value_reg,
+                            .rs1 = reg,
+                            .imm12 = 0,
+                        } },
+                    });
+                },
+                else => return self.fail("TODO: genSetStack for size={d}", .{value_size}),
+            }
+        },
+        else => return self.fail("TODO implement storing to MCValue.{s}", .{@tagName(pointer)}),
+    }
+}
+
 fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) !void {
     const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
     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
             if (!self.wantSafety()) return;
             try self.genSetStack(ty, stack_offset, .{ .immediate = 0xaaaaaaaaaaaaaaaa });
         },
-        .immediate => {
+        .immediate,
+        .ptr_stack_offset,
+        => {
+            // TODO: remove this lock in favor of a copyToTmpRegister when we load 64 bit immediates with
+            // a register allocation.
             const reg = try self.register_manager.allocReg(null, gp);
-            const reg_lock = self.register_manager.lockReg(reg);
-            defer if (reg_lock) |lock| self.register_manager.unlockReg(lock);
+            const reg_lock = self.register_manager.lockRegAssumeUnused(reg);
+            defer self.register_manager.unlockReg(reg_lock);
 
             try self.genSetReg(ty, reg, src_val);
 
@@ -2849,7 +2883,18 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_val: MCValue) InnerError!
 
     switch (src_val) {
         .dead => unreachable,
-        .ptr_stack_offset => |off| try self.genSetReg(ty, reg, .{ .stack_offset = off }),
+        .ptr_stack_offset => |off| {
+            _ = try self.addInst(.{
+                .tag = .addi,
+                .data = .{ .i_type = .{
+                    .rd = reg,
+                    .rs1 = .s0,
+                    .imm12 = math.cast(i12, off) orelse {
+                        return self.fail("TODO: bigger stack sizes", .{});
+                    },
+                } },
+            });
+        },
         .unreach, .none => return, // Nothing to do.
         .undef => {
             if (!self.wantSafety())
@@ -3166,6 +3211,8 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void {
 
 fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void {
     const prefetch = self.air.instructions.items(.data)[@intFromEnum(inst)].prefetch;
+    // TODO: RISC-V does have prefetch instruction variants.
+    // see here: https://raw.githubusercontent.com/riscv/riscv-CMOs/master/specifications/cmobase-v1.0.1.pdf
     return self.finishAir(inst, MCValue.dead, .{ prefetch.ptr, .none, .none });
 }
 
@@ -3205,12 +3252,13 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue {
 
 fn genTypedValue(self: *Self, val: Value) InnerError!MCValue {
     const mod = self.bin_file.comp.module.?;
-    const mcv: MCValue = switch (try codegen.genTypedValue(
+    const result = try codegen.genTypedValue(
         self.bin_file,
         self.src_loc,
         val,
         mod.funcOwnerDeclIndex(self.func_index),
-    )) {
+    );
+    const mcv: MCValue = switch (result) {
         .mcv => |mcv| switch (mcv) {
             .none => .none,
             .undef => .undef,
src/arch/riscv64/Emit.zig
@@ -442,6 +442,7 @@ fn isStore(tag: Mir.Inst.Tag) bool {
         .sh => true,
         .sw => true,
         .sd => true,
+        .addi => true, // needed for ptr_stack_offset stores
         else => false,
     };
 }
src/arch/riscv64/Mir.zig
@@ -72,9 +72,9 @@ pub const Inst = struct {
         /// allocate a register for temporary use.
         cmp_imm_gte,
 
-        /// Branch if equal Uses b_type
+        /// Branch if equal, Uses b_type
         beq,
-        /// Branch if not eql Uses b_type
+        /// Branch if not equal, Uses b_type
         bne,
 
         nop,