diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2022-06-07 18:04:58 +0200 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2022-06-07 19:33:43 +0200 |
| commit | fc015231ad4e2e449e848fd08dd003efd049ad43 (patch) | |
| tree | 570b0547f7cb42d3353e47532c581d7d19da1fa4 | |
| parent | 117f9f69e79a628347c9fdb22e7ee8618de143c5 (diff) | |
| download | zig-fc015231ad4e2e449e848fd08dd003efd049ad43.tar.gz zig-fc015231ad4e2e449e848fd08dd003efd049ad43.zip | |
x64: account for non-pow-two stores via register deref
In this case, we need to proceed rather carefully to avoid writing
containing register width rather than the precise amount of bytes.
| -rw-r--r-- | src/arch/x86_64/CodeGen.zig | 49 |
1 files changed, 40 insertions, 9 deletions
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 0d4aae2688..be41f99b56 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -2732,15 +2732,46 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type } }, .register => |src_reg| { - _ = try self.addInst(.{ - .tag = .mov, - .ops = Mir.Inst.Ops.encode(.{ - .reg1 = reg.to64(), - .reg2 = registerAlias(src_reg, @intCast(u32, abi_size)), - .flags = 0b10, - }), - .data = .{ .imm = 0 }, - }); + const src_reg_lock = self.register_manager.lockReg(src_reg); + defer if (src_reg_lock) |lock| self.register_manager.unlockReg(lock); + + // TODO common code-path with genSetStack, refactor! + if (!math.isPowerOfTwo(abi_size)) { + const tmp_reg = try self.copyToTmpRegister(value_ty, value); + + var next_offset: i32 = 0; + var remainder = abi_size; + while (remainder > 0) { + const nearest_power_of_two = @as(u6, 1) << math.log2_int(u3, @intCast(u3, remainder)); + + _ = try self.addInst(.{ + .tag = .mov, + .ops = Mir.Inst.Ops.encode(.{ + .reg1 = reg.to64(), + .reg2 = registerAlias(tmp_reg, nearest_power_of_two), + .flags = 0b10, + }), + .data = .{ .imm = @bitCast(u32, -next_offset) }, + }); + + if (nearest_power_of_two > 1) { + try self.genShiftBinOpMir(.shr, value_ty, tmp_reg, .{ .immediate = nearest_power_of_two * 8 }); + } + + remainder -= nearest_power_of_two; + next_offset -= nearest_power_of_two; + } + } else { + _ = try self.addInst(.{ + .tag = .mov, + .ops = Mir.Inst.Ops.encode(.{ + .reg1 = reg.to64(), + .reg2 = registerAlias(src_reg, @intCast(u32, abi_size)), + .flags = 0b10, + }), + .data = .{ .imm = 0 }, + }); + } }, .got_load, .direct_load, |
