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 {
251251 // error values will be #defined at the top of the file
252252 return writer.print("zig_error_{s}", .{payload.data.name});
253253 },
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 },
254279 else => |e| return dg.fail(dg.decl.src(), "TODO: C backend: implement value {s}", .{
255280 @tagName(e),
256281 }),
......@@ -385,16 +410,17 @@ pub const DeclGen = struct {
385410 return w.writeAll(some.name);
386411 }
387412 const child_type = t.errorUnionChild();
413 const set_type = t.errorUnionSet();
388414
389415 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
390416 defer buffer.deinit();
391417 const bw = buffer.writer();
392418
393419 try bw.writeAll("typedef struct { ");
394 try dg.renderType(bw, t.errorUnionChild());
420 try dg.renderType(bw, child_type);
395421 try bw.writeAll(" payload; uint16_t error; } ");
396422 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
399425 const rendered = buffer.toOwnedSlice();
400426 errdefer dg.typedefs.allocator.free(rendered);
......@@ -543,6 +569,12 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi
543569 .optional_payload_ptr => try genOptionalPayload(o, inst.castTag(.optional_payload).?),
544570 .is_err => try genIsErr(o, inst.castTag(.is_err).?),
545571 .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).?),
546578 else => |e| return o.dg.fail(o.dg.decl.src(), "TODO: C backend: implement codegen for {}", .{e}),
547579 };
548580 switch (result_value) {
......@@ -962,6 +994,35 @@ fn genOptionalPayload(o: *Object, inst: *Inst.UnOp) !CValue {
962994 return local;
963995}
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
9651026fn genWrapOptional(o: *Object, inst: *Inst.UnOp) !CValue {
9661027 const writer = o.writer();
9671028 const operand = try o.resolveInst(inst.operand);
......@@ -978,6 +1039,26 @@ fn genWrapOptional(o: *Object, inst: *Inst.UnOp) !CValue {
9781039 try writer.writeAll("};\n");
9791040 return local;
9801041}
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
9821063fn genIsErr(o: *Object, inst: *Inst.UnOp) !CValue {
9831064 const writer = o.writer();
src/link/C.zig+2-1
......@@ -179,7 +179,8 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {
179179 if (module.global_error_set.size == 0) break :render_errors;
180180 var it = module.global_error_set.iterator();
181181 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 });
183184 }
184185 try err_typedef_writer.writeByte('\n');
185186 }
src/type.zig+11
......@@ -1825,6 +1825,17 @@ pub const Type = extern union {
18251825 };
18261826 }
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
18281839 /// Asserts the type is an array or vector.
18291840 pub fn arrayLen(self: Type) u64 {
18301841 return switch (self.tag()) {
test/stage2/cbe.zig+14
......@@ -286,6 +286,20 @@ pub fn addCases(ctx: *TestContext) !void {
286286 \\ if (!b) unreachable;
287287 \\}
288288 , "");
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 , "");
289303 }
290304 ctx.c("empty start function", linux_x64,
291305 \\export fn _start() noreturn {