authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-09-01 10:37:50+02:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-09-01 10:37:50+02:00
log0a2af0b09a435e95f07fb4624ed1ee1025761a4e
treed9fac4ef1eab54ee00c2632782e22232bd93d50b
parent67f39b551d457478f4c18d6709a04037ce168c75
parent9b9c1d8fe138bad6ecec5a32a180225b0c0c4826

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

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

3 files changed, 133 insertions(+), 114 deletions(-)

src/codegen/loongarch/Mir.zig+21-89
...@@ -13,7 +13,8 @@ internal_relocs: []const Reloc.Internal,...@@ -13,7 +13,8 @@ internal_relocs: []const Reloc.Internal,
1313
14pub const Reloc = struct {14pub const Reloc = struct {
15 label: u32,15 label: u32,
16 addend: i64 align(@alignOf(u32)) = 0,16 type: std.elf.R_LARCH,
17 addend: i64 = 0,
1718
18 pub const Nav = struct {19 pub const Nav = struct {
19 nav: InternPool.Nav.Index,20 nav: InternPool.Nav.Index,
...@@ -35,14 +36,10 @@ pub const Reloc = struct {...@@ -35,14 +36,10 @@ pub const Reloc = struct {
35 reloc: Reloc,36 reloc: Reloc,
36 };37 };
3738
38 pub const Literal = struct {
39 label: u32,
40 };
41
42 pub const Internal = struct {39 pub const Internal = struct {
43 // Target MIR index40 // Target MIR index
44 target: usize = 0,41 target: usize = 0,
45 label: u32,42 reloc: Reloc,
46 };43 };
47};44};
4845
...@@ -91,7 +88,7 @@ pub fn emit(...@@ -91,7 +88,7 @@ pub fn emit(
91 pt,88 pt,
92 nav_reloc.nav,89 nav_reloc.nav,
93 ),90 ),
94 mir.body[nav_reloc.reloc.label],91 nav_reloc.reloc.type,
95 body_end - @sizeOf(Instruction) * (1 + nav_reloc.reloc.label),92 body_end - @sizeOf(Instruction) * (1 + nav_reloc.reloc.label),
96 nav_reloc.reloc.addend,93 nav_reloc.reloc.addend,
97 ) catch |err|94 ) catch |err|
...@@ -105,7 +102,7 @@ pub fn emit(...@@ -105,7 +102,7 @@ pub fn emit(
105 uav_reloc.uav.val,102 uav_reloc.uav.val,
106 ZigType.fromInterned(uav_reloc.uav.orig_ty).ptrAlignment(zcu),103 ZigType.fromInterned(uav_reloc.uav.orig_ty).ptrAlignment(zcu),
107 ),104 ),
108 mir.body[uav_reloc.reloc.label],105 uav_reloc.reloc.type,
109 body_end - @sizeOf(Instruction) * (1 + uav_reloc.reloc.label),106 body_end - @sizeOf(Instruction) * (1 + uav_reloc.reloc.label),
110 uav_reloc.reloc.addend,107 uav_reloc.reloc.addend,
111 ) catch |err|108 ) catch |err|
...@@ -122,7 +119,7 @@ pub fn emit(...@@ -122,7 +119,7 @@ pub fn emit(
122 return zcu.codegenFail(func.owner_nav, "emit lazy symbol: {t}", .{err})119 return zcu.codegenFail(func.owner_nav, "emit lazy symbol: {t}", .{err})
123 else120 else
124 return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {s}", .{@tagName(lf.tag)}),121 return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {s}", .{@tagName(lf.tag)}),
125 mir.body[lazy_reloc.reloc.label],122 lazy_reloc.reloc.type,
126 body_end - @sizeOf(Instruction) * (1 + lazy_reloc.reloc.label),123 body_end - @sizeOf(Instruction) * (1 + lazy_reloc.reloc.label),
127 lazy_reloc.reloc.addend,124 lazy_reloc.reloc.addend,
128 ) catch |err|125 ) catch |err|
...@@ -139,7 +136,7 @@ pub fn emit(...@@ -139,7 +136,7 @@ pub fn emit(
139 .type = .FUNC,136 .type = .FUNC,
140 }) catch |err|137 }) catch |err|
141 return zcu.codegenFail(func.owner_nav, "emit global symbol failed: {t}", .{err}) else return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {s}", .{@tagName(lf.tag)}),138 return zcu.codegenFail(func.owner_nav, "emit global symbol failed: {t}", .{err}) else return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {s}", .{@tagName(lf.tag)}),
142 mir.body[global_reloc.reloc.label],139 global_reloc.reloc.type,
143 body_end - @sizeOf(Instruction) * (1 + global_reloc.reloc.label),140 body_end - @sizeOf(Instruction) * (1 + global_reloc.reloc.label),
144 global_reloc.reloc.addend,141 global_reloc.reloc.addend,
145 ) catch |err|142 ) catch |err|
...@@ -155,8 +152,8 @@ pub fn emit(...@@ -155,8 +152,8 @@ pub fn emit(
155 zcu,152 zcu,
156 atom_index,153 atom_index,
157 func_nav,154 func_nav,
158 mir.body[internal_reloc.label],155 internal_reloc.reloc.type,
159 body_end - @sizeOf(Instruction) * (1 + internal_reloc.label),156 body_end - @sizeOf(Instruction) * (1 + internal_reloc.reloc.label),
160 @sizeOf(Instruction) * (@as(i64, @intCast(mir.prologue.len + mir.body.len - internal_reloc.target))),157 @sizeOf(Instruction) * (@as(i64, @intCast(mir.prologue.len + mir.body.len - internal_reloc.target))),
161 ) catch |err|158 ) catch |err|
162 return zcu.codegenFail(func.owner_nav, "emit reloc failed: {t}", .{err});159 return zcu.codegenFail(func.owner_nav, "emit reloc failed: {t}", .{err});
...@@ -182,86 +179,21 @@ fn emitReloc(...@@ -182,86 +179,21 @@ fn emitReloc(
182 zcu: *Zcu,179 zcu: *Zcu,
183 atom_index: link.File.AtomId,180 atom_index: link.File.AtomId,
184 sym_index: link.File.SymbolId,181 sym_index: link.File.SymbolId,
185 instruction: Instruction,182 reloc_type: std.elf.R_LARCH,
186 offset: u32,183 offset: u32,
187 addend: i64,184 addend: i64,
188) !void {185) !void {
189 const mnemonic = Disassemble.decodeMnemonic(instruction) orelse {186 if (lf.cast(.elf2)) |ef| {
190 mir_log.debug("cannot decode instruction 0x{x}", .{instruction.word});187 try ef.addReloc(atom_index, offset, sym_index, addend, .{ .LARCH = reloc_type });
191 unreachable;188 } else if (lf.cast(.elf)) |ef| {
192 };189 const zo = ef.zigObjectPtr().?;
193 switch (mnemonic) {190 const atom = zo.symbol(@backingInt(atom_index)).atom(ef).?;
194 else => {191 try atom.addReloc(zcu.gpa, .{
195 mir_log.debug("unimplemented reloc on {t}", .{mnemonic});192 .r_offset = offset,
196 unreachable;193 .r_info = @as(u64, @backingInt(sym_index)) << 32 | @backingInt(reloc_type),
197 },194 .r_addend = @bitCast(addend),
198 .pcaddu18i => if (lf.cast(.elf2)) |ef| {195 }, zo);
199 try ef.addReloc(atom_index, offset, sym_index, addend, .{ .LARCH = .CALL36 });196 } else unreachable;
200 } else if (lf.cast(.elf)) |ef| {
201 const zo = ef.zigObjectPtr().?;
202 const atom = zo.symbol(@backingInt(atom_index)).atom(ef).?;
203 try atom.addReloc(zcu.gpa, .{
204 .r_offset = offset,
205 .r_info = @as(u64, @backingInt(sym_index)) << 32 | @backingInt(std.elf.R_LARCH.CALL36),
206 .r_addend = @bitCast(addend),
207 }, zo);
208 } else unreachable,
209 .b, .bl => if (lf.cast(.elf2)) |ef| {
210 try ef.addReloc(atom_index, offset, sym_index, addend, .{ .LARCH = .B26 });
211 } else if (lf.cast(.elf)) |ef| {
212 const zo = ef.zigObjectPtr().?;
213 const atom = zo.symbol(@backingInt(atom_index)).atom(ef).?;
214 try atom.addReloc(zcu.gpa, .{
215 .r_offset = offset,
216 .r_info = @as(u64, @backingInt(sym_index)) << 32 | @backingInt(std.elf.R_LARCH.B26),
217 .r_addend = @bitCast(addend),
218 }, zo);
219 } else unreachable,
220 .beq, .bne, .ble, .bgt, .bleu, .bgtu => if (lf.cast(.elf2)) |ef| {
221 try ef.addReloc(atom_index, offset, sym_index, addend, .{ .LARCH = .B16 });
222 } else if (lf.cast(.elf)) |ef| {
223 const zo = ef.zigObjectPtr().?;
224 const atom = zo.symbol(@backingInt(atom_index)).atom(ef).?;
225 try atom.addReloc(zcu.gpa, .{
226 .r_offset = offset,
227 .r_info = @as(u64, @backingInt(sym_index)) << 32 | @backingInt(std.elf.R_LARCH.B16),
228 .r_addend = @bitCast(addend),
229 }, zo);
230 } else unreachable,
231 .beqz, .bnez, .bceqz, .bcnez => if (lf.cast(.elf2)) |ef| {
232 try ef.addReloc(atom_index, offset, sym_index, addend, .{ .LARCH = .B21 });
233 } else if (lf.cast(.elf)) |ef| {
234 const zo = ef.zigObjectPtr().?;
235 const atom = zo.symbol(@backingInt(atom_index)).atom(ef).?;
236 try atom.addReloc(zcu.gpa, .{
237 .r_offset = offset,
238 .r_info = @as(u64, @backingInt(sym_index)) << 32 | @backingInt(std.elf.R_LARCH.B21),
239 .r_addend = @bitCast(addend),
240 }, zo);
241 } else unreachable,
242 .pcalau12i => if (lf.cast(.elf2)) |ef| {
243 try ef.addReloc(atom_index, offset, sym_index, addend, .{ .LARCH = .PCALA_HI20 });
244 } else if (lf.cast(.elf)) |ef| {
245 const zo = ef.zigObjectPtr().?;
246 const atom = zo.symbol(@backingInt(atom_index)).atom(ef).?;
247 try atom.addReloc(zcu.gpa, .{
248 .r_offset = offset,
249 .r_info = @as(u64, @backingInt(sym_index)) << 32 | @backingInt(std.elf.R_LARCH.PCALA_HI20),
250 .r_addend = @bitCast(addend),
251 }, zo);
252 } else unreachable,
253 .@"addi.d" => if (lf.cast(.elf2)) |ef| {
254 try ef.addReloc(atom_index, offset, sym_index, addend, .{ .LARCH = .PCALA_LO12 });
255 } else if (lf.cast(.elf)) |ef| {
256 const zo = ef.zigObjectPtr().?;
257 const atom = zo.symbol(@backingInt(atom_index)).atom(ef).?;
258 try atom.addReloc(zcu.gpa, .{
259 .r_offset = offset,
260 .r_info = @as(u64, @backingInt(sym_index)) << 32 | @backingInt(std.elf.R_LARCH.PCALA_LO12),
261 .r_addend = @bitCast(addend),
262 }, zo);
263 } else unreachable,
264 }
265}197}
266198
267const Air = @import("../../Air.zig");199const Air = @import("../../Air.zig");
src/codegen/loongarch/Select.zig+111-24
...@@ -101,8 +101,8 @@ pub const Block = struct {...@@ -101,8 +101,8 @@ pub const Block = struct {
101 fn branch(target_block: *Block, isel: *Select) !void {101 fn branch(target_block: *Block, isel: *Select) !void {
102 if (isel.instructions.items.len > target_block.target_label) {102 if (isel.instructions.items.len > target_block.target_label) {
103 try isel.internal_relocs.append(isel.pt.zcu.gpa, .{103 try isel.internal_relocs.append(isel.pt.zcu.gpa, .{
104 .label = @intCast(isel.instructions.items.len),
105 .target = target_block.target_label,104 .target = target_block.target_label,
105 .reloc = .{ .label = @intCast(isel.instructions.items.len), .type = .B26 },
106 });106 });
107 try isel.emit(.b(0, 0));107 try isel.emit(.b(0, 0));
108 }108 }
...@@ -1026,7 +1026,7 @@ pub const Value = struct {...@@ -1026,7 +1026,7 @@ pub const Value = struct {
1026 }1026 }
10271027
1028 /// Defines a value with a register.1028 /// Defines a value with a register.
1029 /// Returned registers are free-ed.1029 /// Returned registers are free-ed and marked as written.
1030 /// Extension unchanged.1030 /// Extension unchanged.
1031 fn defReg(vi: Value.Index, isel: *Select) !?Register.Alias {1031 fn defReg(vi: Value.Index, isel: *Select) !?Register.Alias {
1032 const value = vi.get(isel);1032 const value = vi.get(isel);
...@@ -1449,6 +1449,7 @@ pub const Value = struct {...@@ -1449,6 +1449,7 @@ pub const Value = struct {
1449 .reloc = .{1449 .reloc = .{
1450 .label = @intCast(isel.instructions.items.len),1450 .label = @intCast(isel.instructions.items.len),
1451 .addend = @intCast(total_root_offset),1451 .addend = @intCast(total_root_offset),
1452 .type = .PCALA_LO12,
1452 },1453 },
1453 });1454 });
1454 try isel.emit(.@"addi.d"(ptr_reg, ptr_reg, 0));1455 try isel.emit(.@"addi.d"(ptr_reg, ptr_reg, 0));
...@@ -1460,6 +1461,7 @@ pub const Value = struct {...@@ -1460,6 +1461,7 @@ pub const Value = struct {
1460 .reloc = .{1461 .reloc = .{
1461 .label = @intCast(isel.instructions.items.len),1462 .label = @intCast(isel.instructions.items.len),
1462 .addend = @intCast(total_root_offset),1463 .addend = @intCast(total_root_offset),
1464 .type = .PCALA_HI20,
1463 },1465 },
1464 });1466 });
1465 try isel.emit(.pcalau12i(ptr_reg, 0));1467 try isel.emit(.pcalau12i(ptr_reg, 0));
...@@ -2590,6 +2592,7 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {...@@ -2590,6 +2592,7 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {
2590 .is_named_enum_value,2592 .is_named_enum_value,
2591 .tag_name,2593 .tag_name,
2592 .error_name,2594 .error_name,
2595 .cmp_lte_errors_len,
2593 => {2596 => {
2594 const un_op = air_data[@backingInt(air_inst_index)].un_op;2597 const un_op = air_data[@backingInt(air_inst_index)].un_op;
25952598
...@@ -3163,8 +3166,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -3163,8 +3166,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
3163 const next_repeat_label = instruction.*;3166 const next_repeat_label = instruction.*;
3164 instruction.* = .b(0, 0);3167 instruction.* = .b(0, 0);
3165 try isel.internal_relocs.append(gpa, .{3168 try isel.internal_relocs.append(gpa, .{
3166 .label = repeat_label,
3167 .target = isel.instructions.items.len,3169 .target = isel.instructions.items.len,
3170 .reloc = .{ .label = repeat_label, .type = .B26 },
3168 });3171 });
3169 repeat_label = @bitCast(next_repeat_label);3172 repeat_label = @bitCast(next_repeat_label);
3170 }3173 }
...@@ -3196,8 +3199,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -3196,8 +3199,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
3196 .extension = .zero_ext,3199 .extension = .zero_ext,
3197 });3200 });
3198 try isel.internal_relocs.append(gpa, .{3201 try isel.internal_relocs.append(gpa, .{
3199 .label = @intCast(isel.instructions.items.len),
3200 .target = else_label,3202 .target = else_label,
3203 .reloc = .{ .label = @intCast(isel.instructions.items.len), .type = .B21 },
3201 });3204 });
3202 try isel.emit(.beqz(cond_mat.reg(), 0, 0));3205 try isel.emit(.beqz(cond_mat.reg(), 0, 0));
3203 try cond_mat.finish(isel);3206 try cond_mat.finish(isel);
...@@ -3240,8 +3243,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -3240,8 +3243,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
3240 });3243 });
32413244
3242 try isel.internal_relocs.append(gpa, .{3245 try isel.internal_relocs.append(gpa, .{
3243 .label = @intCast(isel.instructions.items.len),
3244 .target = next_label,3246 .target = next_label,
3247 .reloc = .{ .label = @intCast(isel.instructions.items.len), .type = .B26 },
3245 });3248 });
3246 try isel.emit(.b(0, 0));3249 try isel.emit(.b(0, 0));
32473250
...@@ -3267,8 +3270,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -3267,8 +3270,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
3267 defer isel.freeReg(item_reg);3270 defer isel.freeReg(item_reg);
32683271
3269 try isel.internal_relocs.append(gpa, .{3272 try isel.internal_relocs.append(gpa, .{
3270 .label = @intCast(isel.instructions.items.len),
3271 .target = case_label,3273 .target = case_label,
3274 .reloc = .{ .label = @intCast(isel.instructions.items.len), .type = .B16 },
3272 });3275 });
3273 try isel.emit(.beq(cond_mat.reg(), item_reg, 0));3276 try isel.emit(.beq(cond_mat.reg(), item_reg, 0));
3274 try isel.moveIntImm(item_reg, @bitCast(item_int));3277 try isel.moveIntImm(item_reg, @bitCast(item_int));
...@@ -3322,13 +3325,14 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -3322,13 +3325,14 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
3322 else => unreachable,3325 else => unreachable,
3323 inline .@"extern", .func => |func| .{3326 inline .@"extern", .func => |func| .{
3324 .nav = func.owner_nav,3327 .nav = func.owner_nav,
3325 .reloc = .{ .label = @intCast(isel.instructions.items.len) },3328 .reloc = .{ .label = @intCast(isel.instructions.items.len), .type = .CALL36 },
3326 },3329 },
3327 .ptr => |ptr| .{3330 .ptr => |ptr| .{
3328 .nav = ptr.base_addr.nav,3331 .nav = ptr.base_addr.nav,
3329 .reloc = .{3332 .reloc = .{
3330 .label = @intCast(isel.instructions.items.len),3333 .label = @intCast(isel.instructions.items.len),
3331 .addend = @intCast(ptr.byte_offset),3334 .addend = @intCast(ptr.byte_offset),
3335 .type = .CALL36,
3332 },3336 },
3333 },3337 },
3334 });3338 });
...@@ -3573,6 +3577,26 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -3573,6 +3577,26 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
3573 },3577 },
3574 }) else return isel.fail("unimplemented float", .{});3578 }) else return isel.fail("unimplemented float", .{});
3575 },3579 },
3580 .add_with_overflow, .sub_with_overflow => if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| {
3581 defer res_vi.value.deref(isel);
3582
3583 const ty_pl = air.data(air.inst_index).ty_pl;
3584 const bin_op = isel.air.extraData(Air.Bin, ty_pl.payload).data;
3585 const ty = isel.air.typeOf(bin_op.lhs, ip);
3586 const lhs_vi = try isel.use(bin_op.lhs);
3587 const rhs_vi = try isel.use(bin_op.rhs);
3588 const ty_size = lhs_vi.size(isel);
3589
3590 const wrapped_vi = try res_vi.value.partExact(isel, 0, ty_size);
3591 const overflow_vi = try res_vi.value.partExact(isel, ty_size, 1);
3592 try isel.addOrSubtract(ty, wrapped_vi, switch (air_tag) {
3593 else => unreachable,
3594 .add_with_overflow => .add,
3595 .sub_with_overflow => .sub,
3596 }, lhs_vi, rhs_vi, .{
3597 .overflow = if (try overflow_vi.defReg(isel)) |overflow_ra| .{ .overflow_ra = overflow_ra } else .wrap,
3598 });
3599 },
3576 .not => if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {3600 .not => if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: {
3577 defer res_vi.value.deref(isel);3601 defer res_vi.value.deref(isel);
35783602
...@@ -3676,7 +3700,10 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -3676,7 +3700,10 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
3676 try rhs_mat.finish(isel);3700 try rhs_mat.finish(isel);
3677 try lhs_mat.finish(isel);3701 try lhs_mat.finish(isel);
3678 },3702 },
3679 else => try isel.failUnimplemented("too big {t} {f}", .{ air_tag, isel.fmtType(ty) }),3703 else => {
3704 _ = try res_vi.value.def(isel);
3705 try isel.failUnimplemented("too big {t} {f}", .{ air_tag, isel.fmtType(ty) });
3706 },
3680 }3707 }
3681 } else try isel.failUnimplemented("unimplemented float div", .{});3708 } else try isel.failUnimplemented("unimplemented float div", .{});
3682 },3709 },
...@@ -3734,12 +3761,12 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -3734,12 +3761,12 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
3734 } else if (dst_tag == .float and src_tag == .float) {3761 } else if (dst_tag == .float and src_tag == .float) {
3735 assert(dst_ty.floatBits(isel.target) == src_ty.floatBits(isel.target));3762 assert(dst_ty.floatBits(isel.target) == src_ty.floatBits(isel.target));
3736 try dst_vi.value.defMove(isel, ty_op.operand);3763 try dst_vi.value.defMove(isel, ty_op.operand);
3737 } else if (dst_ty.isAbiInt(zcu) and src_tag == .float) {3764 } else if (dst_ty.isAbiInt(zcu) and src_tag == .float and isel.canUseFprForFloat(src_ty.floatBits(isel.target))) {
3738 const dst_int_info = dst_ty.intInfo(zcu);3765 const dst_int_info = dst_ty.intInfo(zcu);
3739 assert(dst_int_info.bits == src_ty.floatBits(isel.target));3766 assert(dst_int_info.bits == src_ty.floatBits(isel.target));
37403767
3741 try dst_vi.value.reextendToGarbage(isel);3768 try dst_vi.value.reextendToGarbage(isel);
3742 const dst_reg = try dst_vi.value.defRegMod(isel, .fromFloating(dst_int_info.bits)) orelse break :unused;3769 const dst_reg = try dst_vi.value.defRegMod(isel, .fromFloatBits(dst_int_info.bits)) orelse break :unused;
3743 const src_vi = try isel.use(ty_op.operand);3770 const src_vi = try isel.use(ty_op.operand);
3744 const src_mat = try src_vi.matReg(isel);3771 const src_mat = try src_vi.matReg(isel);
3745 const src_reg = src_mat.reg();3772 const src_reg = src_mat.reg();
...@@ -3749,12 +3776,12 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -3749,12 +3776,12 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
3749 64 => .@"movfr2gr.d"(dst_reg, src_reg),3776 64 => .@"movfr2gr.d"(dst_reg, src_reg),
3750 });3777 });
3751 try src_mat.finish(isel);3778 try src_mat.finish(isel);
3752 } else if (dst_tag == .float and src_ty.isAbiInt(zcu)) {3779 } else if (dst_tag == .float and src_ty.isAbiInt(zcu) and isel.canUseFprForFloat(dst_ty.floatBits(isel.target))) {
3753 const src_int_info = src_ty.intInfo(zcu);3780 const src_int_info = src_ty.intInfo(zcu);
3754 assert(dst_ty.floatBits(isel.target) == src_int_info.bits);3781 assert(dst_ty.floatBits(isel.target) == src_int_info.bits);
37553782
3756 try dst_vi.value.reextendToGarbage(isel);3783 try dst_vi.value.reextendToGarbage(isel);
3757 const dst_reg = try dst_vi.value.defRegMod(isel, .fromFloating(src_int_info.bits)) orelse break :unused;3784 const dst_reg = try dst_vi.value.defRegMod(isel, .fromFloatBits(src_int_info.bits)) orelse break :unused;
3758 const src_vi = try isel.use(ty_op.operand);3785 const src_vi = try isel.use(ty_op.operand);
3759 const src_mat = try src_vi.matReg(isel);3786 const src_mat = try src_vi.matReg(isel);
3760 const src_reg = src_mat.reg();3787 const src_reg = src_mat.reg();
...@@ -3896,13 +3923,13 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -3896,13 +3923,13 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
3896 .extension = .zero_ext,3923 .extension = .zero_ext,
3897 });3924 });
3898 try isel.internal_relocs.append(gpa, .{3925 try isel.internal_relocs.append(gpa, .{
3899 .label = @intCast(isel.instructions.items.len),
3900 .target = cmp_label,3926 .target = cmp_label,
3927 .reloc = .{ .label = @intCast(isel.instructions.items.len), .type = .B21 },
3901 });3928 });
3902 try isel.emit(.beqz(lhs_tag_mat.reg(), 0, 0));3929 try isel.emit(.beqz(lhs_tag_mat.reg(), 0, 0));
3903 try isel.internal_relocs.append(gpa, .{3930 try isel.internal_relocs.append(gpa, .{
3904 .label = @intCast(isel.instructions.items.len),
3905 .target = cmp_label,3931 .target = cmp_label,
3932 .reloc = .{ .label = @intCast(isel.instructions.items.len), .type = .B21 },
3906 });3933 });
3907 try isel.emit(.beqz(res_reg, 0, 0));3934 try isel.emit(.beqz(res_reg, 0, 0));
39083935
...@@ -4250,8 +4277,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -4250,8 +4277,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
4250 );4277 );
4251 const error_set_part_mat = try error_set_part_vi.matIntRegZeroExt(isel);4278 const error_set_part_mat = try error_set_part_vi.matIntRegZeroExt(isel);
4252 try isel.internal_relocs.append(gpa, .{4279 try isel.internal_relocs.append(gpa, .{
4253 .label = @intCast(isel.instructions.items.len),
4254 .target = cont_label,4280 .target = cont_label,
4281 .reloc = .{ .label = @intCast(isel.instructions.items.len), .type = .B26 },
4255 });4282 });
4256 try isel.emit(.beqz(error_set_part_mat.reg(), 0, 0));4283 try isel.emit(.beqz(error_set_part_mat.reg(), 0, 0));
4257 try error_set_part_mat.finish(isel);4284 try error_set_part_mat.finish(isel);
...@@ -4288,8 +4315,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -4288,8 +4315,8 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
4288 defer isel.freeReg(tmp_reg);4315 defer isel.freeReg(tmp_reg);
42894316
4290 try isel.internal_relocs.append(gpa, .{4317 try isel.internal_relocs.append(gpa, .{
4291 .label = @intCast(isel.instructions.items.len),
4292 .target = cont_label,4318 .target = cont_label,
4319 .reloc = .{ .label = @intCast(isel.instructions.items.len), .type = .B26 },
4293 });4320 });
4294 try isel.emit(.beqz(tmp_reg, 0, 0));4321 try isel.emit(.beqz(tmp_reg, 0, 0));
42954322
...@@ -5924,6 +5951,9 @@ fn cmp(...@@ -5924,6 +5951,9 @@ fn cmp(
5924 rhs_vi: Value.Index,5951 rhs_vi: Value.Index,
5925) !void {5952) !void {
5926 wip_mir_log.debug(" | # cmp {f}, {t}, {f}, {t}, {f}", .{ isel.fmtType(ty), res_reg, lhs_vi, op, rhs_vi });5953 wip_mir_log.debug(" | # cmp {f}, {t}, {f}, {t}, {f}", .{ isel.fmtType(ty), res_reg, lhs_vi, op, rhs_vi });
5954 const res_lock = isel.tryLockReg(res_reg);
5955 defer res_lock.unlock(isel);
5956
5927 if (!ty.isRuntimeFloat() and !ty.isArrayOrVector(isel.pt.zcu)) {5957 if (!ty.isRuntimeFloat() and !ty.isArrayOrVector(isel.pt.zcu)) {
5928 // integeral comparison5958 // integeral comparison
5929 const int_info: std.builtin.Type.Int = if (ty.toIntern() == .bool_type)5959 const int_info: std.builtin.Type.Int = if (ty.toIntern() == .bool_type)
...@@ -5996,7 +6026,7 @@ const AddOrSubtractOptions = struct {...@@ -5996,7 +6026,7 @@ const AddOrSubtractOptions = struct {
5996 @"unreachable",6026 @"unreachable",
5997 panic: Zcu.SimplePanicId,6027 panic: Zcu.SimplePanicId,
5998 wrap,6028 wrap,
5999 reg: Register,6029 overflow_ra: Register.Alias,
6000 };6030 };
6001};6031};
60026032
...@@ -6011,11 +6041,25 @@ fn addOrSubtract(...@@ -6011,11 +6041,25 @@ fn addOrSubtract(
6011 opts: AddOrSubtractOptions,6041 opts: AddOrSubtractOptions,
6012) !void {6042) !void {
6013 wip_mir_log.debug(" | # {t} ty = {f}, res = {f}, lhs = {f}, rhs = {f}, overflow = {t}", .{ op, isel.fmtType(ty), res_vi, lhs_vi, rhs_vi, opts.overflow });6043 wip_mir_log.debug(" | # {t} ty = {f}, res = {f}, lhs = {f}, rhs = {f}, overflow = {t}", .{ op, isel.fmtType(ty), res_vi, lhs_vi, rhs_vi, opts.overflow });
6014 // TODO: implement opts.overflow
6015 const zcu = isel.pt.zcu;6044 const zcu = isel.pt.zcu;
6016 assert(ty.isAbiInt(zcu));6045 assert(ty.isAbiInt(zcu));
6017 const int_info = ty.intInfo(zcu);6046 const int_info = ty.intInfo(zcu);
60186047
6048 switch (opts.overflow) {
6049 .wrap, .@"unreachable" => {},
6050 .overflow_ra => |overflow_ra| {
6051 const overflow_reg = if (overflow_ra.mod == .integer) overflow_ra.reg else try isel.allocRegForWrite(.int);
6052 defer if (overflow_ra.mod != .integer) isel.freeReg(overflow_reg);
6053 switch (op) {
6054 .add => try isel.cmp(overflow_reg, ty, res_vi, .lt, lhs_vi),
6055 .sub => try isel.cmp(overflow_reg, ty, res_vi, .gt, lhs_vi),
6056 }
6057 },
6058 .panic => {
6059 try isel.failUnimplemented("unimplemented {t} with {t}", .{ op, opts.overflow });
6060 },
6061 }
6062
6019 if (int_info.bits <= 32) {6063 if (int_info.bits <= 32) {
6020 try res_vi.reextendToGarbage(isel); // TODO optimize6064 try res_vi.reextendToGarbage(isel); // TODO optimize
6021 const res_reg = try res_vi.defRegMod(isel, .integer) orelse return;6065 const res_reg = try res_vi.defRegMod(isel, .integer) orelse return;
...@@ -6426,6 +6470,7 @@ fn moveConstant(isel: *Select, dst: Value.Location, init_constant: Constant, ini...@@ -6426,6 +6470,7 @@ fn moveConstant(isel: *Select, dst: Value.Location, init_constant: Constant, ini
6426 .reloc = .{6470 .reloc = .{
6427 .label = @intCast(isel.instructions.items.len),6471 .label = @intCast(isel.instructions.items.len),
6428 .addend = @intCast(ptr.byte_offset),6472 .addend = @intCast(ptr.byte_offset),
6473 .type = .PCALA_LO12,
6429 },6474 },
6430 });6475 });
6431 try isel.emit(.@"addi.d"(rd, rd, 0));6476 try isel.emit(.@"addi.d"(rd, rd, 0));
...@@ -6434,6 +6479,7 @@ fn moveConstant(isel: *Select, dst: Value.Location, init_constant: Constant, ini...@@ -6434,6 +6479,7 @@ fn moveConstant(isel: *Select, dst: Value.Location, init_constant: Constant, ini
6434 .reloc = .{6479 .reloc = .{
6435 .label = @intCast(isel.instructions.items.len),6480 .label = @intCast(isel.instructions.items.len),
6436 .addend = @intCast(ptr.byte_offset),6481 .addend = @intCast(ptr.byte_offset),
6482 .type = .PCALA_HI20,
6437 },6483 },
6438 });6484 });
6439 try isel.emit(.pcalau12i(rd, 0));6485 try isel.emit(.pcalau12i(rd, 0));
...@@ -6448,6 +6494,7 @@ fn moveConstant(isel: *Select, dst: Value.Location, init_constant: Constant, ini...@@ -6448,6 +6494,7 @@ fn moveConstant(isel: *Select, dst: Value.Location, init_constant: Constant, ini
6448 .reloc = .{6494 .reloc = .{
6449 .label = @intCast(isel.instructions.items.len),6495 .label = @intCast(isel.instructions.items.len),
6450 .addend = @intCast(ptr.byte_offset),6496 .addend = @intCast(ptr.byte_offset),
6497 .type = .PCALA_LO12,
6451 },6498 },
6452 });6499 });
6453 try isel.emit(.@"addi.d"(rd, rd, 0));6500 try isel.emit(.@"addi.d"(rd, rd, 0));
...@@ -6456,6 +6503,7 @@ fn moveConstant(isel: *Select, dst: Value.Location, init_constant: Constant, ini...@@ -6456,6 +6503,7 @@ fn moveConstant(isel: *Select, dst: Value.Location, init_constant: Constant, ini
6456 .reloc = .{6503 .reloc = .{
6457 .label = @intCast(isel.instructions.items.len),6504 .label = @intCast(isel.instructions.items.len),
6458 .addend = @intCast(ptr.byte_offset),6505 .addend = @intCast(ptr.byte_offset),
6506 .type = .PCALA_HI20,
6459 },6507 },
6460 });6508 });
6461 try isel.emit(.pcalau12i(rd, 0));6509 try isel.emit(.pcalau12i(rd, 0));
...@@ -6711,15 +6759,12 @@ fn moveConstant(isel: *Select, dst: Value.Location, init_constant: Constant, ini...@@ -6711,15 +6759,12 @@ fn moveConstant(isel: *Select, dst: Value.Location, init_constant: Constant, ini
6711 // load constant pointer6759 // load constant pointer
6712 try isel.uav_relocs.append(zcu.gpa, .{6760 try isel.uav_relocs.append(zcu.gpa, .{
6713 .uav = uav,6761 .uav = uav,
6714 .reloc = .{ .label = @intCast(isel.instructions.items.len), .addend = 0 },6762 .reloc = .{ .label = @intCast(isel.instructions.items.len), .type = .PCALA_LO12 },
6715 });6763 });
6716 try isel.emit(.@"addi.d"(tmp_reg, tmp_reg, 0));6764 try isel.emit(.@"addi.d"(tmp_reg, tmp_reg, 0));
6717 try isel.uav_relocs.append(zcu.gpa, .{6765 try isel.uav_relocs.append(zcu.gpa, .{
6718 .uav = uav,6766 .uav = uav,
6719 .reloc = .{6767 .reloc = .{ .label = @intCast(isel.instructions.items.len), .type = .PCALA_HI20 },
6720 .label = @intCast(isel.instructions.items.len),
6721 .addend = 0,
6722 },
6723 });6768 });
6724 try isel.emit(.pcalau12i(tmp_reg, 0));6769 try isel.emit(.pcalau12i(tmp_reg, 0));
67256770
...@@ -6901,6 +6946,7 @@ pub const CallAbiIterator = struct {...@@ -6901,6 +6946,7 @@ pub const CallAbiIterator = struct {
6901 },6946 },
6902 .simple_type => |simple_type| switch (simple_type) {6947 .simple_type => |simple_type| switch (simple_type) {
6903 .f80 => continue :type_key .{ .int_type = .{ .signedness = .unsigned, .bits = 80 } },6948 .f80 => continue :type_key .{ .int_type = .{ .signedness = .unsigned, .bits = 80 } },
6949 .f128 => continue :type_key .{ .int_type = .{ .signedness = .unsigned, .bits = 128 } },
6904 .usize,6950 .usize,
6905 .isize,6951 .isize,
6906 .c_char,6952 .c_char,
...@@ -6918,7 +6964,22 @@ pub const CallAbiIterator = struct {...@@ -6918,7 +6964,22 @@ pub const CallAbiIterator = struct {
6918 .signedness = .unsigned,6964 .signedness = .unsigned,
6919 .bits = zcu.errorSetBits(),6965 .bits = zcu.errorSetBits(),
6920 } },6966 } },
6921 .f16, .f32, .f64, .f128, .c_longdouble => return isel.fail("CallAbiIterator.resolve({t})", .{simple_type}),6967 .f16, .f32, .f64 => {
6968 const bits = ty.floatBits(isel.target);
6969 if (isel.canUseFprForFloat(bits)) {
6970 if (it.allocReg(.fpr)) |reg| {
6971 wip_vi.setHintRegister(isel, reg);
6972 if (bits != 16) {
6973 wip_vi.setHintModifier(isel, .fromFloatBits(bits));
6974 } else {
6975 wip_vi.setHintModifier(isel, .floating32);
6976 }
6977 } else it.assignStack(wip_vi);
6978 } else {
6979 continue :type_key .{ .int_type = .{ .signedness = .unsigned, .bits = bits } };
6980 }
6981 },
6982 .c_longdouble => return isel.fail("CallAbiIterator.resolve({t})", .{simple_type}),
6922 else => return isel.fail("CallAbiIterator.resolve({t})", .{simple_type}),6983 else => return isel.fail("CallAbiIterator.resolve({t})", .{simple_type}),
6923 },6984 },
6924 .struct_type => {6985 .struct_type => {
...@@ -7217,6 +7278,32 @@ fn gprAlignment(isel: *Select) std.mem.Alignment {...@@ -7217,6 +7278,32 @@ fn gprAlignment(isel: *Select) std.mem.Alignment {
7217 };7278 };
7218}7279}
72197280
7281fn fprBits(isel: *Select) u7 {
7282 const cpu = &isel.target.cpu;
7283 if (cpu.has(.loongarch, .d)) {
7284 return 64;
7285 } else if (cpu.has(.loongarch, .f)) {
7286 return 32;
7287 } else {
7288 return 0;
7289 }
7290}
7291
7292fn vectorBits(isel: *Select) u7 {
7293 const cpu = &isel.target.cpu;
7294 if (cpu.has(.loongarch, .lasx)) {
7295 return 256;
7296 } else if (cpu.has(.loongarch, .lsx)) {
7297 return 128;
7298 } else {
7299 return isel.fprBits();
7300 }
7301}
7302
7303fn canUseFprForFloat(isel: *Select, bits: u16) bool {
7304 return bits <= isel.fprBits();
7305}
7306
7220fn typeOfField(isel: *Select, ty: ZigType, offset: u64) ?ZigType {7307fn typeOfField(isel: *Select, ty: ZigType, offset: u64) ?ZigType {
7221 const zcu = isel.pt.zcu;7308 const zcu = isel.pt.zcu;
7222 const ip = &zcu.intern_pool;7309 const ip = &zcu.intern_pool;
src/codegen/loongarch/bits.zig+1-1
...@@ -85,7 +85,7 @@ pub const Register = enum(u7) {...@@ -85,7 +85,7 @@ pub const Register = enum(u7) {
85 };85 };
86 }86 }
8787
88 pub fn fromFloating(bits: u16) Modifier {88 pub fn fromFloatBits(bits: u16) Modifier {
89 return switch (bits) {89 return switch (bits) {
90 else => unreachable,90 else => unreachable,
91 32 => .floating32,91 32 => .floating32,