| ... | @@ -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 | } |
| 1009 | | 1016 | |
| ... | @@ -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; | | |
| 1110 | | 1118 | |
| 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 applicable | 1280 | // 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 | } |
| 1278 | | 1293 | |
| 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 | }; |
| 1283 | | 1299 | |
| 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 | }; |
| 1309 | | 1325 | |
| 1310 | /// Materializes a value | 1326 | /// 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; | | |
| 1482 | | 1497 | |
| 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 | } |
| 1549 | | 1564 | |
| ... | @@ -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 | } |
| 2048 | | 2063 | |
| 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 | } |
| 2068 | | 2081 | |
| 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 | } |
| 2317 | | 2330 | |
| 2318 | fn moveDebugString(isel: *Select, reg: Register, msg: [:0]const u8) error{ OutOfMemory, AlreadyReported }!void { | 2331 | fn 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); |
| 2321 | | 2334 | |
| ... | @@ -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", .{}); |
| 3975 | | 3989 | |
| 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); |
| 3979 | | 3994 | |
| ... | @@ -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); |
| 3992 | | 4030 | |
| ... | @@ -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 | } |
| 6209 | | 6281 | |
| | 6282 | const MoveLocOptions = struct { |
| | 6283 | dst_prot: DestProtection = .none, |
| | 6284 | atomic: bool = false, |
| | 6285 | }; |
| | 6286 | |
| 6210 | fn moveLoc( | 6287 | fn 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 | }); |
| 6231 | | 6309 | |
| 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_slot | 6352 | // 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 | } |
| 6309 | | 6389 | |
| ... | @@ -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 to | 6394 | // 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); |
| 6466 | | 6548 | |
| 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 model | 6552 | // 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 | }; |
| 6727 | | 6809 | |
| 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)); |
| 6730 | | 6819 | |
| 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 | ); |
| 6761 | | 6850 | |
| 6762 | // load constant pointer | 6851 | // 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 | } |