Commit 845531dde1
Changed files (2)
src
arch
arm
test
stage2
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", .{});
+ 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);
- try self.spillCompareFlagsIfOccupied();
- self.compare_flags_inst = inst;
+ 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 = try self.resolveInst(bin_op.lhs);
- const rhs = try self.resolveInst(bin_op.rhs);
- const result: MCValue = result: {
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 });
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;
+ \\}
+ ,
+ "",
+ );
}
{