Skip to content

Commit 2e15a40

Browse files
Scibuildandrewrk
authored andcommitted
C backend: errors and optionals
* bitcast treats all pointers as pointers * correctly unwrapping error unions with pointers * equality operators for primitive optional types
1 parent 8f1e417 commit 2e15a40

File tree

4 files changed

+79
-28
lines changed

4 files changed

+79
-28
lines changed

src/codegen/c.zig

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1162,12 +1162,12 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
11621162

11631163
.slice => try airSlice(f, inst),
11641164

1165-
.cmp_eq => try airBinOp(f, inst, " == "),
1165+
.cmp_eq => try airEquality(f, inst, .cmp_eq),
11661166
.cmp_gt => try airBinOp(f, inst, " > "),
11671167
.cmp_gte => try airBinOp(f, inst, " >= "),
11681168
.cmp_lt => try airBinOp(f, inst, " < "),
11691169
.cmp_lte => try airBinOp(f, inst, " <= "),
1170-
.cmp_neq => try airBinOp(f, inst, " != "),
1170+
.cmp_neq => try airEquality(f, inst, .cmp_neq),
11711171

11721172
// bool_and and bool_or are non-short-circuit operations
11731173
.bool_and => try airBinOp(f, inst, " & "),
@@ -1257,9 +1257,9 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
12571257
.slice_elem_ptr => try airSliceElemPtr(f, inst),
12581258
.array_elem_val => try airArrayElemVal(f, inst),
12591259

1260-
.unwrap_errunion_payload => try airUnwrapErrUnionPay(f, inst),
1260+
.unwrap_errunion_payload => try airUnwrapErrUnionPay(f, inst, ""),
12611261
.unwrap_errunion_err => try airUnwrapErrUnionErr(f, inst),
1262-
.unwrap_errunion_payload_ptr => try airUnwrapErrUnionPay(f, inst),
1262+
.unwrap_errunion_payload_ptr => try airUnwrapErrUnionPay(f, inst, "&"),
12631263
.unwrap_errunion_err_ptr => try airUnwrapErrUnionErr(f, inst),
12641264
.wrap_errunion_payload => try airWrapErrUnionPay(f, inst),
12651265
.wrap_errunion_err => try airWrapErrUnionErr(f, inst),
@@ -1908,6 +1908,51 @@ fn airBinOp(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CValue
19081908
return local;
19091909
}
19101910

