Commit 2cbd8e1deb

David Rubin <daviru007@icloud.com>
2024-03-18 07:18:48
riscv: progress toward arrays
- implement `airArrayElemVal` for arrays on the stack. This is really easy as we can just move the offset by the bytes into the array. This only works when the index access is comptime-known though, this won't work for runtime access.
1 parent 9b2a458
Changed files (1)
src
arch
riscv64
src/arch/riscv64/CodeGen.zig
@@ -1442,8 +1442,29 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) !void {
 }
 
 fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
+    const mod = self.bin_file.comp.module.?;
     const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
-    const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement array_elem_val for {}", .{self.target.cpu.arch});
+    const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
+        const array_ty = self.typeOf(bin_op.lhs);
+        const array_mcv = try self.resolveInst(bin_op.lhs);
+
+        const index_mcv = try self.resolveInst(bin_op.rhs);
+
+        const elem_ty = array_ty.childType(mod);
+        const elem_abi_size = elem_ty.abiSize(mod);
+
+        switch (array_mcv) {
+            // all we need to do is calculate the offset that the elem exits at.
+            .stack_offset => |off| {
+                if (index_mcv == .immediate) {
+                    const true_offset: u32 = @intCast(index_mcv.immediate * elem_abi_size);
+                    break :result MCValue{ .stack_offset = off + true_offset };
+                }
+                return self.fail("TODO: airArrayElemVal with runtime index", .{});
+            },
+            else => return self.fail("TODO: airArrayElemVal {s}", .{@tagName(array_mcv)}),
+        }
+    };
     return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
 }
 
@@ -1639,17 +1660,10 @@ fn load(self: *Self, dst_mcv: MCValue, src_ptr: MCValue, ptr_ty: Type) InnerErro
         .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 }),
-        .register => try self.setValue(elem_ty, dst_mcv, src_ptr),
-        .memory,
         .stack_offset,
-        => {
-            const reg = try self.register_manager.allocReg(null, gp);
-            const reg_lock = self.register_manager.lockRegAssumeUnused(reg);
-            errdefer self.register_manager.unlockReg(reg_lock);
-
-            try self.genSetReg(ptr_ty, reg, src_ptr);
-            try self.load(dst_mcv, .{ .register = reg }, ptr_ty);
-        },
+        .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);
@@ -1675,7 +1689,8 @@ 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 {
-                break :blk try self.allocRegOrMem(inst, true);
+                // TODO: set this to true, will need to implement register version of arrays and structs
+                break :blk try self.allocRegOrMem(inst, false);
             }
         };
         try self.load(dst_mcv, ptr, self.typeOf(ty_op.operand));
@@ -1750,7 +1765,13 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
         const field_ty = struct_ty.structFieldType(index, mod);
         if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) break :result .none;
 
-        const field_off = @as(u32, @intCast(struct_ty.structFieldOffset(index, mod)));
+        const field_off: u32 = switch (struct_ty.containerLayout(mod)) {
+            .Auto, .Extern => @intCast(struct_ty.structFieldOffset(index, mod) * 8),
+            .Packed => if (mod.typeToStruct(struct_ty)) |struct_type|
+                mod.structPackedFieldBitOffset(struct_type, index)
+            else
+                0,
+        };
 
         switch (src_mcv) {
             .dead, .unreach => unreachable,
@@ -1778,10 +1799,15 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
                             },
                         },
                     });
+
+                    return self.fail("TODO: airStructFieldVal register with field_off > 0", .{});
                 }
 
                 break :result if (field_off == 0) dst_mcv else try self.copyToNewRegister(inst, dst_mcv);
             },
+            .stack_offset => |off| {
+                break :result MCValue{ .stack_offset = off + field_off };
+            },
             else => return self.fail("TODO: airStructField {s}", .{@tagName(src_mcv)}),
         }
     };
@@ -2435,7 +2461,8 @@ fn performReloc(self: *Self, inst: Mir.Inst.Index, target: Mir.Inst.Index) !void
         .bne,
         .beq,
         => self.mir_instructions.items(.data)[inst].b_type.inst = target,
-        .jal => self.mir_instructions.items(.data)[inst].j_type.inst = target,
+        .jal,
+        => self.mir_instructions.items(.data)[inst].j_type.inst = target,
         else => return self.fail("TODO: performReloc {s}", .{@tagName(tag)}),
     }
 }
@@ -2614,6 +2641,7 @@ fn setValue(self: *Self, ty: Type, dst_val: MCValue, src_val: MCValue) !void {
     if (dst_val == .none) return;
 
     if (!dst_val.isMutable()) {
+        // panic so we can see the trace
         return std.debug.panic("tried to setValue immutable: {s}", .{@tagName(dst_val)});
     }
 
@@ -2649,8 +2677,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, src_val: MCValue) Inner
         .register => |reg| {
             switch (abi_size) {
                 1, 2, 4, 8 => {
-                    assert(std.mem.isAlignedGeneric(u32, stack_offset, abi_size));
-
                     const tag: Mir.Inst.Tag = switch (abi_size) {
                         1 => .sb,
                         2 => .sh,
@@ -2733,7 +2759,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, src_val: MCValue) Inner
             // memcpy(src, dst, len)
             try self.genInlineMemcpy(src_reg, dst_reg, len_reg, count_reg, tmp_reg);
         },
-
         else => return self.fail("TODO: genSetStack {s}", .{@tagName(src_val)}),
     }
 }