aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2022-06-07 18:04:58 +0200
committerJakub Konka <kubkon@jakubkonka.com>2022-06-07 19:33:43 +0200
commitfc015231ad4e2e449e848fd08dd003efd049ad43 (patch)
tree570b0547f7cb42d3353e47532c581d7d19da1fa4 /src
parent117f9f69e79a628347c9fdb22e7ee8618de143c5 (diff)
downloadzig-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.
Diffstat (limited to 'src')
-rw-r--r--src/arch/x86_64/CodeGen.zig49
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,