1911+
fn airEquality(f: *Function, inst: Air.Inst.Index, op: Air.Inst.Tag) !CValue {
1912+
if (f.liveness.isUnused(inst))
1913+
return CValue.none;
1914+
1915+
const bin_op = f.air.instructions.items(.data)[inst].bin_op;
1916+
const lhs = try f.resolveInst(bin_op.lhs);
1917+
const rhs = try f.resolveInst(bin_op.rhs);
1918+
1919+
const writer = f.object.writer();
1920+
const inst_ty = f.air.typeOfIndex(inst);
1921+
const local = try f.allocLocal(inst_ty, .Const);
1922+
1923+
try writer.writeAll(" = ");
1924+
1925+
const lhs_ty = f.air.typeOf(bin_op.lhs);
1926+
if (lhs_ty.tag() == .optional) {
1927+
// (A && B) || (C && (A == B))
1928+
// A = lhs.is_null ; B = rhs.is_null ; C = rhs.payload == lhs.payload
1929+
1930+
try writer.writeAll(if (op == .cmp_eq) "((" else "!((");
1931+
try f.writeCValue(writer, lhs);
1932+
try writer.writeAll(".is_null && ");
1933+
try f.writeCValue(writer, rhs);
1934+
try writer.writeAll(".is_null) || (");
1935+
try f.writeCValue(writer, lhs);
1936+
try writer.writeAll(".payload == ");
1937+
try f.writeCValue(writer, rhs);
1938+
try writer.writeAll(".payload && ");
1939+
try f.writeCValue(writer, lhs);
1940+
try writer.writeAll(".is_null == ");
1941+
try f.writeCValue(writer, rhs);
1942+
try writer.writeAll(".is_null));\n");
1943+
1944+
return local;
1945+
}
1946+
1947+
const operator = if (op == .cmp_eq) "==" else "!=";
1948+
try f.writeCValue(writer, lhs);
1949+
try writer.print("{s}", .{operator});
1950+
try f.writeCValue(writer, rhs);
1951+
try writer.writeAll(";\n");
1952+
1953+
return local;
1954+
}
1955+
19111956
fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CValue {
19121957
if (f.liveness.isUnused(inst))
19131958
return CValue.none;
@@ -2104,8 +2149,8 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
21042149

21052150
const writer = f.object.writer();
21062151
const inst_ty = f.air.typeOfIndex(inst);
2107-
if (inst_ty.zigTypeTag() == .Pointer and
2108-
f.air.typeOf(ty_op.operand).zigTypeTag() == .Pointer)
2152+
if (inst_ty.isPtrAtRuntime() and
2153+
f.air.typeOf(ty_op.operand).isPtrAtRuntime())
21092154
{
21102155
const local = try f.allocLocal(inst_ty, .Const);
21112156
try writer.writeAll(" = (");
@@ -2503,7 +2548,7 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
25032548
return local;
25042549
}
25052550

2506-
fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
2551+
fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: []const u8) !CValue {
25072552
if (f.liveness.isUnused(inst))
25082553
return CValue.none;
25092554

@@ -2519,7 +2564,6 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
25192564

25202565
const inst_ty = f.air.typeOfIndex(inst);
25212566
const maybe_deref = if (operand_ty.zigTypeTag() == .Pointer) "->" else ".";
2522-
const maybe_addrof = if (inst_ty.zigTypeTag() == .Pointer) "&" else "";
25232567

25242568
const local = try f.allocLocal(inst_ty, .Const);
25252569
try writer.print(" = {s}(", .{maybe_addrof});

test/behavior.zig

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ test {
4141
_ = @import("behavior/member_func.zig");
4242
_ = @import("behavior/translate_c_macros.zig");
4343
_ = @import("behavior/generics.zig");
44+
_ = @import("behavior/error.zig");
45+
_ = @import("behavior/optional.zig");
4446

4547
if (builtin.object_format != .c) {
4648
// Tests that pass for stage1 and stage2 but not the C backend.
@@ -55,6 +57,7 @@ test {
5557
_ = @import("behavior/bugs/2006.zig");
5658
_ = @import("behavior/bugs/3112.zig");
5759
_ = @import("behavior/cast_llvm.zig");
60+
_ = @import("behavior/error.zig");
5861
_ = @import("behavior/eval.zig");
5962
_ = @import("behavior/floatop.zig");
6063
_ = @import("behavior/fn.zig");
@@ -63,7 +66,7 @@ test {
6366
_ = @import("behavior/math.zig");
6467
_ = @import("behavior/maximum_minimum.zig");
6568
_ = @import("behavior/null_llvm.zig");
66-
_ = @import("behavior/optional.zig");
69+
_ = @import("behavior/optional_llvm.zig");
6770
_ = @import("behavior/popcount.zig");
6871
_ = @import("behavior/saturating_arithmetic.zig");
6972
_ = @import("behavior/sizeof_and_typeof.zig");

test/behavior/optional.zig

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,25 +18,6 @@ test "passing an optional integer as a parameter" {
1818
comptime try expect(S.entry());
1919
}
2020

21-
test "self-referential struct through a slice of optional" {
22-
const S = struct {
23-
const Node = struct {
24-
children: []?Node,
25-
data: ?u8,
26-
27-
fn new() Node {
28-
return Node{
29-
.children = undefined,
30-
.data = null,
31-
};
32-
}
33-
};
34-
};
35-
36-
var n = S.Node.new();
37-
try expect(n.data == null);
38-
}
39-
4021
pub const EmptyStruct = struct {};
4122

4223
test "optional pointer to size zero struct" {

test/behavior/optional_llvm.zig

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
const std = @import("std");
2+
const testing = std.testing;
3+
const expect = testing.expect;
4+
const expectEqual = testing.expectEqual;
5+
6+
test "self-referential struct through a slice of optional" {
7+
const S = struct {
8+
const Node = struct {
9+
children: []?Node,
10+
data: ?u8,
11+
12+
fn new() Node {
13+
return Node{
14+
.children = undefined,
15+
.data = null,
16+
};
17+
}
18+
};
19+
};
20+
21+
var n = S.Node.new();
22+
try expect(n.data == null);
23+
}

0 commit comments

Comments
 (0)