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 {
2626 .soft_f32,
2727 .soft_f64,
2828 .soft_f80,
29 .soft_f128,
2930 });
3031}
3132
src/codegen/loongarch/Select.zig+91-48
......@@ -895,7 +895,7 @@ pub const Value = struct {
895895 };
896896 const unused_bits = @max(new_unused_bits, old_unused_bits);
897897 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
900900 // avoid setting extension to .garbage to reduce MIR for sequences like
901901 // zero_ext -> garbage -> zero_ext
......@@ -913,33 +913,8 @@ pub const Value = struct {
913913 );
914914 try vi_mat.finish(isel);
915915 } else {
916 const unused_bytes = std.math.divCeil(u64, unused_bits, 8) catch unreachable;
917 assert(unused_bytes <= isel.gprSize()); // TODO larger extending
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 }
916 try isel.failUnimplemented("unimplemented sign-extend width > GPR", .{});
917 return;
943918 }
944919 }
945920
......@@ -1325,7 +1300,6 @@ pub const Value = struct {
13251300
13261301 /// Materializes a value
13271302 fn mat(vi: Value.Index, isel: *Select, opts: MatOptions) codegen.Error!Mat {
1328 // try vi.split(isel, true);
13291303 const mat_size = @min(opts.size, @as(u32, @intCast(vi.size(isel) - opts.offset)));
13301304 const loc_pref = if (opts.extension == .garbage)
13311305 opts.pref
......@@ -2124,13 +2098,6 @@ pub const Value = struct {
21242098 .large => value.location_payload.large.stack_slot = vi.allocStackSlot(isel),
21252099 }
21262100 }
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 }
21342101 const vi_loc = vi.location(isel).?;
21352102 const maybe_loc_reg = vi_loc.asRegister();
21362103 if (maybe_loc_reg) |loc_reg| {
......@@ -2152,6 +2119,13 @@ pub const Value = struct {
21522119 assert(loc_live.* == .allocating);
21532120 loc_live.* = vi;
21542121 }
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 }
21552129 },
21562130 .value => unreachable,
21572131 .address => |addr_vi| {
......@@ -2405,6 +2379,8 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {
24052379 .div_trunc_optimized,
24062380 .div_floor,
24072381 .div_floor_optimized,
2382 .div_ceil,
2383 .div_ceil_optimized,
24082384 .div_exact,
24092385 .div_exact_optimized,
24102386 .rem,
......@@ -2758,6 +2734,33 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {
27582734 try isel.analyzeUse(arg);
27592735 }
27602736 },
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 },
27612764 .cond_br => {
27622765 const pl_op = air_data[@backingInt(air_inst_index)].pl_op;
27632766 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
38043807 64 => .@"movfr2gr.d"(dst_reg, src_reg),
38053808 });
38063809 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);
38073812 } else if (dst_ty.isAbiInt(zcu) and src_tag == .array and src_ty.childType(zcu).isAbiInt(zcu)) {
38083813 const dst_int_info = dst_ty.intInfo(zcu);
38093814 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
40584063 .{ 0, @as(u32, @intCast(payload_size)) };
40594064
40604065 const opt_vi = try isel.use(un_op);
4061 const has_value_mat = try opt_vi.mat(isel, .{
4062 .offset = has_value_offset,
4063 .size = has_value_size,
4066 const has_value_vi = try opt_vi.partExact(isel, has_value_offset, has_value_size);
4067 const has_value_mat = try has_value_vi.mat(isel, .{
40644068 .pref = .only_reg,
40654069 .reg_mod = .integer,
40664070 .extension = .zero_ext,
......@@ -4109,7 +4113,11 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) codegen.Error!void
41094113 if (!ty.isRuntimeFloat()) {
41104114 if (!ty.isAbiInt(zcu)) return isel.fail("bad {t} {f}", .{ air_tag, isel.fmtType(ty) });
41114115 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
41144122 try res_vi.value.reextendToGarbage(isel);
41154123 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
65346542 }
65356543 },
65366544 .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 },
65386567 .ptr => |ptr| {
65396568 assert(offset == 0 and size == isel.gprSize());
65406569 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
66156644 .field => |field_idx| {
66166645 var base_ptr = ip.indexToKey(field_idx.base).ptr;
66176646 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;
6619 continue :constant_key .{ .ptr = base_ptr };
6647 switch (ip.indexToKey(agg_ty.toIntern())) {
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 }
66206664 },
66216665 .comptime_alloc, .comptime_field, .arr_elem => unreachable,
66226666 };
......@@ -7056,7 +7100,7 @@ pub const CallAbiIterator = struct {
70567100 .signedness = .unsigned,
70577101 .bits = zcu.errorSetBits(),
70587102 } },
7059 .f16, .f32, .f64 => {
7103 .f16, .f32, .f64, .c_longdouble => {
70607104 const bits = ty.floatBits(isel.target);
70617105 if (isel.canUseFprForFloat(bits)) {
70627106 if (it.allocReg(.fpr)) |reg| {
......@@ -7071,7 +7115,6 @@ pub const CallAbiIterator = struct {
70717115 continue :type_key .{ .int_type = .{ .signedness = .unsigned, .bits = bits } };
70727116 }
70737117 },
7074 .c_longdouble => return isel.fail("CallAbiIterator.resolve({t})", .{simple_type}),
70757118 else => return isel.fail("CallAbiIterator.resolve({t})", .{simple_type}),
70767119 },
70777120 .struct_type => {
......@@ -7370,7 +7413,7 @@ fn gprAlignment(isel: *Select) std.mem.Alignment {
73707413 };
73717414}
73727415
7373fn fprBits(isel: *Select) u7 {
7416fn targetFprBits(isel: *Select) u7 {
73747417 const cpu = &isel.target.cpu;
73757418 if (cpu.has(.loongarch, .d)) {
73767419 return 64;
......@@ -7388,12 +7431,12 @@ fn vectorBits(isel: *Select) u7 {
73887431 } else if (cpu.has(.loongarch, .lsx)) {
73897432 return 128;
73907433 } else {
7391 return isel.fprBits();
7434 return isel.targetFprBits();
73927435 }
73937436}
73947437
73957438fn canUseFprForFloat(isel: *Select, bits: u16) bool {
7396 return bits <= isel.fprBits();
7439 return bits <= isel.targetFprBits();
73977440}
73987441
73997442fn typeOfField(isel: *Select, ty: ZigType, offset: u64) ?ZigType {