From a34f3ff04a9a6d1c3bf7b818a8de28c453cc53d6 Mon Sep 17 00:00:00 2001 From: joachimschmidt557 Date: Mon, 6 Jun 2022 12:34:19 +0200 Subject: [PATCH] stage2 ARM: implement `try` AIR instruction --- src/arch/arm/CodeGen.zig | 114 ++++++++++++++++++++++++--------------- 1 file changed, 70 insertions(+), 44 deletions(-) diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 16e4b6e07b..01f3f1ff6a 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -677,8 +677,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, @@ -1837,8 +1837,8 @@ 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 mcv = try self.resolveInst(ty_op.operand); - break :result try self.errUnionPayload(mcv, error_union_ty); + 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 }); } @@ -3705,6 +3705,42 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { return self.finishAir(inst, .dead, .{ operand, .none, .none }); } +/// Given a boolean condition, emit a jump that is taken when that +/// condition is false. +fn condBr(self: *Self, condition: MCValue) !Mir.Inst.Index { + const condition_code: Condition = switch (condition) { + .cpsr_flags => |cond| cond.negate(), + else => blk: { + const reg = switch (condition) { + .register => |r| r, + else => try self.copyToTmpRegister(Type.bool, condition), + }; + + try self.spillCompareFlagsIfOccupied(); + + // cmp reg, 1 + // bne ... + _ = try self.addInst(.{ + .tag = .cmp, + .cond = .al, + .data = .{ .rr_op = .{ + .rd = .r0, + .rn = reg, + .op = Instruction.Operand.imm(1, 0), + } }, + }); + + break :blk .ne; + }, + }; + + return try self.addInst(.{ + .tag = .b, + .cond = condition_code, + .data = .{ .inst = undefined }, // populated later through performReloc + }); +} + fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { const pl_op = self.air.instructions.items(.data)[inst].pl_op; const cond_inst = try self.resolveInst(pl_op.operand); @@ -3713,39 +3749,7 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { 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 = reloc: { - const condition: Condition = switch (cond_inst) { - .cpsr_flags => |cond| cond.negate(), - else => blk: { - const reg = switch (cond_inst) { - .register => |r| r, - else => try self.copyToTmpRegister(Type.bool, cond_inst), - }; - - try self.spillCompareFlagsIfOccupied(); - - // cmp reg, 1 - // bne ... - _ = try self.addInst(.{ - .tag = .cmp, - .cond = .al, - .data = .{ .rr_op = .{ - .rd = .r0, - .rn = reg, - .op = Instruction.Operand.imm(1, 0), - } }, - }); - - break :blk .ne; - }, - }; - - break :reloc try self.addInst(.{ - .tag = .b, - .cond = condition, - .data = .{ .inst = undefined }, // populated later through performReloc - }); - }; + const reloc: Mir.Inst.Index = try self.condBr(cond_inst); // If the condition dies here in this condbr instruction, process // that death now instead of later as this has an effect on @@ -4157,13 +4161,8 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { .lhs = condition, .rhs = item, } }; - const cmp_result = try self.cmp(operands, condition_ty, .neq); - - relocs[0] = try self.addInst(.{ - .tag = .b, - .cond = cmp_result.cpsr_flags, - .data = .{ .inst = undefined }, // populated later through performReloc - }); + const cmp_result = try self.cmp(operands, condition_ty, .eq); + relocs[0] = try self.condBr(cmp_result); } else { return self.fail("TODO switch with multiple items", .{}); } @@ -5148,6 +5147,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);