authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-10-01 06:50:50+02:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-10-01 06:50:50+02:00
logc29a215217b50989d431ba4d0ee97a323cdedc7b
tree8d487a860b43ebc31d1cebf79378cbd087d4e333
parentf0b51497baa5d6fe1fd5f5d5ece19364f71489bf
parentacc6b7a7d7823ff1b806152763a9adc224c32ed5

Merge pull request 'loongarch: TLS LE; unordered atomic load/store' (#37022) from AstraFall/zig:loongarch/pr into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/37022 Reviewed-by: Alex Rønne Petersen <alex@alexrp.com>

1 files changed, 125 insertions(+), 36 deletions(-)

src/codegen/loongarch/Select.zig+125-36
...@@ -983,7 +983,14 @@ pub const Value = struct {...@@ -983,7 +983,14 @@ pub const Value = struct {
983 while (part_it.next()) |part_vi| {983 while (part_it.next()) |part_vi| {
984 const part_offset, const part_size = part_vi.positionInParent(isel);984 const part_offset, const part_size = part_vi.positionInParent(isel);
985 const part_mat = try part_vi.mat(isel, .{});985 const part_mat = try part_vi.mat(isel, .{});
986 try isel.moveLoc(def_loc, part_offset, part_mat.loc(), 0, part_size, .preserved);986 try isel.moveLoc(
987 def_loc,
988 part_offset,
989 part_mat.loc(),
990 0,
991 part_size,
992 .{ .dst_prot = .preserved },
993 );
987 try part_mat.finish(isel);994 try part_mat.finish(isel);
988 if (reextend_parts)995 if (reextend_parts)
989 try part_vi.reextend(isel, def_ext);996 try part_vi.reextend(isel, def_ext);
...@@ -1003,7 +1010,7 @@ pub const Value = struct {...@@ -1003,7 +1010,7 @@ pub const Value = struct {
1003 const def_loc = def_vi.takeLocationMarkWritten(isel) orelse return;1010 const def_loc = def_vi.takeLocationMarkWritten(isel) orelse return;
1004 const def_offset, const def_size = def_vi.positionInParent(isel);1011 const def_offset, const def_size = def_vi.positionInParent(isel);
1005 const parent_mat = try parent_vi.mat(isel, .{});1012 const parent_mat = try parent_vi.mat(isel, .{});
1006 try isel.moveLoc(def_loc, 0, parent_mat.loc(), def_offset, def_size, .none);1013 try isel.moveLoc(def_loc, 0, parent_mat.loc(), def_offset, def_size, .{});
1007 try parent_mat.finish(isel);1014 try parent_mat.finish(isel);
1008 }1015 }
10091016
...@@ -1104,9 +1111,10 @@ pub const Value = struct {...@@ -1104,9 +1111,10 @@ pub const Value = struct {
1104 ) !bool {1111 ) !bool {
1105 try vi.reextendToPcs(isel);1112 try vi.reextendToPcs(isel);
1106 try vi.collectDefs(isel);1113 try vi.collectDefs(isel);
1114 if (opts.@"volatile")
1115 try (try vi.mat(isel, .{})).finish(isel);
1107 const loc = vi.takeLocationMarkWritten(isel) orelse return false;1116 const loc = vi.takeLocationMarkWritten(isel) orelse return false;
1108 wip_mir_log.debug(" | # load {f} <- [${t}, #{d}] ({d}B)", .{ vi, base_reg, offset, vi.size(isel) });1117 wip_mir_log.debug(" | # load {f} <- [${t}, #{d}] ({d}B)", .{ vi, base_reg, offset, vi.size(isel) });
1109 _ = opts;
11101118
1111 try isel.moveLoc(1119 try isel.moveLoc(
1112 loc,1120 loc,
...@@ -1114,7 +1122,7 @@ pub const Value = struct {...@@ -1114,7 +1122,7 @@ pub const Value = struct {
1114 .{ .stack_slot = .{ .base = base_reg, .offset = 0 } },1122 .{ .stack_slot = .{ .base = base_reg, .offset = 0 } },
1115 offset,1123 offset,
1116 vi.size(isel),1124 vi.size(isel),
1117 .none,1125 .{ .atomic = opts.atomic },
1118 );1126 );
1119 return true;1127 return true;
1120 }1128 }
...@@ -1166,7 +1174,7 @@ pub const Value = struct {...@@ -1166,7 +1174,7 @@ pub const Value = struct {
1166 const src_loc = src_mat.loc();1174 const src_loc = src_mat.loc();
1167 if (!std.meta.eql(loc, src_loc)) {1175 if (!std.meta.eql(loc, src_loc)) {
1168 loc.markRegWritten(isel);1176 loc.markRegWritten(isel);
1169 try isel.moveLoc(loc, 0, src_mat.loc(), 0, copy_size, .none);1177 try isel.moveLoc(loc, 0, src_mat.loc(), 0, copy_size, .{});
1170 }1178 }
1171 try src_mat.finish(isel);1179 try src_mat.finish(isel);
1172 }1180 }
...@@ -1270,15 +1278,23 @@ pub const Value = struct {...@@ -1270,15 +1278,23 @@ pub const Value = struct {
1270 _ = try isel.fillReg(src_reg);1278 _ = try isel.fillReg(src_reg);
1271 }1279 }
1272 // TODO: replace reextending def_part_vi to .zero_ext with moveLoc .wipe when applicable1280 // TODO: replace reextending def_part_vi to .zero_ext with moveLoc .wipe when applicable
1273 try isel.moveLoc(def_part_loc, dst_offset, src_loc, src_offset, mat_size, .preserved);1281 try isel.moveLoc(
1282 def_part_loc,
1283 dst_offset,
1284 src_loc,
1285 src_offset,
1286 mat_size,
1287 .{ .dst_prot = .preserved },
1288 );
1274 }1289 }
1275 }1290 }
1276 if (maybe_def_addr_mat) |def_addr_mat| try def_addr_mat.finish(isel);1291 if (maybe_def_addr_mat) |def_addr_mat| try def_addr_mat.finish(isel);
1277 }1292 }
12781293
1279 const MemoryAccessOptions = struct {1294 const MemoryAccessOptions = struct {
1280 // TODO unimplemented, remove?
1281 @"volatile": bool = false,1295 @"volatile": bool = false,
1296 // Atomicity. This is unrelated to ordering and visibility.
1297 atomic: bool = false,
1282 };1298 };
12831299
1284 const MatOptions = struct {1300 const MatOptions = struct {
...@@ -1308,7 +1324,7 @@ pub const Value = struct {...@@ -1308,7 +1324,7 @@ pub const Value = struct {
1308 };1324 };
13091325
1310 /// Materializes a value1326 /// Materializes a value
1311 fn mat(vi: Value.Index, isel: *Select, opts: MatOptions) Mat.Error!Mat {1327 fn mat(vi: Value.Index, isel: *Select, opts: MatOptions) codegen.Error!Mat {
1312 // try vi.split(isel, true);1328 // try vi.split(isel, true);
1313 const mat_size = @min(opts.size, @as(u32, @intCast(vi.size(isel) - opts.offset)));1329 const mat_size = @min(opts.size, @as(u32, @intCast(vi.size(isel) - opts.offset)));
1314 const loc_pref = if (opts.extension == .garbage)1330 const loc_pref = if (opts.extension == .garbage)
...@@ -1478,7 +1494,6 @@ pub const Value = struct {...@@ -1478,7 +1494,6 @@ pub const Value = struct {
1478 opts: MemoryAccessOptions,1494 opts: MemoryAccessOptions,
1479 ) !void {1495 ) !void {
1480 wip_mir_log.debug(" | # store {f} -> [${t}, #{d}]", .{ vi, base_reg, offset });1496 wip_mir_log.debug(" | # store {f} -> [${t}, #{d}]", .{ vi, base_reg, offset });
1481 _ = opts;
14821497
1483 const hint_stack: Indirect = if (std.math.cast(@FieldType(Indirect, "offset"), offset)) |stack_off|1498 const hint_stack: Indirect = if (std.math.cast(@FieldType(Indirect, "offset"), offset)) |stack_off|
1484 .{ .base = base_reg, .offset = stack_off }1499 .{ .base = base_reg, .offset = stack_off }
...@@ -1491,7 +1506,7 @@ pub const Value = struct {...@@ -1491,7 +1506,7 @@ pub const Value = struct {
1491 value_mat.loc(),1506 value_mat.loc(),
1492 0,1507 0,
1493 vi.size(isel),1508 vi.size(isel),
1494 .none,1509 .{ .atomic = opts.atomic },
1495 );1510 );
1496 try value_mat.finish(isel);1511 try value_mat.finish(isel);
1497 }1512 }
...@@ -1543,7 +1558,7 @@ pub const Value = struct {...@@ -1543,7 +1558,7 @@ pub const Value = struct {
1543 .size = @intCast(part_size),1558 .size = @intCast(part_size),
1544 .extension = part_vi.extension(isel),1559 .extension = part_vi.extension(isel),
1545 });1560 });
1546 try isel.moveLoc(.{ .register = part_ra }, 0, value_mat.loc(), 0, part_size, .none);1561 try isel.moveLoc(.{ .register = part_ra }, 0, value_mat.loc(), 0, part_size, .{});
1547 try value_mat.finish(isel);1562 try value_mat.finish(isel);
1548 }1563 }
15491564
...@@ -1558,7 +1573,7 @@ pub const Value = struct {...@@ -1558,7 +1573,7 @@ pub const Value = struct {
1558 .size = @intCast(part_size),1573 .size = @intCast(part_size),
1559 .extension = part_vi.extension(isel),1574 .extension = part_vi.extension(isel),
1560 });1575 });
1561 try isel.moveLoc(.{ .stack_slot = layout_part_stack }, 0, value_mat.loc(), 0, part_size, .none);1576 try isel.moveLoc(.{ .stack_slot = layout_part_stack }, 0, value_mat.loc(), 0, part_size, .{});
1562 try value_mat.finish(isel);1577 try value_mat.finish(isel);
1563 }1578 }
1564 }1579 }
...@@ -1569,7 +1584,7 @@ pub const Value = struct {...@@ -1569,7 +1584,7 @@ pub const Value = struct {
1569 if (src_loc.asRegister()) |src_reg| _ = try isel.fillReg(src_reg);1584 if (src_loc.asRegister()) |src_reg| _ = try isel.fillReg(src_reg);
1570 tracking_log.debug("{f} -> {f} (move to)", .{ vi, src_loc });1585 tracking_log.debug("{f} -> {f} (move to)", .{ vi, src_loc });
1571 if (vi.takeLocationMarkWritten(isel)) |dst_loc|1586 if (vi.takeLocationMarkWritten(isel)) |dst_loc|
1572 try isel.moveLoc(dst_loc, 0, src_loc, 0, vi.size(isel), .none);1587 try isel.moveLoc(dst_loc, 0, src_loc, 0, vi.size(isel), .{});
1573 if (vi.isSmall(isel)) {1588 if (vi.isSmall(isel)) {
1574 vi.setSmallLocation(isel, src_loc);1589 vi.setSmallLocation(isel, src_loc);
1575 if (src_loc.asRegister()) |src_reg| {1590 if (src_loc.asRegister()) |src_reg| {
...@@ -2046,8 +2061,6 @@ pub const Value = struct {...@@ -2046,8 +2061,6 @@ pub const Value = struct {
2046 if (!std.debug.runtime_safety) assert(@sizeOf(Mat) <= 32);2061 if (!std.debug.runtime_safety) assert(@sizeOf(Mat) <= 32);
2047 }2062 }
20482063
2049 const Error = codegen.Error;
2050
2051 pub fn ra(mat: Value.Mat) Register.Alias {2064 pub fn ra(mat: Value.Mat) Register.Alias {
2052 return mat.location.register;2065 return mat.location.register;
2053 }2066 }
...@@ -2066,7 +2079,7 @@ pub const Value = struct {...@@ -2066,7 +2079,7 @@ pub const Value = struct {
2066 };2079 };
2067 }2080 }
20682081
2069 fn finish(mat: Value.Mat, isel: *Select) Mat.Error!void {2082 fn finish(mat: Value.Mat, isel: *Select) codegen.Error!void {
2070 const vi = mat.vi;2083 const vi = mat.vi;
2071 const value = vi.get(isel);2084 const value = vi.get(isel);
2072 tracking_log.debug("{f}[{d}..{d}] <- {f} (mat finish)", .{ vi, mat.offset, mat.offset + mat.size - 1, mat.loc() });2085 tracking_log.debug("{f}[{d}..{d}] <- {f} (mat finish)", .{ vi, mat.offset, mat.offset + mat.size - 1, mat.loc() });
...@@ -2132,7 +2145,7 @@ pub const Value = struct {...@@ -2132,7 +2145,7 @@ pub const Value = struct {
2132 vi_loc,2145 vi_loc,
2133 mat.offset,2146 mat.offset,
2134 mat.size,2147 mat.size,
2135 .preserved,2148 .{ .dst_prot = .preserved },
2136 );2149 );
2137 if (maybe_loc_reg) |loc_reg| {2150 if (maybe_loc_reg) |loc_reg| {
2138 const loc_live = isel.live_registers.getPtr(loc_reg);2151 const loc_live = isel.live_registers.getPtr(loc_reg);
...@@ -2192,7 +2205,7 @@ pub const Value = struct {...@@ -2192,7 +2205,7 @@ pub const Value = struct {
2192 .{ .stack_slot = .{ .base = addr_mat.reg(), .offset = 0 } },2205 .{ .stack_slot = .{ .base = addr_mat.reg(), .offset = 0 } },
2193 offset_from_root + mat.offset,2206 offset_from_root + mat.offset,
2194 mat.size,2207 mat.size,
2195 .none,2208 .{},
2196 );2209 );
2197 try addr_mat.finish(isel);2210 try addr_mat.finish(isel);
2198 },2211 },
...@@ -2315,7 +2328,7 @@ fn failUnimplemented(isel: *Select, comptime format: []const u8, args: anytype)...@@ -2315,7 +2328,7 @@ fn failUnimplemented(isel: *Select, comptime format: []const u8, args: anytype)
2315 } else return isel.fail(format, args);2328 } else return isel.fail(format, args);
2316}2329}
23172330
2318fn moveDebugString(isel: *Select, reg: Register, msg: [:0]const u8) error{ OutOfMemory, AlreadyReported }!void {2331fn moveDebugString(isel: *Select, reg: Register, msg: [:0]const u8) codegen.Error!void {
2319 @branchHint(.cold);2332 @branchHint(.cold);
2320 assert(debug_trap_unimplemented_code);2333 assert(debug_trap_unimplemented_code);
23212334
...@@ -3417,7 +3430,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) codegen.Error!void...@@ -3417,7 +3430,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) codegen.Error!void
3417 output_loc,3430 output_loc,
3418 0,3431 0,
3419 output_vi.value.size(isel),3432 output_vi.value.size(isel),
3420 .none,3433 .{},
3421 );3434 );
3422 }3435 }
3423 break :output_reg output_reg;3436 break :output_reg output_reg;
...@@ -3546,7 +3559,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) codegen.Error!void...@@ -3546,7 +3559,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) codegen.Error!void
3546 const dst_loc: Value.Location = .{ .register = input_ra };3559 const dst_loc: Value.Location = .{ .register = input_ra };
3547 if (!std.meta.eql(input_val_loc, dst_loc)) {3560 if (!std.meta.eql(input_val_loc, dst_loc)) {
3548 dst_loc.markRegWritten(isel);3561 dst_loc.markRegWritten(isel);
3549 try isel.moveLoc(dst_loc, 0, input_val_loc, 0, input_ra.mod.byteSize(isel.target), .none);3562 try isel.moveLoc(dst_loc, 0, input_val_loc, 0, input_ra.mod.byteSize(isel.target), .{});
3550 }3563 }
3551 try input_val_mat.finish(isel);3564 try input_val_mat.finish(isel);
3552 },3565 },
...@@ -3964,6 +3977,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) codegen.Error!void...@@ -3964,6 +3977,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) codegen.Error!void
3964 const ptr_mat = try ptr_vi.matReg(isel);3977 const ptr_mat = try ptr_vi.matReg(isel);
3965 try src_vi.matStore(isel, ptr_mat.reg(), 0, .{3978 try src_vi.matStore(isel, ptr_mat.reg(), 0, .{
3966 .@"volatile" = ptr_info.flags.is_volatile,3979 .@"volatile" = ptr_info.flags.is_volatile,
3980 .atomic = (air_tag == .atomic_store_unordered),
3967 });3981 });
3968 try ptr_mat.finish(isel);3982 try ptr_mat.finish(isel);
3969 },3983 },
...@@ -3973,7 +3987,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) codegen.Error!void...@@ -3973,7 +3987,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) codegen.Error!void
3973 const ptr_info = ptr_ty.ptrInfo(zcu);3987 const ptr_info = ptr_ty.ptrInfo(zcu);
3974 if (ptr_info.packed_offset.host_size > 0) return isel.fail("packed load", .{});3988 if (ptr_info.packed_offset.host_size > 0) return isel.fail("packed load", .{});
39753989
3976 if (ptr_info.flags.is_volatile) _ = try isel.use(air.inst_index.toRef());3990 if (ptr_info.flags.is_volatile)
3991 _ = try isel.use(air.inst_index.toRef());
3977 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| {3992 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| {
3978 defer dst_vi.value.deref(isel);3993 defer dst_vi.value.deref(isel);
39793994
...@@ -3987,6 +4002,29 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) codegen.Error!void...@@ -3987,6 +4002,29 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) codegen.Error!void
3987 try ptr_mat.finish(isel);4002 try ptr_mat.finish(isel);
3988 }4003 }
3989 },4004 },
4005 .atomic_load => {
4006 const atomic_load = air.data(air.inst_index).atomic_load;
4007 const ptr_ty = isel.air.typeOf(atomic_load.ptr, ip);
4008 const ptr_info = ptr_ty.ptrInfo(zcu);
4009 if (ptr_info.packed_offset.host_size > 0) return isel.fail("packed atomic load", .{});
4010
4011 if (ptr_info.flags.is_volatile)
4012 _ = try isel.use(air.inst_index.toRef());
4013 if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| {
4014 defer dst_vi.value.deref(isel);
4015
4016 const ptr_vi = try isel.use(atomic_load.ptr);
4017 const ptr_mat = try ptr_vi.matIntRegZeroExt(isel);
4018 _ = try dst_vi.value.defLoad(isel, ptr_mat.reg(), 0, .{
4019 .@"volatile" = ptr_info.flags.is_volatile,
4020 .atomic = true,
4021 });
4022 try ptr_mat.finish(isel);
4023
4024 if (atomic_load.order != .unordered)
4025 try isel.failUnimplemented("ordered atomic load", .{});
4026 }
4027 },
3990 .int_cast => if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| {4028 .int_cast => if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| {
3991 defer dst_vi.value.deref(isel);4029 defer dst_vi.value.deref(isel);
39924030
...@@ -4709,6 +4747,40 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) codegen.Error!void...@@ -4709,6 +4747,40 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) codegen.Error!void
4709 try error_union_ptr_mat.finish(isel);4747 try error_union_ptr_mat.finish(isel);
4710 }4748 }
4711 },4749 },
4750 .runtime_nav_ptr => if (isel.live_values.fetchRemove(air.inst_index)) |ptr_vi| unused: {
4751 defer ptr_vi.value.deref(isel);
4752 const ptr_reg = try ptr_vi.value.defRegMod(isel, .integer) orelse break :unused;
4753 const ty_nav = air.data(air.inst_index).ty_nav;
4754 const target_nav = ip.getNav(ty_nav.nav);
4755 const target_nav_resolved = target_nav.resolved.?;
4756
4757 if (target_nav_resolved.@"threadlocal") {
4758 // TODO: implement TLS models other than LE
4759 try isel.emit(switch (isel.gprBits()) {
4760 32 => .@"add.w"(ptr_reg, ptr_reg, .tp),
4761 64 => .@"add.d"(ptr_reg, ptr_reg, .tp),
4762 else => unreachable,
4763 });
4764 try isel.nav_relocs.append(zcu.gpa, .{
4765 .nav = ty_nav.nav,
4766 .reloc = .{
4767 .label = @intCast(isel.instructions.items.len),
4768 .addend = 0,
4769 .type = .TLS_LE_LO12,
4770 },
4771 });
4772 try isel.emit(.ori(ptr_reg, ptr_reg, 0));
4773 try isel.nav_relocs.append(zcu.gpa, .{
4774 .nav = ty_nav.nav,
4775 .reloc = .{
4776 .label = @intCast(isel.instructions.items.len),
4777 .addend = 0,
4778 .type = .TLS_LE_HI20,
4779 },
4780 });
4781 try isel.emit(.@"lu12i.w"(ptr_reg, 0));
4782 } else try isel.failUnimplemented("unimplemented runtime_nav_ptr", .{});
4783 },
4712 }4784 }
4713 if (air_tag != .arg) {4785 if (air_tag != .arg) {
4714 var live_reg_it = isel.live_registers.iterator();4786 var live_reg_it = isel.live_registers.iterator();
...@@ -6207,6 +6279,11 @@ fn elemPtr(...@@ -6207,6 +6279,11 @@ fn elemPtr(
6207 try index_mat.finish(isel);6279 try index_mat.finish(isel);
6208}6280}
62096281
6282const MoveLocOptions = struct {
6283 dst_prot: DestProtection = .none,
6284 atomic: bool = false,
6285};
6286
6210fn moveLoc(6287fn moveLoc(
6211 isel: *Select,6288 isel: *Select,
6212 dst_loc: Value.Location,6289 dst_loc: Value.Location,
...@@ -6214,22 +6291,23 @@ fn moveLoc(...@@ -6214,22 +6291,23 @@ fn moveLoc(
6214 src_loc: Value.Location,6291 src_loc: Value.Location,
6215 src_off: u64,6292 src_off: u64,
6216 size: u64,6293 size: u64,
6217 dst_prot: DestProtection,6294 opts: MoveLocOptions,
6218) !void {6295) !void {
6219 if (dst_loc.isUnallocated()) return;6296 if (dst_loc.isUnallocated()) return;
6220 if (std.meta.eql(dst_loc, src_loc) and dst_off == src_off) return;6297 if (std.meta.eql(dst_loc, src_loc) and dst_off == src_off) return;
6221 if (size == 0) return;6298 if (size == 0) return;
6222 assert(!src_loc.isUnallocated());6299 assert(!src_loc.isUnallocated());
6223 wip_mir_log.debug(" | # move {f}[{d}] <- {f}[{d}], {d}B, dst prot={t}", .{6300 wip_mir_log.debug(" | # move {f}[{d}] <- {f}[{d}], {d}B, dst prot={t}, atomic={}", .{
6224 dst_loc,6301 dst_loc,
6225 dst_off,6302 dst_off,
6226 src_loc,6303 src_loc,
6227 src_off,6304 src_off,
6228 size,6305 size,
6229 dst_prot,6306 opts.dst_prot,
6307 opts.atomic,
6230 });6308 });
62316309
6232 const dst_lock: RegLock = if (dst_prot != .preserved) .empty else dst_loc.tryLock(isel);6310 const dst_lock: RegLock = if (opts.dst_prot != .preserved) .empty else dst_loc.tryLock(isel);
6233 defer dst_lock.unlock(isel);6311 defer dst_lock.unlock(isel);
6234 const src_lock = src_loc.tryLock(isel);6312 const src_lock = src_loc.tryLock(isel);
6235 defer src_lock.unlock(isel);6313 defer src_lock.unlock(isel);
...@@ -6242,7 +6320,7 @@ fn moveLoc(...@@ -6242,7 +6320,7 @@ fn moveLoc(
6242 src_ra,6320 src_ra,
6243 @intCast(src_off * 8),6321 @intCast(src_off * 8),
6244 @intCast(size * 8),6322 @intCast(size * 8),
6245 dst_prot,6323 opts.dst_prot,
6246 ),6324 ),
6247 .stack_slot => |src_stack| {6325 .stack_slot => |src_stack| {
6248 const tmp_reg = if (dst_ra.mod == .integer and dst_off == 0)6326 const tmp_reg = if (dst_ra.mod == .integer and dst_off == 0)
...@@ -6256,7 +6334,7 @@ fn moveLoc(...@@ -6256,7 +6334,7 @@ fn moveLoc(
6256 .{ .reg = tmp_reg, .mod = .integer },6334 .{ .reg = tmp_reg, .mod = .integer },
6257 0,6335 0,
6258 @intCast(size * 8),6336 @intCast(size * 8),
6259 dst_prot,6337 opts.dst_prot,
6260 );6338 );
6261 try isel.loadReg(6339 try isel.loadReg(
6262 tmp_reg,6340 tmp_reg,
...@@ -6268,6 +6346,8 @@ fn moveLoc(...@@ -6268,6 +6346,8 @@ fn moveLoc(
6268 },6346 },
6269 },6347 },
6270 .stack_slot => |dst_stack| {6348 .stack_slot => |dst_stack| {
6349 if (size > isel.gprSize() and opts.atomic)
6350 return isel.fail("Memory store of {d} bytes cannot be atomic", .{size});
6271 if (size > isel.gprSize()) {6351 if (size > isel.gprSize()) {
6272 // large memory copies, src must be stack_slot6352 // large memory copies, src must be stack_slot
6273 const src_stack = src_loc.stack_slot;6353 const src_stack = src_loc.stack_slot;
...@@ -6295,7 +6375,7 @@ fn moveLoc(...@@ -6295,7 +6375,7 @@ fn moveLoc(
6295 if (gen_low_to_high) {6375 if (gen_low_to_high) {
6296 var off: u64 = 0;6376 var off: u64 = 0;
6297 for (0..@intCast(steps)) |_| {6377 for (0..@intCast(steps)) |_| {
6298 try isel.moveLoc(dst_loc, dst_off + off, src_loc, src_off + off, gpr_size, dst_prot);6378 try isel.moveLoc(dst_loc, dst_off + off, src_loc, src_off + off, gpr_size, opts);
6299 off += gpr_size;6379 off += gpr_size;
6300 }6380 }
6301 }6381 }
...@@ -6303,7 +6383,7 @@ fn moveLoc(...@@ -6303,7 +6383,7 @@ fn moveLoc(
6303 var off: u64 = steps * gpr_size;6383 var off: u64 = steps * gpr_size;
6304 for (0..@intCast(steps)) |_| {6384 for (0..@intCast(steps)) |_| {
6305 off -= gpr_size;6385 off -= gpr_size;
6306 try isel.moveLoc(dst_loc, dst_off + off, src_loc, src_off + off, gpr_size, dst_prot);6386 try isel.moveLoc(dst_loc, dst_off + off, src_loc, src_off + off, gpr_size, opts);
6307 }6387 }
6308 }6388 }
63096389
...@@ -6314,7 +6394,9 @@ fn moveLoc(...@@ -6314,7 +6394,9 @@ fn moveLoc(
6314 // If size is not direct mem op size and !kill_dst, old values have to6394 // If size is not direct mem op size and !kill_dst, old values have to
6315 // be loaded first.6395 // be loaded first.
6316 const memop_size = memOpSizeFitting(size);6396 const memop_size = memOpSizeFitting(size);
6317 const need_load = memop_size != size;6397 const need_load = memop_size != size and opts.dst_prot != .none;
6398 if (opts.atomic and need_load)
6399 return isel.fail("Memory store of {d} bytes cannot be atomic without killing other bytes", .{size});
6318 const tmp_reg, const tmp_allocated = tmp_reg: {6400 const tmp_reg, const tmp_allocated = tmp_reg: {
6319 if (src_off == 0 and !need_load) {6401 if (src_off == 0 and !need_load) {
6320 switch (src_loc) {6402 switch (src_loc) {
...@@ -6336,7 +6418,7 @@ fn moveLoc(...@@ -6336,7 +6418,7 @@ fn moveLoc(
6336 src_loc,6418 src_loc,
6337 src_off,6419 src_off,
6338 size,6420 size,
6339 if (need_load) .preserved else .none,6421 opts,
6340 );6422 );
6341 if (need_load)6423 if (need_load)
6342 try isel.loadReg(tmp_reg, memop_size, .unsigned, dst_stack.base, dst_stack_off);6424 try isel.loadReg(tmp_reg, memop_size, .unsigned, dst_stack.base, dst_stack_off);
...@@ -6464,7 +6546,7 @@ fn moveConstant(isel: *Select, dst: Value.Location, init_constant: Constant, ini...@@ -6464,7 +6546,7 @@ fn moveConstant(isel: *Select, dst: Value.Location, init_constant: Constant, ini
6464 const rd = dst_ra.reg;6546 const rd = dst_ra.reg;
6465 defer if (use_tmp_reg) isel.freeReg(rd);6547 defer if (use_tmp_reg) isel.freeReg(rd);
64666548
6467 if (use_tmp_reg) try isel.moveLoc(dst, 0, .{ .register = dst_ra }, 0, isel.gprSize(), .none);6549 if (use_tmp_reg) try isel.moveLoc(dst, 0, .{ .register = dst_ra }, 0, isel.gprSize(), .{});
6468 return switch (ptr.base_addr) {6550 return switch (ptr.base_addr) {
6469 .nav => |nav| if (ZigType.fromInterned(ip.getNav(nav).resolved.?.type).isRuntimeFnOrHasRuntimeBits(zcu)) {6551 .nav => |nav| if (ZigType.fromInterned(ip.getNav(nav).resolved.?.type).isRuntimeFnOrHasRuntimeBits(zcu)) {
6470 // TODO code model6552 // TODO code model
...@@ -6725,7 +6807,14 @@ fn moveConstant(isel: *Select, dst: Value.Location, init_constant: Constant, ini...@@ -6725,7 +6807,14 @@ fn moveConstant(isel: *Select, dst: Value.Location, init_constant: Constant, ini
6725 ),6807 ),
6726 };6808 };
67276809
6728 try isel.moveLoc(dst, part_offset, .{ .register = tmp_ra }, 0, part_size, .preserved);6810 try isel.moveLoc(
6811 dst,
6812 part_offset,
6813 .{ .register = tmp_ra },
6814 0,
6815 part_size,
6816 .{ .dst_prot = .preserved },
6817 );
6729 try isel.moveIntImm(tmp_reg, @bitCast(part_value));6818 try isel.moveIntImm(tmp_reg, @bitCast(part_value));
67306819
6731 if (part_offset == 0) break else part_offset -= gpr_size;6820 if (part_offset == 0) break else part_offset -= gpr_size;
...@@ -6756,7 +6845,7 @@ fn moveConstant(isel: *Select, dst: Value.Location, init_constant: Constant, ini...@@ -6756,7 +6845,7 @@ fn moveConstant(isel: *Select, dst: Value.Location, init_constant: Constant, ini
6756 .{ .stack_slot = .{ .base = tmp_reg, .offset = 0 } },6845 .{ .stack_slot = .{ .base = tmp_reg, .offset = 0 } },
6757 offset,6846 offset,
6758 size,6847 size,
6759 .none,6848 .{},
6760 );6849 );
67616850
6762 // load constant pointer6851 // load constant pointer
...@@ -7238,7 +7327,7 @@ const call = struct {...@@ -7238,7 +7327,7 @@ const call = struct {
7238 .{ .register = .{ .mod = .integer, .reg = tmp_reg } },7327 .{ .register = .{ .mod = .integer, .reg = tmp_reg } },
7239 0,7328 0,
7240 isel.gprSize(),7329 isel.gprSize(),
7241 .preserved,7330 .{ .dst_prot = .preserved },
7242 );7331 );
7243 } else unreachable;7332 } else unreachable;
7244 }7333 }