authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-10-24 23:23:21+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-10-24 23:23:21+02:00
log720939f8c9cee80963a0089645e42ebbb4545906
tree388a39b67390f24137ac563c3e26bdbcbe6cd37a
parentbca1cc3eef57f71ccfbc98d9dfe973431f9f237e
parente9ab04c89ae3079cf106d34571a825e76f46bd58

Merge pull request 'loongarch: minor improvements' (#37287) from AstraFall/zig:loongarch/pr into master

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

2 files changed, 92 insertions(+), 48 deletions(-)

src/codegen/loongarch.zig+1
...@@ -26,6 +26,7 @@ pub fn legalizeFeatures(_: *const std.Target) ?*const Air.Legalize.Features {...@@ -26,6 +26,7 @@ pub fn legalizeFeatures(_: *const std.Target) ?*const Air.Legalize.Features {
26 .soft_f32,26 .soft_f32,
27 .soft_f64,27 .soft_f64,
28 .soft_f80,28 .soft_f80,
29 .soft_f128,
29 });30 });
30}31}
3132
src/codegen/loongarch/Select.zig+91-48
...@@ -895,7 +895,7 @@ pub const Value = struct {...@@ -895,7 +895,7 @@ pub const Value = struct {
895 };895 };
896 const unused_bits = @max(new_unused_bits, old_unused_bits);896 const unused_bits = @max(new_unused_bits, old_unused_bits);
897 if (dst_ext == src_ext and bit_size <= old_bits) return;897 if (dst_ext == src_ext and bit_size <= old_bits) return;
898 tracking_log.debug("{f}: {t} ({t}) -> {t} ({t}), {d}b -> {d}b", .{ vi, src_ext, new_ext, dst_ext, old_ext, old_bits, bit_size });898 tracking_log.debug("{f}: in {t} ({t}) -> out {t} ({t}), {d}b -> {d}b", .{ vi, src_ext, new_ext, dst_ext, old_ext, old_bits, bit_size });
899899
900 // avoid setting extension to .garbage to reduce MIR for sequences like900 // avoid setting extension to .garbage to reduce MIR for sequences like
901 // zero_ext -> garbage -> zero_ext901 // zero_ext -> garbage -> zero_ext
...@@ -913,33 +913,8 @@ pub const Value = struct {...@@ -913,33 +913,8 @@ pub const Value = struct {
913 );913 );
914 try vi_mat.finish(isel);914 try vi_mat.finish(isel);
915 } else {915 } else {
916 const unused_bytes = std.math.divCeil(u64, unused_bits, 8) catch unreachable;916 try isel.failUnimplemented("unimplemented sign-extend width > GPR", .{});
917 assert(unused_bytes <= isel.gprSize()); // TODO larger extending917 return;
918 const used_bytes = vi.size(isel) - unused_bytes;
919
920 var hit = false;
921 var walker = vi.walk(isel, .{});
922 while (walker.next()) |part_vi| {
923 const part_offset = part_vi.offsetIn(isel, vi);
924 const part_size = part_vi.size(isel);
925 const part_end = part_offset + part_size;
926 if (part_end <= used_bytes) continue;
927 if (part_size > isel.gprSize()) continue;
928
929 walker.skipChildren(part_vi);
930
931 const part_mat = try part_vi.mat(isel, .{ .pref = .only_reg });
932 try isel.fillUnusedBits(
933 part_mat.reg(),
934 part_mat.reg(),
935 dst_ext,
936 src_ext,
937 @intCast(unused_bits - ((vi.size(isel) - part_end) * 8)),
938 );
939 try part_mat.finish(isel);
940 if (hit) unreachable; // TODO
941 hit = true;
942 }
943 }918 }
944 }919 }
945920
...@@ -1325,7 +1300,6 @@ pub const Value = struct {...@@ -1325,7 +1300,6 @@ pub const Value = struct {
13251300
1326 /// Materializes a value1301 /// Materializes a value
1327 fn mat(vi: Value.Index, isel: *Select, opts: MatOptions) codegen.Error!Mat {1302 fn mat(vi: Value.Index, isel: *Select, opts: MatOptions) codegen.Error!Mat {
1328 // try vi.split(isel, true);
1329 const mat_size = @min(opts.size, @as(u32, @intCast(vi.size(isel) - opts.offset)));1303 const mat_size = @min(opts.size, @as(u32, @intCast(vi.size(isel) - opts.offset)));
1330 const loc_pref = if (opts.extension == .garbage)1304 const loc_pref = if (opts.extension == .garbage)
1331 opts.pref1305 opts.pref
...@@ -2124,13 +2098,6 @@ pub const Value = struct {...@@ -2124,13 +2098,6 @@ pub const Value = struct {
2124 .large => value.location_payload.large.stack_slot = vi.allocStackSlot(isel),2098 .large => value.location_payload.large.stack_slot = vi.allocStackSlot(isel),
2125 }2099 }
2126 }2100 }
2127 switch (value.flags.location_tag) {
2128 .extreme => unreachable,
2129 .small => {},
2130 .large => {
2131 try vi.reextendAdvanced(isel, vi.bitSize(isel), mat.extension, vi.extension(isel));
2132 },
2133 }
2134 const vi_loc = vi.location(isel).?;2101 const vi_loc = vi.location(isel).?;
2135 const maybe_loc_reg = vi_loc.asRegister();2102 const maybe_loc_reg = vi_loc.asRegister();
2136 if (maybe_loc_reg) |loc_reg| {2103 if (maybe_loc_reg) |loc_reg| {
...@@ -2152,6 +2119,13 @@ pub const Value = struct {...@@ -2152,6 +2119,13 @@ pub const Value = struct {
2152 assert(loc_live.* == .allocating);2119 assert(loc_live.* == .allocating);
2153 loc_live.* = vi;2120 loc_live.* = vi;
2154 }2121 }
2122 switch (value.flags.location_tag) {
2123 .extreme => unreachable,
2124 .small => {},
2125 .large => {
2126 try vi.reextendAdvanced(isel, vi.bitSize(isel), mat.extension, vi.extension(isel));
2127 },
2128 }
2155 },2129 },
2156 .value => unreachable,2130 .value => unreachable,
2157 .address => |addr_vi| {2131 .address => |addr_vi| {
...@@ -2405,6 +2379,8 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -2405,6 +2379,8 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {
2405 .div_trunc_optimized,2379 .div_trunc_optimized,
2406 .div_floor,2380 .div_floor,
2407 .div_floor_optimized,2381 .div_floor_optimized,
2382 .div_ceil,
2383 .div_ceil_optimized,
2408 .div_exact,2384 .div_exact,
2409 .div_exact_optimized,2385 .div_exact_optimized,
2410 .rem,2386 .rem,
...@@ -2758,6 +2734,33 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -2758,6 +2734,33 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {
2758 try isel.analyzeUse(arg);2734 try isel.analyzeUse(arg);
2759 }2735 }
2760 },2736 },
2737 .legalize_compiler_rt_call => {
2738 const compiler_rt_call = isel.air.unwrapCompilerRtCall(air_inst_index);
2739
2740 for (compiler_rt_call.args) |arg|
2741 try isel.analyzeUse(arg);
2742
2743 var cc_it: CallAbiIterator = .{
2744 .isel = isel,
2745 .cc = &compiler_rt_call.func.@"callconv"(isel.target),
2746 };
2747 if (try cc_it.resolve(compiler_rt_call.func.returnType(), true)) |ret_vi| {
2748 tracking_log.debug("{f} <- %{d} (call return)", .{ ret_vi, @backingInt(air_inst_index) });
2749 switch (ret_vi.parent(isel)) {
2750 .none => {},
2751 .value, .constant => unreachable,
2752 .address => |address_vi| {
2753 defer address_vi.deref(isel);
2754 const ret_value = ret_vi.get(isel);
2755 ret_value.flags.parent_tag = .none;
2756 ret_value.parent_payload = .{ .none = {} };
2757 },
2758 }
2759 try isel.live_values.putNoClobber(gpa, air_inst_index, ret_vi);
2760
2761 try isel.def_order.putNoClobber(gpa, air_inst_index, {});
2762 }
2763 },
2761 .cond_br => {2764 .cond_br => {
2762 const pl_op = air_data[@backingInt(air_inst_index)].pl_op;2765 const pl_op = air_data[@backingInt(air_inst_index)].pl_op;
2763 const extra = isel.air.extraData(Air.CondBr, pl_op.payload);2766 const extra = isel.air.extraData(Air.CondBr, pl_op.payload);
...@@ -3804,6 +3807,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) codegen.Error!void...@@ -3804,6 +3807,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) codegen.Error!void
3804 64 => .@"movfr2gr.d"(dst_reg, src_reg),3807 64 => .@"movfr2gr.d"(dst_reg, src_reg),
3805 });3808 });
3806 try src_mat.finish(isel);3809 try src_mat.finish(isel);
3810 } else if ((dst_ty.isAbiInt(zcu) and src_tag == .float) or ((dst_tag == .float and src_ty.isAbiInt(zcu)))) {
3811 try dst_vi.value.defMove(isel, ty_op.operand);
3807 } else if (dst_ty.isAbiInt(zcu) and src_tag == .array and src_ty.childType(zcu).isAbiInt(zcu)) {3812 } else if (dst_ty.isAbiInt(zcu) and src_tag == .array and src_ty.childType(zcu).isAbiInt(zcu)) {
3808 const dst_int_info = dst_ty.intInfo(zcu);3813 const dst_int_info = dst_ty.intInfo(zcu);
3809 const src_child_int_info = src_ty.childType(zcu).intInfo(zcu);3814 const src_child_int_info = src_ty.childType(zcu).intInfo(zcu);
...@@ -4058,9 +4063,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) codegen.Error!void...@@ -4058,9 +4063,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) codegen.Error!void
4058 .{ 0, @as(u32, @intCast(payload_size)) };4063 .{ 0, @as(u32, @intCast(payload_size)) };
40594064
4060 const opt_vi = try isel.use(un_op);4065 const opt_vi = try isel.use(un_op);
4061 const has_value_mat = try opt_vi.mat(isel, .{4066 const has_value_vi = try opt_vi.partExact(isel, has_value_offset, has_value_size);
4062 .offset = has_value_offset,4067 const has_value_mat = try has_value_vi.mat(isel, .{
4063 .size = has_value_size,
4064 .pref = .only_reg,4068 .pref = .only_reg,
4065 .reg_mod = .integer,4069 .reg_mod = .integer,
4066 .extension = .zero_ext,4070 .extension = .zero_ext,
...@@ -4109,7 +4113,11 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) codegen.Error!void...@@ -4109,7 +4113,11 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) codegen.Error!void
4109 if (!ty.isRuntimeFloat()) {4113 if (!ty.isRuntimeFloat()) {
4110 if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) });4114 if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) });
4111 const int_info = ty.intInfo(zcu);4115 const int_info = ty.intInfo(zcu);
4112 if (int_info.bits > 64) return isel.fail("too big {t} {f}", .{ air_tag, isel.fmtType(ty) });4116 if (int_info.bits > 64) {
4117 _ = res_vi.value.takeLocationMarkWritten(isel);
4118 try isel.failUnimplemented("too big {t} {f}", .{ air_tag, isel.fmtType(ty) });
4119 break :unused;
4120 }
41134121
4114 try res_vi.value.reextendToGarbage(isel);4122 try res_vi.value.reextendToGarbage(isel);
4115 const res_reg = try res_vi.value.defRegMod(isel, .integer) orelse break :unused;4123 const res_reg = try res_vi.value.defRegMod(isel, .integer) orelse break :unused;
...@@ -6534,7 +6542,28 @@ fn moveConstant(isel: *Select, dst: Value.Location, init_constant: Constant, ini...@@ -6534,7 +6542,28 @@ fn moveConstant(isel: *Select, dst: Value.Location, init_constant: Constant, ini
6534 }6542 }
6535 },6543 },
6536 .enum_tag => |enum_tag| continue :constant_key .{ .int = ip.indexToKey(enum_tag.int).int },6544 .enum_tag => |enum_tag| continue :constant_key .{ .int = ip.indexToKey(enum_tag.int).int },
6537 .float => return isel.fail("float unimplemented", .{}),6545 .float => |float| {
6546 if (isel.canUseFprForFloat(ZigType.fromInterned(float.ty).floatBits(isel.target))) {
6547 return isel.fail("float unimplemented", .{});
6548 } else {
6549 switch (float.ty) {
6550 .f16_type => continue :constant_key .{ .int = .{
6551 .ty = .u16_type,
6552 .storage = .{ .u64 = @as(u16, @bitCast(float.storage.f16)) },
6553 } },
6554 .f32_type => continue :constant_key .{ .int = .{
6555 .ty = .u32_type,
6556 .storage = .{ .u64 = @as(u32, @bitCast(float.storage.f32)) },
6557 } },
6558 .f64_type => continue :constant_key .{ .int = .{
6559 .ty = .u64_type,
6560 .storage = .{ .u64 = @as(u64, @bitCast(float.storage.f64)) },
6561 } },
6562 .f80_type, .f128_type => {},
6563 else => unreachable,
6564 }
6565 }
6566 },
6538 .ptr => |ptr| {6567 .ptr => |ptr| {
6539 assert(offset == 0 and size == isel.gprSize());6568 assert(offset == 0 and size == isel.gprSize());
6540 const dst_ra: Register.Alias, const use_tmp_reg = select_tmp: {6569 const dst_ra: Register.Alias, const use_tmp_reg = select_tmp: {
...@@ -6615,8 +6644,23 @@ fn moveConstant(isel: *Select, dst: Value.Location, init_constant: Constant, ini...@@ -6615,8 +6644,23 @@ fn moveConstant(isel: *Select, dst: Value.Location, init_constant: Constant, ini
6615 .field => |field_idx| {6644 .field => |field_idx| {
6616 var base_ptr = ip.indexToKey(field_idx.base).ptr;6645 var base_ptr = ip.indexToKey(field_idx.base).ptr;
6617 const agg_ty: ZigType = .fromInterned(ip.indexToKey(base_ptr.ty).ptr_type.child);6646 const agg_ty: ZigType = .fromInterned(ip.indexToKey(base_ptr.ty).ptr_type.child);
6618 base_ptr.byte_offset += agg_ty.structFieldOffset(@intCast(field_idx.index), zcu) + ptr.byte_offset;6647 switch (ip.indexToKey(agg_ty.toIntern())) {
6619 continue :constant_key .{ .ptr = base_ptr };6648 .ptr_type => |ptr_ty| {
6649 assert(ptr_ty.flags.size == .slice);
6650 const field_offset = switch (field_idx.index) {
6651 Constant.slice_ptr_index => 0,
6652 Constant.slice_len_index => isel.gprSize(),
6653 else => unreachable,
6654 };
6655 base_ptr.byte_offset += ptr.byte_offset + field_offset;
6656 continue :constant_key .{ .ptr = base_ptr };
6657 },
6658 .struct_type, .tuple_type, .union_type => {
6659 base_ptr.byte_offset += agg_ty.structFieldOffset(@intCast(field_idx.index), zcu) + ptr.byte_offset;
6660 continue :constant_key .{ .ptr = base_ptr };
6661 },
6662 else => unreachable,
6663 }
6620 },6664 },
6621 .comptime_alloc, .comptime_field, .arr_elem => unreachable,6665 .comptime_alloc, .comptime_field, .arr_elem => unreachable,
6622 };6666 };
...@@ -7056,7 +7100,7 @@ pub const CallAbiIterator = struct {...@@ -7056,7 +7100,7 @@ pub const CallAbiIterator = struct {
7056 .signedness = .unsigned,7100 .signedness = .unsigned,
7057 .bits = zcu.errorSetBits(),7101 .bits = zcu.errorSetBits(),
7058 } },7102 } },
7059 .f16, .f32, .f64 => {7103 .f16, .f32, .f64, .c_longdouble => {
7060 const bits = ty.floatBits(isel.target);7104 const bits = ty.floatBits(isel.target);
7061 if (isel.canUseFprForFloat(bits)) {7105 if (isel.canUseFprForFloat(bits)) {
7062 if (it.allocReg(.fpr)) |reg| {7106 if (it.allocReg(.fpr)) |reg| {
...@@ -7071,7 +7115,6 @@ pub const CallAbiIterator = struct {...@@ -7071,7 +7115,6 @@ pub const CallAbiIterator = struct {
7071 continue :type_key .{ .int_type = .{ .signedness = .unsigned, .bits = bits } };7115 continue :type_key .{ .int_type = .{ .signedness = .unsigned, .bits = bits } };
7072 }7116 }
7073 },7117 },
7074 .c_longdouble => return isel.fail("CallAbiIterator.resolve({t})", .{simple_type}),
7075 else => return isel.fail("CallAbiIterator.resolve({t})", .{simple_type}),7118 else => return isel.fail("CallAbiIterator.resolve({t})", .{simple_type}),
7076 },7119 },
7077 .struct_type => {7120 .struct_type => {
...@@ -7370,7 +7413,7 @@ fn gprAlignment(isel: *Select) std.mem.Alignment {...@@ -7370,7 +7413,7 @@ fn gprAlignment(isel: *Select) std.mem.Alignment {
7370 };7413 };
7371}7414}
73727415
7373fn fprBits(isel: *Select) u7 {7416fn targetFprBits(isel: *Select) u7 {
7374 const cpu = &isel.target.cpu;7417 const cpu = &isel.target.cpu;
7375 if (cpu.has(.loongarch, .d)) {7418 if (cpu.has(.loongarch, .d)) {
7376 return 64;7419 return 64;
...@@ -7388,12 +7431,12 @@ fn vectorBits(isel: *Select) u7 {...@@ -7388,12 +7431,12 @@ fn vectorBits(isel: *Select) u7 {
7388 } else if (cpu.has(.loongarch, .lsx)) {7431 } else if (cpu.has(.loongarch, .lsx)) {
7389 return 128;7432 return 128;
7390 } else {7433 } else {
7391 return isel.fprBits();7434 return isel.targetFprBits();
7392 }7435 }
7393}7436}
73947437
7395fn canUseFprForFloat(isel: *Select, bits: u16) bool {7438fn canUseFprForFloat(isel: *Select, bits: u16) bool {
7396 return bits <= isel.fprBits();7439 return bits <= isel.targetFprBits();
7397}7440}
73987441
7399fn typeOfField(isel: *Select, ty: ZigType, offset: u64) ?ZigType {7442fn typeOfField(isel: *Select, ty: ZigType, offset: u64) ?ZigType {