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
signature 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 {...@@ -665,8 +665,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
665 .prefetch => try self.airPrefetch(inst),665 .prefetch => try self.airPrefetch(inst),
666 .mul_add => try self.airMulAdd(inst),666 .mul_add => try self.airMulAdd(inst),
667667
668 .@"try" => @panic("TODO"),668 .@"try" => try self.airTry(inst),
669 .try_ptr => @panic("TODO"),669 .try_ptr => try self.airTryPtr(inst),
670670
671 .dbg_var_ptr,671 .dbg_var_ptr,
672 .dbg_var_val,672 .dbg_var_val,
...@@ -2308,27 +2308,70 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {...@@ -2308,27 +2308,70 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
2308 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });2308 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2309}2309}
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
2311fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {2335fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
2312 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2336 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2313 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {2337 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2314 const error_union_ty = self.air.typeOf(ty_op.operand);2338 const error_union_ty = self.air.typeOf(ty_op.operand);
2315 const payload_ty = error_union_ty.errorUnionPayload();
2316 const mcv = try self.resolveInst(ty_op.operand);2339 const mcv = try self.resolveInst(ty_op.operand);
2317 if (!payload_ty.hasRuntimeBits()) break :result mcv;2340 break :result try self.errUnionErr(mcv, error_union_ty);
2318
2319 return self.fail("TODO implement unwrap error union error for non-empty payloads", .{});
2320 };2341 };
2321 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });2342 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2322}2343}
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
2324fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {2369fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {
2325 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2370 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2326 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {2371 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2327 const error_union_ty = self.air.typeOf(ty_op.operand);2372 const error_union_ty = self.air.typeOf(ty_op.operand);
2328 const payload_ty = error_union_ty.errorUnionPayload();2373 const error_union = try self.resolveInst(ty_op.operand);
2329 if (!payload_ty.hasRuntimeBits()) break :result MCValue.none;2374 break :result try self.errUnionPayload(error_union, error_union_ty);
2330
2331 return self.fail("TODO implement unwrap error union payload for non-empty payloads", .{});
2332 };2375 };
2333 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });2376 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2334}2377}
...@@ -3389,45 +3432,38 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {...@@ -3389,45 +3432,38 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
3389 return self.finishAir(inst, .dead, .{ operand, .none, .none });3432 return self.finishAir(inst, .dead, .{ operand, .none, .none });
3390}3433}
33913434
3392fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {3435fn condBr(self: *Self, condition: MCValue) !Mir.Inst.Index {
3393 const pl_op = self.air.instructions.items(.data)[inst].pl_op;3436 switch (condition) {
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) {
3401 .compare_flags_signed,3437 .compare_flags_signed,
3402 .compare_flags_unsigned,3438 .compare_flags_unsigned,
3403 => try self.addInst(.{3439 => return try self.addInst(.{
3404 .tag = .b_cond,3440 .tag = .b_cond,
3405 .data = .{3441 .data = .{
3406 .inst_cond = .{3442 .inst_cond = .{
3407 .inst = undefined, // populated later through performReloc3443 .inst = undefined, // populated later through performReloc
3408 .cond = switch (cond) {3444 .cond = switch (condition) {
3409 .compare_flags_signed => |cmp_op| blk: {3445 .compare_flags_signed => |cmp_op| blk: {
3410 // Here we map to the opposite condition because the jump is to the false branch.3446 // Here we map to the opposite condition because the jump is to the false branch.
3411 const condition = Instruction.Condition.fromCompareOperatorSigned(cmp_op);3447 const condition_code = Instruction.Condition.fromCompareOperatorSigned(cmp_op);
3412 break :blk condition.negate();3448 break :blk condition_code.negate();
3413 },3449 },
3414 .compare_flags_unsigned => |cmp_op| blk: {3450 .compare_flags_unsigned => |cmp_op| blk: {
3415 // Here we map to the opposite condition because the jump is to the false branch.3451 // Here we map to the opposite condition because the jump is to the false branch.
3416 const condition = Instruction.Condition.fromCompareOperatorUnsigned(cmp_op);3452 const condition_code = Instruction.Condition.fromCompareOperatorUnsigned(cmp_op);
3417 break :blk condition.negate();3453 break :blk condition_code.negate();
3418 },3454 },
3419 else => unreachable,3455 else => unreachable,
3420 },3456 },
3421 },3457 },
3422 },3458 },
3423 }),3459 }),
3424 else => blk: {3460 else => {
3425 const reg = switch (cond) {3461 const reg = switch (condition) {
3426 .register => |r| r,3462 .register => |r| r,
3427 else => try self.copyToTmpRegister(Type.bool, cond),3463 else => try self.copyToTmpRegister(Type.bool, condition),
3428 };3464 };
34293465
3430 break :blk try self.addInst(.{3466 return try self.addInst(.{
3431 .tag = .cbz,3467 .tag = .cbz,
3432 .data = .{3468 .data = .{
3433 .r_inst = .{3469 .r_inst = .{
...@@ -3437,7 +3473,18 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {...@@ -3437,7 +3473,18 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
3437 },3473 },
3438 });3474 });
3439 },3475 },
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
3442 // If the condition dies here in this condbr instruction, process3489 // If the condition dies here in this condbr instruction, process
3443 // that death now instead of later as this has an effect on3490 // 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 {...@@ -4469,6 +4516,33 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void {
4469 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, pl_op.operand });4516 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, pl_op.operand });
4470}4517}
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
4472fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {4546fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
4473 // First section of indexes correspond to a set number of constant values.4547 // First section of indexes correspond to a set number of constant values.
4474 const ref_int = @enumToInt(inst);4548 const ref_int = @enumToInt(inst);