authorgravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-03-14 15:34:06-07:00
committergravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-05-11 02:17:11-07:00
log3ccf0fd4c2d024d696bdb1e71a0b36af38ad6bed
treeab05699caca1a13fd5888e75a3296b2426aaf5b2
parent2be3033acda53389cac9f3e9a8ca0a3d41348eef

riscv: basic struct field access

the current implementation only works when the struct is in a register. we use some shifting magic to get the field into the LSB, and from there, given the type provenance, the generated code should never reach into the bits beyond the bit size of the type and interact with the rest of the struct.

4 files changed, 88 insertions(+), 15 deletions(-)

lib/compiler/test_runner.zig+3-1
......@@ -12,7 +12,9 @@ var cmdline_buffer: [4096]u8 = undefined;
1212var fba = std.heap.FixedBufferAllocator.init(&cmdline_buffer);
1313
1414pub fn main() void {
15 if (builtin.zig_backend == .stage2_aarch64) {
15 if (builtin.zig_backend == .stage2_aarch64 or
16 builtin.zig_backend == .stage2_riscv64)
17 {
1618 return mainSimple() catch @panic("test failure");
1719 }
1820
src/arch/riscv64/CodeGen.zig+78-14
......@@ -1586,11 +1586,53 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, ty:
15861586
15871587fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
15881588 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
1589 _ = ty_pl;
1589 const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;
1590 const operand = extra.struct_operand;
1591 const index = extra.field_index;
1592 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1593 const mod = self.bin_file.comp.module.?;
1594 const src_mcv = try self.resolveInst(operand);
1595 const struct_ty = self.typeOf(operand);
1596 const field_ty = struct_ty.structFieldType(index, mod);
1597 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) break :result .none;
1598
1599 const field_off = @as(u32, @intCast(struct_ty.structFieldOffset(index, mod)));
1600
1601 switch (src_mcv) {
1602 .dead, .unreach => unreachable,
1603 .register => |src_reg| {
1604 const src_reg_lock = self.register_manager.lockRegAssumeUnused(src_reg);
1605 defer self.register_manager.unlockReg(src_reg_lock);
1606
1607 const dst_reg = if (field_off == 0)
1608 (try self.copyToNewRegister(inst, src_mcv)).register
1609 else
1610 try self.copyToTmpRegister(Type.usize, .{ .register = src_reg });
1611
1612 const dst_mcv: MCValue = .{ .register = dst_reg };
1613 const dst_lock = self.register_manager.lockReg(dst_reg);
1614 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
1615
1616 if (field_off > 0) {
1617 _ = try self.addInst(.{
1618 .tag = .srli,
1619 .data = .{
1620 .i_type = .{
1621 .imm12 = @intCast(field_off),
1622 .rd = dst_reg,
1623 .rs1 = dst_reg,
1624 },
1625 },
1626 });
1627 }
15901628
1591 return self.fail("TODO: airStructFieldVal", .{});
1629 break :result if (field_off == 0) dst_mcv else try self.copyToNewRegister(inst, dst_mcv);
1630 },
1631 else => return self.fail("TODO: airStructField {s}", .{@tagName(src_mcv)}),
1632 }
1633 };
15921634
1593 // return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none });
1635 return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none });
15941636}
15951637
15961638fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {
......@@ -1626,8 +1668,6 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
16261668 self.arg_index = arg_index + 1;
16271669
16281670 const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: {
1629 const arg_ty = self.typeOfIndex(inst);
1630 _ = arg_ty;
16311671 const src_mcv = self.args[arg_index];
16321672
16331673 const dst_mcv = switch (src_mcv) {
......@@ -2471,12 +2511,14 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, src_val: MCValue) Inner
24712511 }
24722512 },
24732513 .stack_offset, .load_symbol => {
2474 if (true)
2475 return self.fail("TODO: genSetStack {s}", .{@tagName(src_val)});
2514 switch (src_val) {
2515 .stack_offset => |off| if (off == stack_offset) return,
2516 else => {},
2517 }
24762518
24772519 if (abi_size <= 8) {
24782520 const reg = try self.copyToTmpRegister(ty, src_val);
2479 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
2521 return self.genSetStack(ty, stack_offset, .{ .register = reg });
24802522 }
24812523
24822524 const ptr_ty = try mod.singleMutPtrType(ty);
......@@ -2496,7 +2538,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, src_val: MCValue) Inner
24962538
24972539 switch (src_val) {
24982540 .stack_offset => |offset| {
2499 if (offset == stack_offset) return;
25002541 try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = offset });
25012542 },
25022543 .load_symbol => |sym_off| {
......@@ -2553,11 +2594,34 @@ fn genInlineMemcpy(
25532594) !void {
25542595 _ = src;
25552596 _ = dst;
2556 _ = len;
2557 _ = count;
2558 _ = tmp;
25592597
2560 return self.fail("TODO: genInlineMemcpy", .{});
2598 // store 0 in the count
2599 try self.genSetReg(Type.usize, count, .{ .immediate = 0 });
2600
2601 // compare count to length
2602 const compare_inst = try self.addInst(.{
2603 .tag = .cmp_gt,
2604 .data = .{ .r_type = .{
2605 .rd = tmp,
2606 .rs1 = count,
2607 .rs2 = len,
2608 } },
2609 });
2610
2611 // end if true
2612 _ = try self.addInst(.{
2613 .tag = .bne,
2614 .data = .{
2615 .b_type = .{
2616 .inst = @intCast(self.mir_instructions.len + 0), // points after the last inst
2617 .rs1 = .zero,
2618 .rs2 = tmp,
2619 },
2620 },
2621 });
2622 _ = compare_inst;
2623
2624 return self.fail("TODO: finish genInlineMemcpy", .{});
25612625}
25622626
25632627/// Sets the value of `src_val` into `reg`. Assumes you have a lock on it.
......@@ -2567,7 +2631,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_val: MCValue) InnerError!
25672631
25682632 switch (src_val) {
25692633 .dead => unreachable,
2570 .ptr_stack_offset => return self.fail("TODO genSetReg ptr_stack_offset", .{}),
2634 .ptr_stack_offset => |off| try self.genSetReg(ty, reg, .{ .stack_offset = off }),
25712635 .unreach, .none => return, // Nothing to do.
25722636 .undef => {
25732637 if (!self.wantSafety())
src/arch/riscv64/Emit.zig+4
......@@ -98,6 +98,8 @@ pub fn emitMir(
9898 .sh => try emit.mirIType(inst),
9999 .sb => try emit.mirIType(inst),
100100
101 .srli => try emit.mirIType(inst),
102
101103 .ldr_ptr_stack => try emit.mirIType(inst),
102104
103105 .load_symbol => try emit.mirLoadSymbol(inst),
......@@ -224,6 +226,8 @@ fn mirIType(emit: *Emit, inst: Mir.Inst.Index) !void {
224226 try emit.writeInstruction(Instruction.subw(i_type.rs1, i_type.rs1, i_type.rd));
225227 },
226228
229 .srli => try emit.writeInstruction(Instruction.srli(i_type.rd, i_type.rs1, @intCast(i_type.imm12))),
230
227231 else => unreachable,
228232 }
229233}
src/arch/riscv64/Mir.zig+3
......@@ -41,6 +41,9 @@ pub const Inst = struct {
4141 /// Absolute Value, uses i_type payload.
4242 abs,
4343
44 /// Logical Right Shift, uses i_type payload
45 srli,
46
4447 jal,
4548 /// Jumps. Uses `inst` payload.
4649 j,