authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-11-23 15:55:55-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-11-23 15:55:55-05:00
log57e1f6a89f044e731fe60ce15e98b496dcbaa74f
tree53476730474c176f05286b814495da372a23fa62
parent8f1e417757f2172485cdea792580e2a2afb53ffa
parent7ee02b5e70c99159e861cd94adac4707a3315959
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10166 from Scibuild/master

C backend: errors and optionals

4 files changed, 83 insertions(+), 28 deletions(-)

src/codegen/c.zig+56-8
...@@ -1162,12 +1162,13 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -1162,12 +1162,13 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
11621162
1163 .slice => try airSlice(f, inst),1163 .slice => try airSlice(f, inst),
11641164
1165 .cmp_eq => try airBinOp(f, inst, " == "),
1166 .cmp_gt => try airBinOp(f, inst, " > "),1165 .cmp_gt => try airBinOp(f, inst, " > "),
1167 .cmp_gte => try airBinOp(f, inst, " >= "),1166 .cmp_gte => try airBinOp(f, inst, " >= "),
1168 .cmp_lt => try airBinOp(f, inst, " < "),1167 .cmp_lt => try airBinOp(f, inst, " < "),
1169 .cmp_lte => try airBinOp(f, inst, " <= "),1168 .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
1172 // bool_and and bool_or are non-short-circuit operations1173 // bool_and and bool_or are non-short-circuit operations
1173 .bool_and => try airBinOp(f, inst, " & "),1174 .bool_and => try airBinOp(f, inst, " & "),
...@@ -1257,9 +1258,9 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -1257,9 +1258,9 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1257 .slice_elem_ptr => try airSliceElemPtr(f, inst),1258 .slice_elem_ptr => try airSliceElemPtr(f, inst),
1258 .array_elem_val => try airArrayElemVal(f, inst),1259 .array_elem_val => try airArrayElemVal(f, inst),
12591260
1260 .unwrap_errunion_payload => try airUnwrapErrUnionPay(f, inst),1261 .unwrap_errunion_payload => try airUnwrapErrUnionPay(f, inst, ""),
1261 .unwrap_errunion_err => try airUnwrapErrUnionErr(f, inst),1262 .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, "&"),
1263 .unwrap_errunion_err_ptr => try airUnwrapErrUnionErr(f, inst),1264 .unwrap_errunion_err_ptr => try airUnwrapErrUnionErr(f, inst),
1264 .wrap_errunion_payload => try airWrapErrUnionPay(f, inst),1265 .wrap_errunion_payload => try airWrapErrUnionPay(f, inst),
1265 .wrap_errunion_err => try airWrapErrUnionErr(f, inst),1266 .wrap_errunion_err => try airWrapErrUnionErr(f, inst),
...@@ -1908,6 +1909,54 @@ fn airBinOp(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CValue...@@ -1908,6 +1909,54 @@ fn airBinOp(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CValue
1908 return local;1909 return local;
1909}1910}
19101911
1912fn 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
1911fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CValue {1960fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CValue {
1912 if (f.liveness.isUnused(inst))1961 if (f.liveness.isUnused(inst))
1913 return CValue.none;1962 return CValue.none;
...@@ -2104,8 +2153,8 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2104,8 +2153,8 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
21042153
2105 const writer = f.object.writer();2154 const writer = f.object.writer();
2106 const inst_ty = f.air.typeOfIndex(inst);2155 const inst_ty = f.air.typeOfIndex(inst);
2107 if (inst_ty.zigTypeTag() == .Pointer and2156 if (inst_ty.isPtrAtRuntime() and
2108 f.air.typeOf(ty_op.operand).zigTypeTag() == .Pointer)2157 f.air.typeOf(ty_op.operand).isPtrAtRuntime())
2109 {2158 {
2110 const local = try f.allocLocal(inst_ty, .Const);2159 const local = try f.allocLocal(inst_ty, .Const);
2111 try writer.writeAll(" = (");2160 try writer.writeAll(" = (");
...@@ -2503,7 +2552,7 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2503,7 +2552,7 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
2503 return local;2552 return local;
2504}2553}
25052554
2506fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {2555fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: []const u8) !CValue {
2507 if (f.liveness.isUnused(inst))2556 if (f.liveness.isUnused(inst))
2508 return CValue.none;2557 return CValue.none;
25092558
...@@ -2519,7 +2568,6 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2519,7 +2568,6 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
25192568
2520 const inst_ty = f.air.typeOfIndex(inst);2569 const inst_ty = f.air.typeOfIndex(inst);
2521 const maybe_deref = if (operand_ty.zigTypeTag() == .Pointer) "->" else ".";2570 const maybe_deref = if (operand_ty.zigTypeTag() == .Pointer) "->" else ".";
2522 const maybe_addrof = if (inst_ty.zigTypeTag() == .Pointer) "&" else "";
25232571
2524 const local = try f.allocLocal(inst_ty, .Const);2572 const local = try f.allocLocal(inst_ty, .Const);
2525 try writer.print(" = {s}(", .{maybe_addrof});2573 try writer.print(" = {s}(", .{maybe_addrof});
test/behavior.zig+4-1
...@@ -41,6 +41,8 @@ test {...@@ -41,6 +41,8 @@ test {
41 _ = @import("behavior/member_func.zig");41 _ = @import("behavior/member_func.zig");
42 _ = @import("behavior/translate_c_macros.zig");42 _ = @import("behavior/translate_c_macros.zig");
43 _ = @import("behavior/generics.zig");43 _ = @import("behavior/generics.zig");
44 _ = @import("behavior/error.zig");
45 _ = @import("behavior/optional.zig");
4446
45 if (builtin.object_format != .c) {47 if (builtin.object_format != .c) {
46 // Tests that pass for stage1 and stage2 but not the C backend.48 // Tests that pass for stage1 and stage2 but not the C backend.
...@@ -55,6 +57,7 @@ test {...@@ -55,6 +57,7 @@ test {
55 _ = @import("behavior/bugs/2006.zig");57 _ = @import("behavior/bugs/2006.zig");
56 _ = @import("behavior/bugs/3112.zig");58 _ = @import("behavior/bugs/3112.zig");
57 _ = @import("behavior/cast_llvm.zig");59 _ = @import("behavior/cast_llvm.zig");
60 _ = @import("behavior/error.zig");
58 _ = @import("behavior/eval.zig");61 _ = @import("behavior/eval.zig");
59 _ = @import("behavior/floatop.zig");62 _ = @import("behavior/floatop.zig");
60 _ = @import("behavior/fn.zig");63 _ = @import("behavior/fn.zig");
...@@ -63,7 +66,7 @@ test {...@@ -63,7 +66,7 @@ test {
63 _ = @import("behavior/math.zig");66 _ = @import("behavior/math.zig");
64 _ = @import("behavior/maximum_minimum.zig");67 _ = @import("behavior/maximum_minimum.zig");
65 _ = @import("behavior/null_llvm.zig");68 _ = @import("behavior/null_llvm.zig");
66 _ = @import("behavior/optional.zig");69 _ = @import("behavior/optional_llvm.zig");
67 _ = @import("behavior/popcount.zig");70 _ = @import("behavior/popcount.zig");
68 _ = @import("behavior/saturating_arithmetic.zig");71 _ = @import("behavior/saturating_arithmetic.zig");
69 _ = @import("behavior/sizeof_and_typeof.zig");72 _ = @import("behavior/sizeof_and_typeof.zig");
test/behavior/optional.zig-19
...@@ -18,25 +18,6 @@ test "passing an optional integer as a parameter" {...@@ -18,25 +18,6 @@ test "passing an optional integer as a parameter" {
18 comptime try expect(S.entry());18 comptime try expect(S.entry());
19}19}
2020
21test "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
40pub const EmptyStruct = struct {};21pub const EmptyStruct = struct {};
4122
42test "optional pointer to size zero struct" {23test "optional pointer to size zero struct" {
test/behavior/optional_llvm.zig created+23
...@@ -0,0 +1,23 @@
1const std = @import("std");
2const testing = std.testing;
3const expect = testing.expect;
4const expectEqual = testing.expectEqual;
5
6test "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}