stage2 AArch64: implement try AIR instruction

This commit is contained in:
joachimschmidt557 2022-06-06 21:27:36 +02:00
parent a34f3ff04a
commit 8ca6dc33d1
No known key found for this signature in database
GPG Key ID: E0B575BE2884ACC5

View File

@ -665,8 +665,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.prefetch => try self.airPrefetch(inst),
.mul_add => try self.airMulAdd(inst),
.@"try" => @panic("TODO"),
.try_ptr => @panic("TODO"),
.@"try" => try self.airTry(inst),
.try_ptr => try self.airTryPtr(inst),
.dbg_var_ptr,
.dbg_var_val,
@ -2308,27 +2308,70 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
/// Given an error union, returns the error
fn errUnionErr(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCValue {
const err_ty = error_union_ty.errorUnionSet();
const payload_ty = error_union_ty.errorUnionPayload();
if (err_ty.errorSetCardinality() == .zero) {
return MCValue{ .immediate = 0 };
}
if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
return error_union_mcv;
}
const err_offset = @intCast(u32, errUnionErrorOffset(payload_ty, self.target.*));
switch (error_union_mcv) {
.register => return self.fail("TODO errUnionErr for registers", .{}),
.stack_offset => |off| {
return MCValue{ .stack_offset = off - err_offset };
},
.memory => |addr| {
return MCValue{ .memory = addr + err_offset };
},
else => unreachable, // invalid MCValue for an error union
}
}
fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
const error_union_ty = self.air.typeOf(ty_op.operand);
const payload_ty = error_union_ty.errorUnionPayload();
const mcv = try self.resolveInst(ty_op.operand);
if (!payload_ty.hasRuntimeBits()) break :result mcv;
return self.fail("TODO implement unwrap error union error for non-empty payloads", .{});
break :result try self.errUnionErr(mcv, error_union_ty);
};
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
/// Given an error union, returns the payload
fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCValue {
const err_ty = error_union_ty.errorUnionSet();
const payload_ty = error_union_ty.errorUnionPayload();
if (err_ty.errorSetCardinality() == .zero) {
return error_union_mcv;
}
if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
return MCValue.none;
}
const payload_offset = @intCast(u32, errUnionPayloadOffset(payload_ty, self.target.*));
switch (error_union_mcv) {
.register => return self.fail("TODO errUnionPayload for registers", .{}),
.stack_offset => |off| {
return MCValue{ .stack_offset = off - payload_offset };
},
.memory => |addr| {
return MCValue{ .memory = addr + payload_offset };
},
else => unreachable, // invalid MCValue for an error union
}
}
fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
const error_union_ty = self.air.typeOf(ty_op.operand);
const payload_ty = error_union_ty.errorUnionPayload();
if (!payload_ty.hasRuntimeBits()) break :result MCValue.none;
return self.fail("TODO implement unwrap error union payload for non-empty payloads", .{});
const error_union = try self.resolveInst(ty_op.operand);
break :result try self.errUnionPayload(error_union, error_union_ty);
};
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
@ -3389,45 +3432,38 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAir(inst, .dead, .{ operand, .none, .none });
}
fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
const pl_op = self.air.instructions.items(.data)[inst].pl_op;
const cond = try self.resolveInst(pl_op.operand);
const extra = self.air.extraData(Air.CondBr, pl_op.payload);
const then_body = self.air.extra[extra.end..][0..extra.data.then_body_len];
const else_body = self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
const liveness_condbr = self.liveness.getCondBr(inst);
const reloc: Mir.Inst.Index = switch (cond) {
fn condBr(self: *Self, condition: MCValue) !Mir.Inst.Index {
switch (condition) {
.compare_flags_signed,
.compare_flags_unsigned,
=> try self.addInst(.{
=> return try self.addInst(.{
.tag = .b_cond,
.data = .{
.inst_cond = .{
.inst = undefined, // populated later through performReloc
.cond = switch (cond) {
.cond = switch (condition) {
.compare_flags_signed => |cmp_op| blk: {
// Here we map to the opposite condition because the jump is to the false branch.
const condition = Instruction.Condition.fromCompareOperatorSigned(cmp_op);
break :blk condition.negate();
const condition_code = Instruction.Condition.fromCompareOperatorSigned(cmp_op);
break :blk condition_code.negate();
},
.compare_flags_unsigned => |cmp_op| blk: {
// Here we map to the opposite condition because the jump is to the false branch.
const condition = Instruction.Condition.fromCompareOperatorUnsigned(cmp_op);
break :blk condition.negate();
const condition_code = Instruction.Condition.fromCompareOperatorUnsigned(cmp_op);
break :blk condition_code.negate();
},
else => unreachable,
},
},
},
}),
else => blk: {
const reg = switch (cond) {
else => {
const reg = switch (condition) {
.register => |r| r,
else => try self.copyToTmpRegister(Type.bool, cond),
else => try self.copyToTmpRegister(Type.bool, condition),
};
break :blk try self.addInst(.{
return try self.addInst(.{
.tag = .cbz,
.data = .{
.r_inst = .{
@ -3437,7 +3473,18 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
},
});
},
};
}
}
fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
const pl_op = self.air.instructions.items(.data)[inst].pl_op;
const cond = try self.resolveInst(pl_op.operand);
const extra = self.air.extraData(Air.CondBr, pl_op.payload);
const then_body = self.air.extra[extra.end..][0..extra.data.then_body_len];
const else_body = self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
const liveness_condbr = self.liveness.getCondBr(inst);
const reloc = try self.condBr(cond);
// If the condition dies here in this condbr instruction, process
// that death now instead of later as this has an effect on
@ -4469,6 +4516,33 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, pl_op.operand });
}
fn airTry(self: *Self, inst: Air.Inst.Index) !void {
const pl_op = self.air.instructions.items(.data)[inst].pl_op;
const extra = self.air.extraData(Air.Try, pl_op.payload);
const body = self.air.extra[extra.end..][0..extra.data.body_len];
const result: MCValue = result: {
const error_union_ty = self.air.typeOf(pl_op.operand);
const error_union = try self.resolveInst(pl_op.operand);
const is_err_result = try self.isErr(error_union_ty, error_union);
const reloc = try self.condBr(is_err_result);
try self.genBody(body);
try self.performReloc(reloc);
break :result try self.errUnionPayload(error_union, error_union_ty);
};
return self.finishAir(inst, result, .{ pl_op.operand, .none, .none });
}
fn airTryPtr(self: *Self, inst: Air.Inst.Index) !void {
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const extra = self.air.extraData(Air.TryPtr, ty_pl.payload);
const body = self.air.extra[extra.end..][0..extra.data.body_len];
_ = body;
return self.fail("TODO implement airTryPtr for arm", .{});
// return self.finishAir(inst, result, .{ extra.data.ptr, .none, .none });
}
fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
// First section of indexes correspond to a set number of constant values.
const ref_int = @enumToInt(inst);