diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index a607ce54fda3538548ff5ae12414dbe0831433c8..d1c7c7ecf0be3758a3cc52fbca5013770d850de8 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -1099,15 +1099,22 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { 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 return self.fail("TODO implement unwrap error union error for {}", .{self.target.cpu.arch}); + 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.hasCodeGenBits()) break :result mcv; + + return self.fail("TODO implement unwrap error union error for non-empty payloads", .{}); + }; return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } 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 err_ty = self.air.typeOf(ty_op.operand); - const payload_ty = err_ty.errorUnionPayload(); + const error_union_ty = self.air.typeOf(ty_op.operand); + const payload_ty = error_union_ty.errorUnionPayload(); if (!payload_ty.hasCodeGenBits()) break :result MCValue.none; return self.fail("TODO implement unwrap error union payload for non-empty payloads", .{}); @@ -2411,19 +2418,26 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { const bin_op = self.air.instructions.items(.data)[inst].bin_op; - if (self.liveness.isUnused(inst)) - return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none }); - const ty = self.air.typeOf(bin_op.lhs); - assert(ty.eql(self.air.typeOf(bin_op.rhs))); - if (ty.zigTypeTag() == .ErrorSet) - return self.fail("TODO implement cmp for errors", .{}); - - try self.spillCompareFlagsIfOccupied(); - self.compare_flags_inst = inst; - - const lhs = try self.resolveInst(bin_op.lhs); - const rhs = try self.resolveInst(bin_op.rhs); - const result: MCValue = result: { + const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { + const lhs = try self.resolveInst(bin_op.lhs); + const rhs = try self.resolveInst(bin_op.rhs); + const lhs_ty = self.air.typeOf(bin_op.lhs); + + if (lhs_ty.abiSize(self.target.*) > 4) { + return self.fail("TODO cmp for types with size > 4", .{}); + } + + const signedness: std.builtin.Signedness = blk: { + // by default we tell the operand type is unsigned (i.e. bools and enum values) + if (lhs_ty.zigTypeTag() != .Int) break :blk .unsigned; + + // incase of an actual integer, we emit the correct signedness + break :blk lhs_ty.intInfo(self.target.*).signedness; + }; + + try self.spillCompareFlagsIfOccupied(); + self.compare_flags_inst = inst; + const lhs_is_register = lhs == .register; const rhs_is_register = rhs == .register; // lhs should always be a register @@ -2457,11 +2471,11 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { // Move the operands to the newly allocated registers const branch = &self.branch_stack.items[self.branch_stack.items.len - 1]; if (lhs_mcv == .register and !lhs_is_register) { - try self.genSetReg(ty, lhs_mcv.register, lhs); + try self.genSetReg(lhs_ty, lhs_mcv.register, lhs); branch.inst_table.putAssumeCapacity(Air.refToIndex(bin_op.lhs).?, lhs); } if (rhs_mcv == .register and !rhs_is_register) { - try self.genSetReg(ty, rhs_mcv.register, rhs); + try self.genSetReg(lhs_ty, rhs_mcv.register, rhs); branch.inst_table.putAssumeCapacity(Air.refToIndex(bin_op.rhs).?, rhs); } @@ -2469,9 +2483,9 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { // The signedness of the integer does not matter for the cmp instruction try self.genArmBinOpCode(undefined, lhs_mcv, rhs_mcv, false, .cmp_eq, undefined); - break :result switch (ty.isSignedInt()) { - true => MCValue{ .compare_flags_signed = op }, - false => MCValue{ .compare_flags_unsigned = op }, + break :result switch (signedness) { + .signed => MCValue{ .compare_flags_signed = op }, + .unsigned => MCValue{ .compare_flags_unsigned = op }, }; }; return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); diff --git a/test/stage2/arm.zig b/test/stage2/arm.zig index 9739c0553a1f6ccb08602f1f6b4adb096577262c..e76847f58a295dcaa9cc9ca6a76d90c240490e95 100644 --- a/test/stage2/arm.zig +++ b/test/stage2/arm.zig @@ -636,6 +636,35 @@ pub fn addCases(ctx: *TestContext) !void { , "Hello, World!\n", ); + + case.addCompareOutput( + \\pub fn main() void { + \\ foo() catch |err| { + \\ assert(err == error.Foo); + \\ assert(err != error.Bar); + \\ assert(err != error.Baz); + \\ }; + \\ bar() catch |err| { + \\ assert(err != error.Foo); + \\ assert(err == error.Bar); + \\ assert(err != error.Baz); + \\ }; + \\} + \\ + \\fn assert(ok: bool) void { + \\ if (!ok) unreachable; + \\} + \\ + \\fn foo() anyerror!void { + \\ return error.Foo; + \\} + \\ + \\fn bar() anyerror!void { + \\ return error.Bar; + \\} + , + "", + ); } {