diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2023-02-20 23:01:21 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-02-20 23:01:21 +0100 |
| commit | dc1f50e505105cabe1ed53951ca612778d6019ee (patch) | |
| tree | b0d91b810a6643028fc088d0af849b29dfeee632 /src/arch | |
| parent | a933a59ced8175a513ff123c3496b1b563d58453 (diff) | |
| parent | 0aee40bd13fa72ac4ca41e133440917c0ed94ffb (diff) | |
| download | zig-dc1f50e505105cabe1ed53951ca612778d6019ee.tar.gz zig-dc1f50e505105cabe1ed53951ca612778d6019ee.zip | |
Merge pull request #14685 from ziglang/bitcast-fixes
Bitcast fixes for self-hosted native backends
Diffstat (limited to 'src/arch')
| -rw-r--r-- | src/arch/aarch64/CodeGen.zig | 21 | ||||
| -rw-r--r-- | src/arch/arm/CodeGen.zig | 23 | ||||
| -rw-r--r-- | src/arch/riscv64/CodeGen.zig | 15 | ||||
| -rw-r--r-- | src/arch/sparc64/CodeGen.zig | 16 | ||||
| -rw-r--r-- | src/arch/x86_64/CodeGen.zig | 67 |
5 files changed, 126 insertions, 16 deletions
diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 5b0db30757..e7fef20a4f 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -3958,7 +3958,9 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type switch (value) { .dead => unreachable, - .undef => unreachable, + .undef => { + try self.genSetReg(value_ty, addr_reg, value); + }, .register => |value_reg| { log.debug("store: register {} to {}", .{ value_reg, addr_reg }); try self.genStrRegister(value_reg, addr_reg, value_ty); @@ -5870,7 +5872,22 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void { fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; - const result = try self.resolveInst(ty_op.operand); + const result = if (self.liveness.isUnused(inst)) .dead else result: { + const operand = try self.resolveInst(ty_op.operand); + if (self.reuseOperand(inst, ty_op.operand, 0, operand)) break :result operand; + + const operand_lock = switch (operand) { + .register => |reg| self.register_manager.lockReg(reg), + .register_with_overflow => |rwo| self.register_manager.lockReg(rwo.reg), + else => null, + }; + defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); + + const dest_ty = self.air.typeOfIndex(inst); + const dest = try self.allocRegOrMem(dest_ty, true, inst); + try self.setRegOrMem(dest_ty, dest, operand); + break :result dest; + }; return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 0fbf1ee984..fc89b2e26b 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -2765,7 +2765,9 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type switch (value) { .dead => unreachable, - .undef => unreachable, + .undef => { + try self.genSetReg(value_ty, addr_reg, value); + }, .register => |value_reg| { try self.genStrRegister(value_reg, addr_reg, value_ty); }, @@ -5816,7 +5818,24 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void { fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; - const result = try self.resolveInst(ty_op.operand); + const result = if (self.liveness.isUnused(inst)) .dead else result: { + const operand = try self.resolveInst(ty_op.operand); + if (self.reuseOperand(inst, ty_op.operand, 0, operand)) break :result operand; + + const operand_lock = switch (operand) { + .register, + .register_c_flag, + .register_v_flag, + => |reg| self.register_manager.lockReg(reg), + else => null, + }; + defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); + + const dest_ty = self.air.typeOfIndex(inst); + const dest = try self.allocRegOrMem(dest_ty, true, inst); + try self.setRegOrMem(dest_ty, dest, operand); + break :result dest; + }; return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index b97ac727c1..afcf4b0bb7 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -2338,7 +2338,20 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void { fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; - const result = try self.resolveInst(ty_op.operand); + const result = if (self.liveness.isUnused(inst)) .dead else result: { + const operand = try self.resolveInst(ty_op.operand); + if (self.reuseOperand(inst, ty_op.operand, 0, operand)) break :result operand; + + const operand_lock = switch (operand) { + .register => |reg| self.register_manager.lockReg(reg), + else => null, + }; + defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); + + const dest = try self.allocRegOrMem(inst, true); + try self.setRegOrMem(self.air.typeOfIndex(inst), dest, operand); + break :result dest; + }; return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index 8344b6e0cc..c8f77fe702 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -1091,7 +1091,21 @@ fn airPtrArithmetic(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; - const result = try self.resolveInst(ty_op.operand); + const result = if (self.liveness.isUnused(inst)) .dead else result: { + const operand = try self.resolveInst(ty_op.operand); + if (self.reuseOperand(inst, ty_op.operand, 0, operand)) break :result operand; + + const operand_lock = switch (operand) { + .register => |reg| self.register_manager.lockReg(reg), + .register_with_overflow => |rwo| self.register_manager.lockReg(rwo.reg), + else => null, + }; + defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); + + const dest = try self.allocRegOrMem(inst, true); + try self.setRegOrMem(self.air.typeOfIndex(inst), dest, operand); + break :result dest; + }; return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index f63d80486e..20e443b83c 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -920,9 +920,6 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { const mod = self.bin_file.options.module.?; return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); }; - const abi_align = elem_ty.abiAlignment(self.target.*); - if (abi_align > self.stack_align) - self.stack_align = abi_align; if (reg_ok) { switch (elem_ty.zigTypeTag()) { @@ -951,6 +948,10 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { }, } } + + const abi_align = elem_ty.abiAlignment(self.target.*); + if (abi_align > self.stack_align) + self.stack_align = abi_align; const stack_offset = try self.allocMem(inst, abi_size, abi_align); return MCValue{ .stack_offset = @intCast(i32, stack_offset) }; } @@ -990,7 +991,7 @@ fn revertState(self: *Self, state: State) void { 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}", .{ inst, stack_mcv }); const reg_mcv = self.getResolvedInstValue(inst); switch (reg_mcv) { .register => |other| { @@ -1016,7 +1017,7 @@ pub fn spillEflagsIfOccupied(self: *Self) !void { }; try self.setRegOrMem(self.air.typeOfIndex(inst_to_save), new_mcv, mcv); - log.debug("spilling {d} to mcv {any}", .{ inst_to_save, new_mcv }); + log.debug("spilling %{d} to mcv {any}", .{ inst_to_save, new_mcv }); const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; 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 { }; break :result dst_mcv; }; + log.debug("airSliceLen(%{d}): {}", .{ inst, result }); return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } @@ -2641,6 +2643,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo fn airLoad(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; const elem_ty = self.air.typeOfIndex(inst); + const elem_size = elem_ty.abiSize(self.target.*); const result: MCValue = result: { if (!elem_ty.hasRuntimeBitsIgnoreComptime()) break :result MCValue.none; @@ -2651,13 +2654,14 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { break :result MCValue.dead; const dst_mcv: MCValue = blk: { - if (self.reuseOperand(inst, ty_op.operand, 0, ptr)) { + if (elem_size <= 8 and self.reuseOperand(inst, ty_op.operand, 0, ptr)) { // The MCValue that holds the pointer can be re-used as the value. break :blk ptr; } else { break :blk try self.allocRegOrMem(inst, true); } }; + log.debug("airLoad(%{d}): {} <- {}", .{ inst, dst_mcv, ptr }); try self.load(dst_mcv, ptr, self.air.typeOf(ty_op.operand)); break :result dst_mcv; }; @@ -2728,10 +2732,12 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type switch (value) { .none => unreachable, - .undef => unreachable, .dead => unreachable, .unreach => unreachable, .eflags => unreachable, + .undef => { + try self.genSetReg(value_ty, reg, value); + }, .immediate => |imm| { switch (abi_size) { 1, 2, 4 => { @@ -2773,6 +2779,30 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type .register => |src_reg| { try self.genInlineMemcpyRegisterRegister(value_ty, reg, src_reg, 0); }, + .register_overflow => |ro| { + const ro_reg_lock = self.register_manager.lockReg(ro.reg); + defer if (ro_reg_lock) |lock| self.register_manager.unlockReg(lock); + + const wrapped_ty = value_ty.structFieldType(0); + try self.genInlineMemcpyRegisterRegister(wrapped_ty, reg, ro.reg, 0); + + const overflow_bit_ty = value_ty.structFieldType(1); + const overflow_bit_offset = value_ty.structFieldOffset(1, self.target.*); + const tmp_reg = try self.register_manager.allocReg(null, gp); + _ = try self.addInst(.{ + .tag = .cond_set_byte, + .ops = Mir.Inst.Ops.encode(.{ + .reg1 = tmp_reg.to8(), + }), + .data = .{ .cc = ro.eflags }, + }); + try self.genInlineMemcpyRegisterRegister( + overflow_bit_ty, + reg, + tmp_reg, + -@intCast(i32, overflow_bit_offset), + ); + }, .linker_load, .memory, .stack_offset, @@ -2787,8 +2817,9 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type .dest_stack_base = reg.to64(), }); }, - else => |other| { - return self.fail("TODO implement set pointee with {}", .{other}); + .ptr_stack_offset => { + const tmp_reg = try self.copyToTmpRegister(value_ty, value); + return self.store(ptr, .{ .register = tmp_reg }, ptr_ty, value_ty); }, } }, @@ -2902,6 +2933,7 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void { const ptr_ty = self.air.typeOf(bin_op.lhs); const value = try self.resolveInst(bin_op.rhs); const value_ty = self.air.typeOf(bin_op.rhs); + log.debug("airStore(%{d}): {} <- {}", .{ inst, ptr, value }); try self.store(ptr, value, ptr_ty, value_ty); return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); } @@ -6321,7 +6353,22 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void { fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; - const result = try self.resolveInst(ty_op.operand); + const result = if (self.liveness.isUnused(inst)) .dead else result: { + const operand = try self.resolveInst(ty_op.operand); + if (self.reuseOperand(inst, ty_op.operand, 0, operand)) break :result operand; + + const operand_lock = switch (operand) { + .register => |reg| self.register_manager.lockReg(reg), + .register_overflow => |ro| self.register_manager.lockReg(ro.reg), + else => null, + }; + defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); + + const dest = try self.allocRegOrMem(inst, true); + try self.setRegOrMem(self.air.typeOfIndex(inst), dest, operand); + break :result dest; + }; + log.debug("airBitCast(%{d}): {}", .{ inst, result }); return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } |
