authorgravatar for jacoblevgw@gmail.comJacob G-W <jacoblevgw@gmail.com> 2021-03-01 15:16:18-05:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-03-08 00:33:59+02:00
log30ffa052f2b53d9a01aedbe672bec3c5e28d5118
tree252ec19b85f0e80e3e7c872d570ef3d4540bec73
parent6467ef6d3b5648d47c13b877d3d4fe6a5b5efb7d
signature Commit is signed but in an unrecognized format.

stage2 cbe: add error union and error union operations


4 files changed, 110 insertions(+), 3 deletions(-)

src/codegen/c.zig+83-2
...@@ -251,6 +251,31 @@ pub const DeclGen = struct {...@@ -251,6 +251,31 @@ pub const DeclGen = struct {
251 // error values will be #defined at the top of the file251 // error values will be #defined at the top of the file
252 return writer.print("zig_error_{s}", .{payload.data.name});252 return writer.print("zig_error_{s}", .{payload.data.name});
253 },253 },
254 .ErrorUnion => {
255 const error_type = t.errorUnionSet();
256 const payload_type = t.errorUnionChild();
257 const data = val.castTag(.error_union).?.data;
258 try writer.writeByte('(');
259 try dg.renderType(writer, t);
260 try writer.writeAll("){");
261 if (val.getError()) |_| {
262 try writer.writeAll(" .error = ");
263 try dg.renderValue(
264 writer,
265 error_type,
266 data,
267 );
268 try writer.writeAll(" }");
269 } else {
270 try writer.writeAll(" .payload = ");
271 try dg.renderValue(
272 writer,
273 payload_type,
274 data,
275 );
276 try writer.writeAll(", .error = 0 }");
277 }
278 },
254 else => |e| return dg.fail(dg.decl.src(), "TODO: C backend: implement value {s}", .{279 else => |e| return dg.fail(dg.decl.src(), "TODO: C backend: implement value {s}", .{
255 @tagName(e),280 @tagName(e),
256 }),281 }),
...@@ -385,16 +410,17 @@ pub const DeclGen = struct {...@@ -385,16 +410,17 @@ pub const DeclGen = struct {
385 return w.writeAll(some.name);410 return w.writeAll(some.name);
386 }411 }
387 const child_type = t.errorUnionChild();412 const child_type = t.errorUnionChild();
413 const set_type = t.errorUnionSet();
388414
389 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);415 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
390 defer buffer.deinit();416 defer buffer.deinit();
391 const bw = buffer.writer();417 const bw = buffer.writer();
392418
393 try bw.writeAll("typedef struct { ");419 try bw.writeAll("typedef struct { ");
394 try dg.renderType(bw, t.errorUnionChild());420 try dg.renderType(bw, child_type);
395 try bw.writeAll(" payload; uint16_t error; } ");421 try bw.writeAll(" payload; uint16_t error; } ");
396 const name_index = buffer.items.len;422 const name_index = buffer.items.len;
397 try bw.print("zig_err_union_{s}_t;\n", .{typeToCIdentifier(child_type)});423 try bw.print("zig_err_union_{s}_{s}_t;\n", .{ typeToCIdentifier(set_type), typeToCIdentifier(child_type) });
398424
399 const rendered = buffer.toOwnedSlice();425 const rendered = buffer.toOwnedSlice();
400 errdefer dg.typedefs.allocator.free(rendered);426 errdefer dg.typedefs.allocator.free(rendered);
...@@ -543,6 +569,12 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi...@@ -543,6 +569,12 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi
543 .optional_payload_ptr => try genOptionalPayload(o, inst.castTag(.optional_payload).?),569 .optional_payload_ptr => try genOptionalPayload(o, inst.castTag(.optional_payload).?),
544 .is_err => try genIsErr(o, inst.castTag(.is_err).?),570 .is_err => try genIsErr(o, inst.castTag(.is_err).?),
545 .is_err_ptr => try genIsErr(o, inst.castTag(.is_err_ptr).?),571 .is_err_ptr => try genIsErr(o, inst.castTag(.is_err_ptr).?),
572 .unwrap_errunion_payload => try genUnwrapErrUnionPay(o, inst.castTag(.unwrap_errunion_payload).?),
573 .unwrap_errunion_err => try genUnwrapErrUnionErr(o, inst.castTag(.unwrap_errunion_err).?),
574 .unwrap_errunion_payload_ptr => try genUnwrapErrUnionPay(o, inst.castTag(.unwrap_errunion_payload_ptr).?),
575 .unwrap_errunion_err_ptr => try genUnwrapErrUnionErr(o, inst.castTag(.unwrap_errunion_err_ptr).?),
576 .wrap_errunion_payload => try genWrapErrUnionPay(o, inst.castTag(.wrap_errunion_payload).?),
577 .wrap_errunion_err => try genWrapErrUnionErr(o, inst.castTag(.wrap_errunion_err).?),
546 else => |e| return o.dg.fail(o.dg.decl.src(), "TODO: C backend: implement codegen for {}", .{e}),578 else => |e| return o.dg.fail(o.dg.decl.src(), "TODO: C backend: implement codegen for {}", .{e}),
547 };579 };
548 switch (result_value) {580 switch (result_value) {
...@@ -962,6 +994,35 @@ fn genOptionalPayload(o: *Object, inst: *Inst.UnOp) !CValue {...@@ -962,6 +994,35 @@ fn genOptionalPayload(o: *Object, inst: *Inst.UnOp) !CValue {
962 return local;994 return local;
963}995}
964996
997// *(E!T) -> E NOT *E
998fn genUnwrapErrUnionErr(o: *Object, inst: *Inst.UnOp) !CValue {
999 const writer = o.writer();
1000 const operand = try o.resolveInst(inst.operand);
1001
1002 const maybe_deref = if (inst.operand.ty.zigTypeTag() == .Pointer) "->" else ".";
1003
1004 const local = try o.allocLocal(inst.base.ty, .Const);
1005 try writer.writeAll(" = (");
1006 try o.writeCValue(writer, operand);
1007
1008 try writer.print("){s}error;\n", .{maybe_deref});
1009 return local;
1010}
1011fn genUnwrapErrUnionPay(o: *Object, inst: *Inst.UnOp) !CValue {
1012 const writer = o.writer();
1013 const operand = try o.resolveInst(inst.operand);
1014
1015 const maybe_deref = if (inst.operand.ty.zigTypeTag() == .Pointer) "->" else ".";
1016 const maybe_addrof = if (inst.base.ty.zigTypeTag() == .Pointer) "&" else "";
1017
1018 const local = try o.allocLocal(inst.base.ty, .Const);
1019 try writer.print(" = {s}(", .{maybe_addrof});
1020 try o.writeCValue(writer, operand);
1021
1022 try writer.print("){s}payload;\n", .{maybe_deref});
1023 return local;
1024}
1025
965fn genWrapOptional(o: *Object, inst: *Inst.UnOp) !CValue {1026fn genWrapOptional(o: *Object, inst: *Inst.UnOp) !CValue {
966 const writer = o.writer();1027 const writer = o.writer();
967 const operand = try o.resolveInst(inst.operand);1028 const operand = try o.resolveInst(inst.operand);
...@@ -978,6 +1039,26 @@ fn genWrapOptional(o: *Object, inst: *Inst.UnOp) !CValue {...@@ -978,6 +1039,26 @@ fn genWrapOptional(o: *Object, inst: *Inst.UnOp) !CValue {
978 try writer.writeAll("};\n");1039 try writer.writeAll("};\n");
979 return local;1040 return local;
980}1041}
1042fn genWrapErrUnionErr(o: *Object, inst: *Inst.UnOp) !CValue {
1043 const writer = o.writer();
1044 const operand = try o.resolveInst(inst.operand);
1045
1046 const local = try o.allocLocal(inst.base.ty, .Const);
1047 try writer.writeAll(" = { .error = ");
1048 try o.writeCValue(writer, operand);
1049 try writer.writeAll(" };\n");
1050 return local;
1051}
1052fn genWrapErrUnionPay(o: *Object, inst: *Inst.UnOp) !CValue {
1053 const writer = o.writer();
1054 const operand = try o.resolveInst(inst.operand);
1055
1056 const local = try o.allocLocal(inst.base.ty, .Const);
1057 try writer.writeAll(" = { .error = 0, .payload = ");
1058 try o.writeCValue(writer, operand);
1059 try writer.writeAll(" };\n");
1060 return local;
1061}
9811062
982fn genIsErr(o: *Object, inst: *Inst.UnOp) !CValue {1063fn genIsErr(o: *Object, inst: *Inst.UnOp) !CValue {
983 const writer = o.writer();1064 const writer = o.writer();
src/link/C.zig+2-1
...@@ -179,7 +179,8 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {...@@ -179,7 +179,8 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {
179 if (module.global_error_set.size == 0) break :render_errors;179 if (module.global_error_set.size == 0) break :render_errors;
180 var it = module.global_error_set.iterator();180 var it = module.global_error_set.iterator();
181 while (it.next()) |entry| {181 while (it.next()) |entry| {
182 try err_typedef_writer.print("#define zig_error_{s} {d}\n", .{ entry.key, entry.value });182 // + 1 because 0 represents no error
183 try err_typedef_writer.print("#define zig_error_{s} {d}\n", .{ entry.key, entry.value + 1 });
183 }184 }
184 try err_typedef_writer.writeByte('\n');185 try err_typedef_writer.writeByte('\n');
185 }186 }
src/type.zig+11
...@@ -1825,6 +1825,17 @@ pub const Type = extern union {...@@ -1825,6 +1825,17 @@ pub const Type = extern union {
1825 };1825 };
1826 }1826 }
18271827
1828 pub fn errorUnionSet(self: Type) Type {
1829 return switch (self.tag()) {
1830 .anyerror_void_error_union => Type.initTag(.anyerror),
1831 .error_union => {
1832 const payload = self.castTag(.error_union).?;
1833 return payload.data.error_set;
1834 },
1835 else => unreachable,
1836 };
1837 }
1838
1828 /// Asserts the type is an array or vector.1839 /// Asserts the type is an array or vector.
1829 pub fn arrayLen(self: Type) u64 {1840 pub fn arrayLen(self: Type) u64 {
1830 return switch (self.tag()) {1841 return switch (self.tag()) {
test/stage2/cbe.zig+14
...@@ -286,6 +286,20 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -286,6 +286,20 @@ pub fn addCases(ctx: *TestContext) !void {
286 \\ if (!b) unreachable;286 \\ if (!b) unreachable;
287 \\}287 \\}
288 , "");288 , "");
289 case.addCompareOutput(
290 \\export fn main() c_int {
291 \\ var e: anyerror!c_int = 0;
292 \\ const i = e catch 69;
293 \\ return i;
294 \\}
295 , "");
296 case.addCompareOutput(
297 \\export fn main() c_int {
298 \\ var e: anyerror!c_int = error.Foo;
299 \\ const i = e catch 69;
300 \\ return 69 - i;
301 \\}
302 , "");
289 }303 }
290 ctx.c("empty start function", linux_x64,304 ctx.c("empty start function", linux_x64,
291 \\export fn _start() noreturn {305 \\export fn _start() noreturn {