authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-06-06 21:27:36+02:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-06-06 21:27:36+02:00
log8ca6dc33d1523061f198474c84a68330085d6667
tree8577475bbf3650c9cfe420a1d3af85db9d070643
parenta34f3ff04a9a6d1c3bf7b818a8de28c453cc53d6
signaturelock-open Commit is signed but in an unrecognized format.

stage2 AArch64: implement `try` AIR instruction


1 files changed, 104 insertions(+), 30 deletions(-)

src/arch/aarch64/CodeGen.zig+104-30
......@@ -665,8 +665,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
665665 .prefetch => try self.airPrefetch(inst),
666666 .mul_add => try self.airMulAdd(inst),
667667
668 .@"try" => @panic("TODO"),
669 .try_ptr => @panic("TODO"),
668 .@"try" => try self.airTry(inst),
669 .try_ptr => try self.airTryPtr(inst),
670670
671671 .dbg_var_ptr,
672672 .dbg_var_val,
......@@ -2308,27 +2308,70 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
23082308 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
23092309}
23102310
2311/// Given an error union, returns the error
2312fn errUnionErr(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCValue {
2313 const err_ty = error_union_ty.errorUnionSet();
2314 const payload_ty = error_union_ty.errorUnionPayload();
2315 if (err_ty.errorSetCardinality() == .zero) {
2316 return MCValue{ .immediate = 0 };
2317 }
2318 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
2319 return error_union_mcv;
2320 }
2321
2322 const err_offset = @intCast(u32, errUnionErrorOffset(payload_ty, self.target.*));
2323 switch (error_union_mcv) {
2324 .register => return self.fail("TODO errUnionErr for registers", .{}),
2325 .stack_offset => |off| {
2326 return MCValue{ .stack_offset = off - err_offset };
2327 },
2328 .memory => |addr| {
2329 return MCValue{ .memory = addr + err_offset };
2330 },
2331 else => unreachable, // invalid MCValue for an error union
2332 }
2333}
2334
23112335fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
23122336 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
23132337 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
23142338 const error_union_ty = self.air.typeOf(ty_op.operand);
2315 const payload_ty = error_union_ty.errorUnionPayload();
23162339 const mcv = try self.resolveInst(ty_op.operand);
2317 if (!payload_ty.hasRuntimeBits()) break :result mcv;
2318
2319 return self.fail("TODO implement unwrap error union error for non-empty payloads", .{});
2340 break :result try self.errUnionErr(mcv, error_union_ty);
23202341 };
23212342 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
23222343}
23232344
2345/// Given an error union, returns the payload
2346fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCValue {
2347 const err_ty = error_union_ty.errorUnionSet();
2348 const payload_ty = error_union_ty.errorUnionPayload();
2349 if (err_ty.errorSetCardinality() == .zero) {
2350 return error_union_mcv;
2351 }
2352 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
2353 return MCValue.none;
2354 }
2355
2356 const payload_offset = @intCast(u32, errUnionPayloadOffset(payload_ty, self.target.*));
2357 switch (error_union_mcv) {
2358 .register => return self.fail("TODO errUnionPayload for registers", .{}),
2359 .stack_offset => |off| {
2360 return MCValue{ .stack_offset = off - payload_offset };
2361 },
2362 .memory => |addr| {
2363 return MCValue{ .memory = addr + payload_offset };
2364 },
2365 else => unreachable, // invalid MCValue for an error union
2366 }
2367}
2368
23242369fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {
23252370 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
23262371 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
23272372 const error_union_ty = self.air.typeOf(ty_op.operand);
2328 const payload_ty = error_union_ty.errorUnionPayload();
2329 if (!payload_ty.hasRuntimeBits()) break :result MCValue.none;
2330
2331 return self.fail("TODO implement unwrap error union payload for non-empty payloads", .{});
2373 const error_union = try self.resolveInst(ty_op.operand);
2374 break :result try self.errUnionPayload(error_union, error_union_ty);
23322375 };
23332376 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
23342377}
......@@ -3389,45 +3432,38 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
33893432 return self.finishAir(inst, .dead, .{ operand, .none, .none });
33903433}
33913434
3392fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
3393 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
3394 const cond = try self.resolveInst(pl_op.operand);
3395 const extra = self.air.extraData(Air.CondBr, pl_op.payload);
3396 const then_body = self.air.extra[extra.end..][0..extra.data.then_body_len];
3397 const else_body = self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
3398 const liveness_condbr = self.liveness.getCondBr(inst);
3399
3400 const reloc: Mir.Inst.Index = switch (cond) {
3435fn condBr(self: *Self, condition: MCValue) !Mir.Inst.Index {
3436 switch (condition) {
34013437 .compare_flags_signed,
34023438 .compare_flags_unsigned,
3403 => try self.addInst(.{
3439 => return try self.addInst(.{
34043440 .tag = .b_cond,
34053441 .data = .{
34063442 .inst_cond = .{
34073443 .inst = undefined, // populated later through performReloc
3408 .cond = switch (cond) {
3444 .cond = switch (condition) {
34093445 .compare_flags_signed => |cmp_op| blk: {
34103446 // Here we map to the opposite condition because the jump is to the false branch.
3411 const condition = Instruction.Condition.fromCompareOperatorSigned(cmp_op);
3412 break :blk condition.negate();
3447 const condition_code = Instruction.Condition.fromCompareOperatorSigned(cmp_op);
3448 break :blk condition_code.negate();
34133449 },
34143450 .compare_flags_unsigned => |cmp_op| blk: {
34153451 // Here we map to the opposite condition because the jump is to the false branch.
3416 const condition = Instruction.Condition.fromCompareOperatorUnsigned(cmp_op);
3417 break :blk condition.negate();
3452 const condition_code = Instruction.Condition.fromCompareOperatorUnsigned(cmp_op);
3453 break :blk condition_code.negate();
34183454 },
34193455 else => unreachable,
34203456 },
34213457 },
34223458 },
34233459 }),
3424 else => blk: {
3425 const reg = switch (cond) {
3460 else => {
3461 const reg = switch (condition) {
34263462 .register => |r| r,
3427 else => try self.copyToTmpRegister(Type.bool, cond),
3463 else => try self.copyToTmpRegister(Type.bool, condition),
34283464 };
34293465
3430 break :blk try self.addInst(.{
3466 return try self.addInst(.{
34313467 .tag = .cbz,
34323468 .data = .{
34333469 .r_inst = .{
......@@ -3437,7 +3473,18 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
34373473 },
34383474 });
34393475 },
3440 };
3476 }
3477}
3478
3479fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
3480 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
3481 const cond = try self.resolveInst(pl_op.operand);
3482 const extra = self.air.extraData(Air.CondBr, pl_op.payload);
3483 const then_body = self.air.extra[extra.end..][0..extra.data.then_body_len];
3484 const else_body = self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
3485 const liveness_condbr = self.liveness.getCondBr(inst);
3486
3487 const reloc = try self.condBr(cond);
34413488
34423489 // If the condition dies here in this condbr instruction, process
34433490 // 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 {
44694516 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, pl_op.operand });
44704517}
44714518
4519fn airTry(self: *Self, inst: Air.Inst.Index) !void {
4520 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
4521 const extra = self.air.extraData(Air.Try, pl_op.payload);
4522 const body = self.air.extra[extra.end..][0..extra.data.body_len];
4523 const result: MCValue = result: {
4524 const error_union_ty = self.air.typeOf(pl_op.operand);
4525 const error_union = try self.resolveInst(pl_op.operand);
4526 const is_err_result = try self.isErr(error_union_ty, error_union);
4527 const reloc = try self.condBr(is_err_result);
4528
4529 try self.genBody(body);
4530
4531 try self.performReloc(reloc);
4532 break :result try self.errUnionPayload(error_union, error_union_ty);
4533 };
4534 return self.finishAir(inst, result, .{ pl_op.operand, .none, .none });
4535}
4536
4537fn airTryPtr(self: *Self, inst: Air.Inst.Index) !void {
4538 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
4539 const extra = self.air.extraData(Air.TryPtr, ty_pl.payload);
4540 const body = self.air.extra[extra.end..][0..extra.data.body_len];
4541 _ = body;
4542 return self.fail("TODO implement airTryPtr for arm", .{});
4543 // return self.finishAir(inst, result, .{ extra.data.ptr, .none, .none });
4544}
4545
44724546fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
44734547 // First section of indexes correspond to a set number of constant values.
44744548 const ref_int = @enumToInt(inst);