Skip to content

Commit 57e1f6a

Browse files
authored
Merge pull request #10166 from Scibuild/master
C backend: errors and optionals
2 parents 8f1e417 + 7ee02b5 commit 57e1f6a

File tree

4 files changed

+83
-28
lines changed

4 files changed

+83
-28
lines changed

src/codegen/c.zig

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1162,12 +1162,13 @@ 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, " == "),
11661165
.cmp_gt => try airBinOp(f, inst, " > "),
11671166
.cmp_gte => try airBinOp(f, inst, " >= "),
11681167
.cmp_lt => try airBinOp(f, inst, " < "),
11691168
.cmp_lte => try airBinOp(f, inst, " <= "),
1170-
.cmp_neq => try airBinOp(f, inst, " != "),
1169+
1170+
.cmp_eq => try airEquality(f, inst, "((", "=="),
1171+
.cmp_neq => try airEquality(f, inst, "!((", "!="),
11711172

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

1260-
.unwrap_errunion_payload => try airUnwrapErrUnionPay(f, inst),
1261+
.unwrap_errunion_payload => try airUnwrapErrUnionPay(f, inst, ""),
12611262
.unwrap_errunion_err => try airUnwrapErrUnionErr(f, inst),
1262-
.unwrap_errunion_payload_ptr => try airUnwrapErrUnionPay(f, inst),
1263+
.unwrap_errunion_payload_ptr => try airUnwrapErrUnionPay(f, inst, "&"),
12631264
.unwrap_errunion_err_ptr => try airUnwrapErrUnionErr(f, inst),
12641265
.wrap_errunion_payload => try airWrapErrUnionPay(f, inst),
12651266
.wrap_errunion_err => try airWrapErrUnionErr(f, inst),
@@ -1908,6 +1909,54 @@ fn airBinOp(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CValue
19081909
return local;
19091910
}
19101911

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

21052154
const writer = f.object.writer();
21062155
const inst_ty = f.air.typeOfIndex(inst);
2107-
if (inst_ty.zigTypeTag() == .Pointer and
2108-
f.air.typeOf(ty_op.operand).zigTypeTag() == .Pointer)
2156+
if (inst_ty.isPtrAtRuntime() and
2157+
f.air.typeOf(ty_op.operand).isPtrAtRuntime())
21092158
{
21102159
const local = try f.allocLocal(inst_ty, .Const);
21112160
try writer.writeAll(" = (");
@@ -2503,7 +2552,7 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
25032552
return local;
25042553
}
25052554

2506-
fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
2555+
fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: []const u8) !CValue {
25072556
if (f.liveness.isUnused(inst))
25082557
return CValue.none;
25092558

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

25202569
const inst_ty = f.air.typeOfIndex(inst);
25212570
const maybe_deref = if (operand_ty.zigTypeTag() == .Pointer) "->" else ".";
2522-
const maybe_addrof = if (inst_ty.zigTypeTag() == .Pointer) "&" else "";
25232571

25242572
const local = try f.allocLocal(inst_ty, .Const);
25252573
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)