Skip to content

Commit 738c12a

Browse files
committed
loongarch64: implement try
1 parent 8124753 commit 738c12a

File tree

2 files changed

+106
-14
lines changed

2 files changed

+106
-14
lines changed

src/arch/loongarch64/CodeGen.zig

Lines changed: 100 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1926,6 +1926,9 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
19261926
.wrap_errunion_payload => try cg.airWrapErrUnionPayload(inst),
19271927
.wrap_errunion_err => try cg.airWrapErrUnionErr(inst),
19281928

1929+
.@"try", .try_cold => try cg.airTry(inst),
1930+
.try_ptr, .try_ptr_cold => try cg.airTryPtr(inst),
1931+
19291932
.unreach => {},
19301933

19311934
.intcast_safe,
@@ -2323,6 +2326,7 @@ fn genCopy(cg: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: Cop
23232326
const zcu = cg.pt.zcu;
23242327
if (!ty.hasRuntimeBits(zcu)) return;
23252328

2329+
log.debug("copying {} to {} ({}, safety = {})", .{ src_mcv, dst_mcv, ty.fmt(cg.pt), opts.safety });
23262330
switch (dst_mcv) {
23272331
.register => |reg| try cg.genCopyToReg(.fromByteSize(ty.abiSize(zcu)), reg, src_mcv, opts),
23282332
inline .register_pair, .register_triple, .register_quadruple => |regs| {
@@ -2602,6 +2606,7 @@ const Select = struct {
26022606
}
26032607

26042608
fn finish(sel: *Select, result: Temp) !void {
2609+
cg_select_log.debug("select finished: {}", .{result});
26052610
if (sel.inst) |inst| {
26062611
try result.finish(inst, sel.ops[0..sel.ops_count], sel.cg);
26072612
}
@@ -3615,10 +3620,7 @@ fn airBitCast(cg: *CodeGen, inst: Air.Inst.Index) !void {
36153620
// case 1: no operation needed
36163621
// src and dst must have the same ABI size
36173622
if (try sel.match(.{
3618-
.requirement = src_ty.abiSize(zcu) == dst_ty.abiSize(zcu) and
3619-
((dst_ty.isAbiInt(zcu) and src_ty.isAbiInt(zcu)) or
3620-
src_ty.isPtrAtRuntime(zcu) or
3621-
dst_ty.isPtrAtRuntime(zcu)),
3623+
.requirement = src_ty.abiSize(zcu) == dst_ty.abiSize(zcu),
36223624
.patterns = &.{.{ .srcs = &.{.any} }},
36233625
})) {
36243626
const src = sel.ops[0];
@@ -3692,9 +3694,9 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !void {
36923694
} else return sel.fail();
36933695
}
36943696

3695-
fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, inverted: bool) !void {
3696-
const un_op = cg.getAirData(inst).un_op;
3697-
var sel = Select.init(cg, inst, &try cg.tempsFromOperands(inst, .{un_op}));
3697+
/// Checks if a error union value is error. Returns only register values.
3698+
fn genIsErr(cg: *CodeGen, eu: Temp, reuse: bool, inverted: bool) !Temp {
3699+
var sel = Select.init(cg, null, &.{eu});
36983700

36993701
// case 1: error is in register
37003702
if (try sel.match(.{
@@ -3707,17 +3709,19 @@ fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, inverted: bool) !void {
37073709
const src_mcv = src.tracking(cg);
37083710
const err_reg = src_mcv.getRegs()[0];
37093711
const dst = dst: {
3710-
if (cg.liveness.operandDies(inst, 0)) {
3712+
if (reuse) {
37113713
try src.die(cg);
3712-
break :dst err_reg;
3713-
} else break :dst try cg.allocReg(.bool, inst);
3714+
break :dst try cg.tempInit(.bool, .{ .register = err_reg });
3715+
} else break :dst try cg.tempAlloc(.bool, .{ .use_frame = false });
37143716
};
3717+
const dst_reg = dst.getReg(cg);
37153718

3716-
try cg.asmInst(.sltui(dst, err_reg, 1));
3719+
try cg.asmInst(.sltui(dst_reg, err_reg, 1));
37173720
if (!inverted)
3718-
try cg.asmInst(.xori(dst, dst, 1));
3721+
try cg.asmInst(.xori(dst_reg, dst_reg, 1));
37193722

3720-
try sel.finish(try cg.tempInit(.bool, .{ .register = dst }));
3723+
try sel.finish(dst);
3724+
return dst;
37213725
}
37223726
// case 2: error is in memory
37233727
else if (try sel.match(.{
@@ -3726,7 +3730,7 @@ fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, inverted: bool) !void {
37263730
},
37273731
})) {
37283732
const src = sel.ops[0];
3729-
var limb = try src.getLimb(.bool, 0, cg, cg.liveness.operandDies(inst, 0));
3733+
var limb = try src.getLimb(.bool, 0, cg, reuse);
37303734
while (try limb.moveToRegister(cg, .int, true)) {}
37313735
limb.toType(cg, .bool);
37323736
const limb_reg = limb.getReg(cg);
@@ -3736,9 +3740,18 @@ fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, inverted: bool) !void {
37363740
try cg.asmInst(.xori(limb_reg, limb_reg, 1));
37373741

37383742
try sel.finish(limb);
3743+
return limb;
37393744
} else return sel.fail();
37403745
}
37413746

3747+
fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, inverted: bool) !void {
3748+
const un_op = cg.getAirData(inst).un_op;
3749+
const ops = try cg.tempsFromOperands(inst, .{un_op});
3750+
const reuse = !cg.liveness.operandDies(inst, 0);
3751+
const dst = try cg.genIsErr(ops[0], reuse, inverted);
3752+
try dst.finish(inst, &ops, cg);
3753+
}
3754+
37423755
fn airSlicePtr(cg: *CodeGen, inst: Air.Inst.Index) !void {
37433756
const ty_op = cg.getAirData(inst).ty_op;
37443757
const op = (try cg.tempsFromOperands(inst, .{ty_op.operand}))[0];
@@ -3953,3 +3966,76 @@ fn airWrapErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) !void {
39533966
try eu.write(ops[0], cg, .{ .off = eu_err_off });
39543967
try eu.finish(inst, &ops, cg);
39553968
}
3969+
3970+
fn airTry(cg: *CodeGen, inst: Air.Inst.Index) !void {
3971+
const pl_op = cg.getAirData(inst).pl_op;
3972+
const extra = cg.air.extraData(Air.Try, pl_op.payload);
3973+
const body: []const Air.Inst.Index = @ptrCast(cg.air.extra.items[extra.end..][0..extra.data.body_len]);
3974+
3975+
const operand_ty = cg.typeOf(pl_op.operand);
3976+
const result = try cg.genTry(inst, pl_op.operand, operand_ty, false, body);
3977+
try result.finish(inst, &.{}, cg);
3978+
}
3979+
3980+
fn airTryPtr(cg: *CodeGen, inst: Air.Inst.Index) !void {
3981+
const ty_pl = cg.getAirData(inst).ty_pl;
3982+
const extra = cg.air.extraData(Air.TryPtr, ty_pl.payload);
3983+
const body: []const Air.Inst.Index = @ptrCast(cg.air.extra.items[extra.end..][0..extra.data.body_len]);
3984+
3985+
const operand_ty = cg.typeOf(extra.data.ptr);
3986+
const result = try cg.genTry(inst, extra.data.ptr, operand_ty, true, body);
3987+
try result.finish(inst, &.{}, cg);
3988+
}
3989+
3990+
fn genTry(
3991+
cg: *CodeGen,
3992+
inst: Air.Inst.Index,
3993+
operand: Air.Inst.Ref,
3994+
operand_ty: Type,
3995+
operand_is_ptr: bool,
3996+
body: []const Air.Inst.Index,
3997+
) !Temp {
3998+
const zcu = cg.pt.zcu;
3999+
const liveness_cond_br = cg.liveness.getCondBr(inst);
4000+
const ops = try cg.tempsFromOperands(inst, .{operand});
4001+
const reuse_op = !cg.liveness.operandDies(inst, 0);
4002+
4003+
const is_err_temp = if (operand_is_ptr)
4004+
unreachable // TODO
4005+
else
4006+
try cg.genIsErr(ops[0], reuse_op, true);
4007+
const is_err_reg = is_err_temp.getReg(cg);
4008+
4009+
if (!reuse_op)
4010+
try ops[0].die(cg);
4011+
try is_err_temp.die(cg);
4012+
try cg.resetTemps(@enumFromInt(0));
4013+
4014+
const reloc = try cg.asmBr(null, .{ .ne = .{ is_err_reg, .zero } });
4015+
const state = try cg.saveState();
4016+
for (liveness_cond_br.else_deaths) |death| try cg.resolveInst(death).die(cg, death);
4017+
try cg.genBodyBlock(body);
4018+
try cg.restoreState(state, &.{}, .{
4019+
.emit_instructions = false,
4020+
.update_tracking = true,
4021+
.resurrect = true,
4022+
.close_scope = true,
4023+
});
4024+
cg.performReloc(reloc);
4025+
4026+
for (liveness_cond_br.then_deaths) |death| try cg.resolveInst(death).die(cg, death);
4027+
4028+
const payload_ty = operand_ty.errorUnionPayload(zcu);
4029+
const field_off: i32 = @intCast(codegen.errUnionPayloadOffset(payload_ty, zcu));
4030+
const result =
4031+
if (cg.liveness.isUnused(inst))
4032+
try cg.tempInit(payload_ty, .unreach)
4033+
else if (operand_is_ptr)
4034+
unreachable // TODO
4035+
else if (payload_ty.hasRuntimeBitsIgnoreComptime(zcu))
4036+
try ops[0].read(cg, payload_ty, .{ .off = field_off })
4037+
else
4038+
try cg.tempInit(payload_ty, .none);
4039+
4040+
return result;
4041+
}

src/arch/loongarch64/abi.zig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,9 +427,15 @@ pub const CCResolver = struct {
427427
.optional => {
428428
const child_ty = ty.optionalChild(zcu);
429429
if (child_ty.isPtrAtRuntime(zcu)) return self.allocPtr(ctx, max_regs >= 1);
430+
if (ty.optionalReprIsPayload(zcu)) return self.resolveType(child_ty, ctx, max_regs);
430431

431432
// try allocate reg / reg + frame
432433
if (max_regs >= 1) {
434+
if (child_ty.isAbiInt(zcu) and ty.abiSize(zcu) <= 8) {
435+
if (self.allocReg(.int, ctx)) |reg|
436+
return .{ .register = reg };
437+
}
438+
433439
const state = self.state;
434440
if (self.allocReg(.int, ctx)) |reg| {
435441
const child_ccv = try self.resolveType(child_ty, ctx, max_regs - 1);

0 commit comments

Comments
 (0)