authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-02-19 23:18:24+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-02-20 10:52:26+01:00
loga7de8dc2ddb5b1fa45d2fcfba4b305fef9f59be4
treea08a9232c9040c76039cb97605748073b5736d9a
parent0bb178bbb2451238a326c6e916ecf38fbc34cab1

x86: alloc new mcv in bitcast if cannot reuse operand

Implement missing pointees when ptr is in register.

2 files changed, 58 insertions(+), 10 deletions(-)

src/arch/x86_64/CodeGen.zig+57-10
......@@ -920,9 +920,6 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
920920 const mod = self.bin_file.options.module.?;
921921 return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)});
922922 };
923 const abi_align = elem_ty.abiAlignment(self.target.*);
924 if (abi_align > self.stack_align)
925 self.stack_align = abi_align;
926923
927924 if (reg_ok) {
928925 switch (elem_ty.zigTypeTag()) {
......@@ -951,6 +948,10 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
951948 },
952949 }
953950 }
951
952 const abi_align = elem_ty.abiAlignment(self.target.*);
953 if (abi_align > self.stack_align)
954 self.stack_align = abi_align;
954955 const stack_offset = try self.allocMem(inst, abi_size, abi_align);
955956 return MCValue{ .stack_offset = @intCast(i32, stack_offset) };
956957}
......@@ -990,7 +991,7 @@ fn revertState(self: *Self, state: State) void {
990991
991992pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void {
992993 const stack_mcv = try self.allocRegOrMem(inst, false);
993 log.debug("spilling {d} to stack mcv {any}", .{ inst, stack_mcv });
994 log.debug("spilling %{d} to stack mcv {any}", .{ inst, stack_mcv });
994995 const reg_mcv = self.getResolvedInstValue(inst);
995996 switch (reg_mcv) {
996997 .register => |other| {
......@@ -1016,7 +1017,7 @@ pub fn spillEflagsIfOccupied(self: *Self) !void {
10161017 };
10171018
10181019 try self.setRegOrMem(self.air.typeOfIndex(inst_to_save), new_mcv, mcv);
1019 log.debug("spilling {d} to mcv {any}", .{ inst_to_save, new_mcv });
1020 log.debug("spilling %{d} to mcv {any}", .{ inst_to_save, new_mcv });
10201021
10211022 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
10221023 try branch.inst_table.put(self.gpa, inst_to_save, new_mcv);
......@@ -2114,6 +2115,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) !void {
21142115 };
21152116 break :result dst_mcv;
21162117 };
2118 log.debug("airSliceLen(%{d}): {}", .{ inst, result });
21172119 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
21182120}
21192121
......@@ -2641,6 +2643,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
26412643fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
26422644 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
26432645 const elem_ty = self.air.typeOfIndex(inst);
2646 const elem_size = elem_ty.abiSize(self.target.*);
26442647 const result: MCValue = result: {
26452648 if (!elem_ty.hasRuntimeBitsIgnoreComptime())
26462649 break :result MCValue.none;
......@@ -2651,13 +2654,14 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
26512654 break :result MCValue.dead;
26522655
26532656 const dst_mcv: MCValue = blk: {
2654 if (self.reuseOperand(inst, ty_op.operand, 0, ptr)) {
2657 if (elem_size <= 8 and self.reuseOperand(inst, ty_op.operand, 0, ptr)) {
26552658 // The MCValue that holds the pointer can be re-used as the value.
26562659 break :blk ptr;
26572660 } else {
26582661 break :blk try self.allocRegOrMem(inst, true);
26592662 }
26602663 };
2664 log.debug("airLoad(%{d}): {} <- {}", .{ inst, dst_mcv, ptr });
26612665 try self.load(dst_mcv, ptr, self.air.typeOf(ty_op.operand));
26622666 break :result dst_mcv;
26632667 };
......@@ -2728,10 +2732,12 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
27282732
27292733 switch (value) {
27302734 .none => unreachable,
2731 .undef => unreachable,
27322735 .dead => unreachable,
27332736 .unreach => unreachable,
27342737 .eflags => unreachable,
2738 .undef => {
2739 try self.genSetReg(value_ty, reg, value);
2740 },
27352741 .immediate => |imm| {
27362742 switch (abi_size) {
27372743 1, 2, 4 => {
......@@ -2773,6 +2779,30 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
27732779 .register => |src_reg| {
27742780 try self.genInlineMemcpyRegisterRegister(value_ty, reg, src_reg, 0);
27752781 },
2782 .register_overflow => |ro| {
2783 const ro_reg_lock = self.register_manager.lockReg(ro.reg);
2784 defer if (ro_reg_lock) |lock| self.register_manager.unlockReg(lock);
2785
2786 const wrapped_ty = value_ty.structFieldType(0);
2787 try self.genInlineMemcpyRegisterRegister(wrapped_ty, reg, ro.reg, 0);
2788
2789 const overflow_bit_ty = value_ty.structFieldType(1);
2790 const overflow_bit_offset = value_ty.structFieldOffset(1, self.target.*);
2791 const tmp_reg = try self.register_manager.allocReg(null, gp);
2792 _ = try self.addInst(.{
2793 .tag = .cond_set_byte,
2794 .ops = Mir.Inst.Ops.encode(.{
2795 .reg1 = tmp_reg.to8(),
2796 }),
2797 .data = .{ .cc = ro.eflags },
2798 });
2799 try self.genInlineMemcpyRegisterRegister(
2800 overflow_bit_ty,
2801 reg,
2802 tmp_reg,
2803 -@intCast(i32, overflow_bit_offset),
2804 );
2805 },
27762806 .linker_load,
27772807 .memory,
27782808 .stack_offset,
......@@ -2787,8 +2817,9 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
27872817 .dest_stack_base = reg.to64(),
27882818 });
27892819 },
2790 else => |other| {
2791 return self.fail("TODO implement set pointee with {}", .{other});
2820 .ptr_stack_offset => {
2821 const tmp_reg = try self.copyToTmpRegister(value_ty, value);
2822 return self.store(ptr, .{ .register = tmp_reg }, ptr_ty, value_ty);
27922823 },
27932824 }
27942825 },
......@@ -2902,6 +2933,7 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void {
29022933 const ptr_ty = self.air.typeOf(bin_op.lhs);
29032934 const value = try self.resolveInst(bin_op.rhs);
29042935 const value_ty = self.air.typeOf(bin_op.rhs);
2936 log.debug("airStore(%{d}): {} <- {}", .{ inst, ptr, value });
29052937 try self.store(ptr, value, ptr_ty, value_ty);
29062938 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
29072939}
......@@ -6321,7 +6353,22 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void {
63216353
63226354fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {
63236355 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
6324 const result = try self.resolveInst(ty_op.operand);
6356 const result = if (self.liveness.isUnused(inst)) .dead else result: {
6357 const operand = try self.resolveInst(ty_op.operand);
6358 if (self.reuseOperand(inst, ty_op.operand, 0, operand)) break :result operand;
6359
6360 const operand_lock = switch (operand) {
6361 .register => |reg| self.register_manager.lockReg(reg),
6362 .register_overflow => |ro| self.register_manager.lockReg(ro.reg),
6363 else => null,
6364 };
6365 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
6366
6367 const dest = try self.allocRegOrMem(inst, true);
6368 try self.setRegOrMem(self.air.typeOfIndex(inst), dest, operand);
6369 break :result dest;
6370 };
6371 log.debug("airBitCast(%{d}): {}", .{ inst, result });
63256372 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
63266373}
63276374
test/behavior/basic.zig+1
......@@ -387,6 +387,7 @@ fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA {
387387}
388388
389389test "take address of parameter" {
390 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
390391 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
391392 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
392393 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO