From 3ccf0fd4c2d024d696bdb1e71a0b36af38ad6bed Mon Sep 17 00:00:00 2001 From: David Rubin Date: Thu, 14 Mar 2024 15:34:06 -0700 Subject: [PATCH] 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. --- lib/compiler/test_runner.zig | 4 +- src/arch/riscv64/CodeGen.zig | 92 ++++++++++++++++++++++++++++++------ src/arch/riscv64/Emit.zig | 4 ++ src/arch/riscv64/Mir.zig | 3 ++ 4 files changed, 88 insertions(+), 15 deletions(-) diff --git a/lib/compiler/test_runner.zig b/lib/compiler/test_runner.zig index 0b9a060fb57337d0397b01a7832d4c5050f8371a..08a2e5721b70573e9778dcd4f7240d5d91090c54 100644 --- a/lib/compiler/test_runner.zig +++ b/lib/compiler/test_runner.zig @@ -12,7 +12,9 @@ var cmdline_buffer: [4096]u8 = undefined; var fba = std.heap.FixedBufferAllocator.init(&cmdline_buffer); pub fn main() void { - if (builtin.zig_backend == .stage2_aarch64) { + if (builtin.zig_backend == .stage2_aarch64 or + builtin.zig_backend == .stage2_riscv64) + { return mainSimple() catch @panic("test failure"); } diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index 7e6ad49c67d49392930afb760a1461a6e50aa7a7..ee860da8b56d5c92301ee2d17693f9de01612fcb 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -1586,11 +1586,53 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, ty: fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; - _ = ty_pl; + const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; + const operand = extra.struct_operand; + const index = extra.field_index; + const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { + const mod = self.bin_file.comp.module.?; + const src_mcv = try self.resolveInst(operand); + const struct_ty = self.typeOf(operand); + const field_ty = struct_ty.structFieldType(index, mod); + if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) break :result .none; - return self.fail("TODO: airStructFieldVal", .{}); + const field_off = @as(u32, @intCast(struct_ty.structFieldOffset(index, mod))); - // return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none }); + switch (src_mcv) { + .dead, .unreach => unreachable, + .register => |src_reg| { + const src_reg_lock = self.register_manager.lockRegAssumeUnused(src_reg); + defer self.register_manager.unlockReg(src_reg_lock); + + const dst_reg = if (field_off == 0) + (try self.copyToNewRegister(inst, src_mcv)).register + else + try self.copyToTmpRegister(Type.usize, .{ .register = src_reg }); + + const dst_mcv: MCValue = .{ .register = dst_reg }; + const dst_lock = self.register_manager.lockReg(dst_reg); + defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); + + if (field_off > 0) { + _ = try self.addInst(.{ + .tag = .srli, + .data = .{ + .i_type = .{ + .imm12 = @intCast(field_off), + .rd = dst_reg, + .rs1 = dst_reg, + }, + }, + }); + } + + break :result if (field_off == 0) dst_mcv else try self.copyToNewRegister(inst, dst_mcv); + }, + else => return self.fail("TODO: airStructField {s}", .{@tagName(src_mcv)}), + } + }; + + return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none }); } fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void { @@ -1626,8 +1668,6 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { self.arg_index = arg_index + 1; const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { - const arg_ty = self.typeOfIndex(inst); - _ = arg_ty; const src_mcv = self.args[arg_index]; const dst_mcv = switch (src_mcv) { @@ -2471,12 +2511,14 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, src_val: MCValue) Inner } }, .stack_offset, .load_symbol => { - if (true) - return self.fail("TODO: genSetStack {s}", .{@tagName(src_val)}); + switch (src_val) { + .stack_offset => |off| if (off == stack_offset) return, + else => {}, + } if (abi_size <= 8) { const reg = try self.copyToTmpRegister(ty, src_val); - return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); + return self.genSetStack(ty, stack_offset, .{ .register = reg }); } const ptr_ty = try mod.singleMutPtrType(ty); @@ -2496,7 +2538,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, src_val: MCValue) Inner switch (src_val) { .stack_offset => |offset| { - if (offset == stack_offset) return; try self.genSetReg(ptr_ty, src_reg, .{ .ptr_stack_offset = offset }); }, .load_symbol => |sym_off| { @@ -2553,11 +2594,34 @@ fn genInlineMemcpy( ) !void { _ = src; _ = dst; - _ = len; - _ = count; - _ = tmp; - return self.fail("TODO: genInlineMemcpy", .{}); + // store 0 in the count + try self.genSetReg(Type.usize, count, .{ .immediate = 0 }); + + // compare count to length + const compare_inst = try self.addInst(.{ + .tag = .cmp_gt, + .data = .{ .r_type = .{ + .rd = tmp, + .rs1 = count, + .rs2 = len, + } }, + }); + + // end if true + _ = try self.addInst(.{ + .tag = .bne, + .data = .{ + .b_type = .{ + .inst = @intCast(self.mir_instructions.len + 0), // points after the last inst + .rs1 = .zero, + .rs2 = tmp, + }, + }, + }); + _ = compare_inst; + + return self.fail("TODO: finish genInlineMemcpy", .{}); } /// 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! switch (src_val) { .dead => unreachable, - .ptr_stack_offset => return self.fail("TODO genSetReg ptr_stack_offset", .{}), + .ptr_stack_offset => |off| try self.genSetReg(ty, reg, .{ .stack_offset = off }), .unreach, .none => return, // Nothing to do. .undef => { if (!self.wantSafety()) diff --git a/src/arch/riscv64/Emit.zig b/src/arch/riscv64/Emit.zig index a40d7ba03df49f354f19fa273f5f3366fd2e85d9..036e5deea35a35c7d9f61a11425ade9e8cfb0b6b 100644 --- a/src/arch/riscv64/Emit.zig +++ b/src/arch/riscv64/Emit.zig @@ -98,6 +98,8 @@ pub fn emitMir( .sh => try emit.mirIType(inst), .sb => try emit.mirIType(inst), + .srli => try emit.mirIType(inst), + .ldr_ptr_stack => try emit.mirIType(inst), .load_symbol => try emit.mirLoadSymbol(inst), @@ -224,6 +226,8 @@ fn mirIType(emit: *Emit, inst: Mir.Inst.Index) !void { try emit.writeInstruction(Instruction.subw(i_type.rs1, i_type.rs1, i_type.rd)); }, + .srli => try emit.writeInstruction(Instruction.srli(i_type.rd, i_type.rs1, @intCast(i_type.imm12))), + else => unreachable, } } diff --git a/src/arch/riscv64/Mir.zig b/src/arch/riscv64/Mir.zig index e64ba0c7558a202620514a19a888e473b983fff0..098e0c565589d090c3c9b4f9a18e1d78e981f015 100644 --- a/src/arch/riscv64/Mir.zig +++ b/src/arch/riscv64/Mir.zig @@ -41,6 +41,9 @@ pub const Inst = struct { /// Absolute Value, uses i_type payload. abs, + /// Logical Right Shift, uses i_type payload + srli, + jal, /// Jumps. Uses `inst` payload. j, -- 2.54.0