From 69d03d3a297809d1bc91ed5848501c64666244a1 Mon Sep 17 00:00:00 2001 From: joachimschmidt557 Date: Thu, 30 Dec 2021 14:39:06 +0100 Subject: [PATCH] stage2 ARM: implement struct_field_ptr and struct_field_val --- src/arch/arm/CodeGen.zig | 72 +++++++++++++++++++++++++++++----------- src/codegen.zig | 23 ++++++++++++- src/register_manager.zig | 6 +++- test/stage2/arm.zig | 46 +++++++++++++++++++++++++ 4 files changed, 125 insertions(+), 22 deletions(-) diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index fa40bc0c5a..7765064634 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -783,7 +783,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void { const stack_mcv = try self.allocRegOrMem(inst, false); - log.debug("spilling {d} to stack mcv {any}", .{ inst, stack_mcv }); + log.debug("spilling {} (%{d}) to stack mcv {any}", .{ reg, inst, stack_mcv }); const reg_mcv = self.getResolvedInstValue(inst); assert(reg == reg_mcv.register); const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; @@ -1591,28 +1591,54 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void { fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) !void { const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; - return self.structFieldPtr(extra.struct_operand, ty_pl.ty, extra.field_index); + const result = try self.structFieldPtr(inst, extra.struct_operand, extra.field_index); + return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none }); } fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; - return self.structFieldPtr(ty_op.operand, ty_op.ty, index); + const result = try self.structFieldPtr(inst, ty_op.operand, index); + return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } -fn structFieldPtr(self: *Self, operand: Air.Inst.Ref, ty: Air.Inst.Ref, index: u32) !void { - _ = self; - _ = operand; - _ = ty; - _ = index; - return self.fail("TODO implement codegen struct_field_ptr", .{}); - //return self.finishAir(inst, result, .{ extra.struct_ptr, .none, .none }); + +fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue { + return if (self.liveness.isUnused(inst)) .dead else result: { + const mcv = try self.resolveInst(operand); + const struct_ty = self.air.typeOf(operand).childType(); + const struct_size = @intCast(u32, struct_ty.abiSize(self.target.*)); + const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*)); + const struct_field_ty = struct_ty.structFieldType(index); + const struct_field_size = @intCast(u32, struct_field_ty.abiSize(self.target.*)); + switch (mcv) { + .ptr_stack_offset => |off| { + break :result MCValue{ .ptr_stack_offset = off + struct_size - struct_field_offset - struct_field_size }; + }, + else => return self.fail("TODO implement codegen struct_field_ptr for {}", .{mcv}), + } + }; } fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; const extra = self.air.extraData(Air.StructField, ty_pl.payload).data; - _ = extra; - return self.fail("TODO implement codegen struct_field_val", .{}); - //return self.finishAir(inst, result, .{ extra.struct_ptr, .none, .none }); + const operand = extra.struct_operand; + const index = extra.field_index; + const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { + const mcv = try self.resolveInst(operand); + const struct_ty = self.air.typeOf(operand); + const struct_size = @intCast(u32, struct_ty.abiSize(self.target.*)); + const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*)); + const struct_field_ty = struct_ty.structFieldType(index); + const struct_field_size = @intCast(u32, struct_field_ty.abiSize(self.target.*)); + switch (mcv) { + .stack_offset => |off| { + break :result MCValue{ .stack_offset = off + struct_size - struct_field_offset - struct_field_size }; + }, + else => return self.fail("TODO implement codegen struct_field_val for {}", .{mcv}), + } + }; + + return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none }); } fn armOperandShouldBeRegister(self: *Self, mcv: MCValue) !bool { @@ -1985,11 +2011,11 @@ fn genArmMulConstant(self: *Self, inst: Air.Inst.Index, op: Air.Inst.Ref, op_ind // Allocate 1 or 2 registers if (lhs_is_register) { // Move RHS to register - dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{mcv.register}) }; + dst_mcv = MCValue{ .register = try self.register_manager.allocReg(null, &.{mcv.register}) }; rhs_mcv = dst_mcv; } else { // Move LHS and RHS to register - const regs = try self.register_manager.allocRegs(2, .{ inst, null }, &.{}); + const regs = try self.register_manager.allocRegs(2, .{ null, null }, &.{}); lhs_mcv = MCValue{ .register = regs[0] }; rhs_mcv = MCValue{ .register = regs[1] }; dst_mcv = lhs_mcv; @@ -2401,16 +2427,22 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { if (rhs_should_be_register) { if (!lhs_is_register and !rhs_is_register) { const regs = try self.register_manager.allocRegs(2, .{ - Air.refToIndex(bin_op.rhs).?, Air.refToIndex(bin_op.lhs).?, + Air.refToIndex(bin_op.lhs).?, Air.refToIndex(bin_op.rhs).?, }, &.{}); lhs_mcv = MCValue{ .register = regs[0] }; rhs_mcv = MCValue{ .register = regs[1] }; } else if (!rhs_is_register) { - rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(bin_op.rhs).?, &.{}) }; + const track_inst = if (self.liveness.operandDies(inst, 1)) null else Air.refToIndex(bin_op.rhs).?; + rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(track_inst, &.{}) }; + } else if (!lhs_is_register) { + const track_inst = if (self.liveness.operandDies(inst, 0)) null else Air.refToIndex(bin_op.lhs).?; + lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(track_inst, &.{}) }; + } + } else { + if (!lhs_is_register) { + const track_inst = if (self.liveness.operandDies(inst, 0)) null else Air.refToIndex(bin_op.lhs).?; + lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(track_inst, &.{}) }; } - } - if (!lhs_is_register) { - lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(bin_op.lhs).?, &.{}) }; } // Move the operands to the newly allocated registers diff --git a/src/codegen.zig b/src/codegen.zig index f93c53804b..fdbdb7d5c1 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -372,11 +372,32 @@ pub fn generateSymbol( return Result{ .appended = {} }; }, .Struct => { + // TODO debug info + // TODO padding of struct members const field_vals = typed_value.val.castTag(.@"struct").?.data; - _ = field_vals; // TODO write the fields for real + for (field_vals) |field_val, index| { + const field_ty = typed_value.ty.structFieldType(index); + if (!field_ty.hasCodeGenBits()) continue; + switch (try generateSymbol(bin_file, src_loc, .{ + .ty = field_ty, + .val = field_val, + }, code, debug_output)) { + .appended => {}, + .externally_managed => |external_slice| { + code.appendSliceAssumeCapacity(external_slice); + }, + .fail => |em| return Result{ .fail = em }, + } + } + + return Result{ .appended = {} }; + }, + .Union => { + // TODO generateSymbol for unions const target = bin_file.options.target; const abi_size = try math.cast(usize, typed_value.ty.abiSize(target)); try code.writer().writeByteNTimes(0xaa, abi_size); + return Result{ .appended = {} }; }, else => |t| { diff --git a/src/register_manager.zig b/src/register_manager.zig index 43e19e2ca3..add0335374 100644 --- a/src/register_manager.zig +++ b/src/register_manager.zig @@ -129,7 +129,7 @@ pub fn RegisterManager( comptime assert(count > 0 and count <= callee_preserved_regs.len); assert(count + exceptions.len <= callee_preserved_regs.len); - return self.tryAllocRegs(count, insts, exceptions) orelse blk: { + const result = self.tryAllocRegs(count, insts, exceptions) orelse blk: { // We'll take over the first count registers. Spill // the instructions that were previously there to a // stack allocations. @@ -164,6 +164,9 @@ pub fn RegisterManager( break :blk regs; }; + + log.debug("allocated registers {any} for insts {any}", .{ result, insts }); + return result; } /// Allocates a register and optionally tracks it with a @@ -213,6 +216,7 @@ pub fn RegisterManager( /// Marks the specified register as free pub fn freeReg(self: *Self, reg: Register) void { const index = reg.allocIndex() orelse return; + log.debug("freeing register {}", .{reg}); self.registers[index] = null; self.markRegFree(reg); diff --git a/test/stage2/arm.zig b/test/stage2/arm.zig index ef24caed85..d8417e2f78 100644 --- a/test/stage2/arm.zig +++ b/test/stage2/arm.zig @@ -658,4 +658,50 @@ pub fn addCases(ctx: *TestContext) !void { "", ); } + + { + var case = ctx.exe("structs", linux_arm); + case.addCompareOutput( + \\var array = [_]SomeStruct{ + \\ .{ .a = 0, .b = 42, .c = 69 }, + \\ .{ .a = 1, .b = 2, .c = 3 }, + \\ .{ .a = 123, .b = 456, .c = 789 }, + \\}; + \\var s: []const SomeStruct = &array; + \\ + \\var some_struct: SomeStruct = .{ + \\ .a = 0, + \\ .b = 42, + \\ .c = 69, + \\}; + \\ + \\const SomeStruct = struct { + \\ a: u32, + \\ b: u32, + \\ c: u32, + \\}; + \\ + \\pub fn main() void { + \\ assert(some_struct.a == 0); + \\ assert(some_struct.b == 42); + \\ assert(some_struct.c == 69); + \\ + \\ assert(s[0].a == 0); + \\ assert(s[0].b == 42); + \\ assert(s[0].c == 69); + \\ assert(s[1].a == 1); + \\ assert(s[1].b == 2); + \\ assert(s[1].c == 3); + \\ assert(s[2].a == 123); + \\ assert(s[2].b == 456); + \\ assert(s[2].c == 789); + \\} + \\ + \\fn assert(ok: bool) void { + \\ if (!ok) unreachable; + \\} + , + "", + ); + } }