authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-23 14:36:21-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-24 15:34:52-07:00
logc97c7f9e3bade44136f2bdf8ec4015f1b1b8303f
tree0495f407107f7ca88b19162da381c7f602ccbb03
parent3a059ebe4c84a1e541bb3b2ccee2e7cc25686a4d

C backend: update to new error union semantics


1 files changed, 117 insertions(+), 52 deletions(-)

src/codegen/c.zig+117-52
......@@ -749,6 +749,12 @@ pub const DeclGen = struct {
749749 const error_type = ty.errorUnionSet();
750750 const payload_type = ty.errorUnionPayload();
751751
752 if (error_type.errorSetCardinality() == .zero) {
753 // We use the payload directly as the type.
754 const payload_val = val.castTag(.eu_payload).?.data;
755 return dg.renderValue(writer, payload_type, payload_val, location);
756 }
757
752758 if (!payload_type.hasRuntimeBits()) {
753759 // We use the error type directly as the type.
754760 const err_val = if (val.errorUnionIsPayload()) Value.initTag(.zero) else val;
......@@ -894,10 +900,12 @@ pub const DeclGen = struct {
894900 try w.writeAll("ZIG_COLD ");
895901 }
896902 }
897 const return_ty = dg.decl.ty.fnReturnType();
898 if (return_ty.hasRuntimeBits()) {
899 try dg.renderType(w, return_ty);
900 } else if (return_ty.zigTypeTag() == .NoReturn) {
903 const fn_info = dg.decl.ty.fnInfo();
904 if (fn_info.return_type.hasRuntimeBits()) {
905 try dg.renderType(w, fn_info.return_type);
906 } else if (fn_info.return_type.isError()) {
907 try dg.renderType(w, Type.anyerror);
908 } else if (fn_info.return_type.zigTypeTag() == .NoReturn) {
901909 try w.writeAll("zig_noreturn void");
902910 } else {
903911 try w.writeAll("void");
......@@ -905,22 +913,19 @@ pub const DeclGen = struct {
905913 try w.writeAll(" ");
906914 try dg.renderDeclName(w, dg.decl_index);
907915 try w.writeAll("(");
908 const param_len = dg.decl.ty.fnParamLen();
909916
910 var index: usize = 0;
911917 var params_written: usize = 0;
912 while (index < param_len) : (index += 1) {
913 const param_type = dg.decl.ty.fnParamType(index);
918 for (fn_info.param_types) |param_type, index| {
914919 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
915920 if (params_written > 0) {
916921 try w.writeAll(", ");
917922 }
918923 const name = CValue{ .arg = index };
919 try dg.renderTypeAndName(w, dg.decl.ty.fnParamType(index), name, .Mut, 0);
924 try dg.renderTypeAndName(w, param_type, name, .Mut, 0);
920925 params_written += 1;
921926 }
922927
923 if (dg.decl.ty.fnIsVarArgs()) {
928 if (fn_info.is_var_args) {
924929 if (params_written != 0) try w.writeAll(", ");
925930 try w.writeAll("...");
926931 } else if (params_written == 0) {
......@@ -1156,26 +1161,36 @@ pub const DeclGen = struct {
11561161 }
11571162
11581163 fn renderErrorUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
1159 const child_type = t.errorUnionPayload();
1160 const err_set_type = t.errorUnionSet();
1164 const payload_ty = t.errorUnionPayload();
1165 const error_ty = t.errorUnionSet();
11611166
11621167 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
11631168 defer buffer.deinit();
11641169 const bw = buffer.writer();
11651170
1166 try bw.writeAll("typedef struct { ");
11671171 const payload_name = CValue{ .bytes = "payload" };
1168 try dg.renderTypeAndName(bw, child_type, payload_name, .Mut, 0);
1169 try bw.writeAll("; uint16_t error; } ");
1172 const target = dg.module.getTarget();
1173 const payload_align = payload_ty.abiAlignment(target);
1174 const error_align = Type.anyerror.abiAlignment(target);
1175 if (error_align > payload_align) {
1176 try bw.writeAll("typedef struct { ");
1177 try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0);
1178 try bw.writeAll("; uint16_t error; } ");
1179 } else {
1180 try bw.writeAll("typedef struct { uint16_t error; ");
1181 try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0);
1182 try bw.writeAll("; } ");
1183 }
1184
11701185 const name_index = buffer.items.len;
1171 if (err_set_type.castTag(.error_set_inferred)) |inf_err_set_payload| {
1186 if (error_ty.castTag(.error_set_inferred)) |inf_err_set_payload| {
11721187 const func = inf_err_set_payload.data.func;
11731188 try bw.writeAll("zig_E_");
11741189 try dg.renderDeclName(bw, func.owner_decl);
11751190 try bw.writeAll(";\n");
11761191 } else {
11771192 try bw.print("zig_E_{s}_{s};\n", .{
1178 typeToCIdentifier(err_set_type, dg.module), typeToCIdentifier(child_type, dg.module),
1193 typeToCIdentifier(error_ty, dg.module), typeToCIdentifier(payload_ty, dg.module),
11791194 });
11801195 }
11811196
......@@ -1359,12 +1374,19 @@ pub const DeclGen = struct {
13591374 return w.writeAll(name);
13601375 },
13611376 .ErrorSet => {
1362 comptime assert(Type.initTag(.anyerror).abiSize(builtin.target) == 2);
1377 comptime assert(Type.anyerror.abiSize(builtin.target) == 2);
13631378 return w.writeAll("uint16_t");
13641379 },
13651380 .ErrorUnion => {
1366 if (t.errorUnionPayload().abiSize(target) == 0) {
1367 return dg.renderType(w, t.errorUnionSet());
1381 const error_ty = t.errorUnionSet();
1382 const payload_ty = t.errorUnionPayload();
1383
1384 if (error_ty.errorSetCardinality() == .zero) {
1385 return dg.renderType(w, payload_ty);
1386 }
1387
1388 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
1389 return dg.renderType(w, Type.anyerror);
13681390 }
13691391
13701392 const name = dg.getTypedefName(t) orelse
......@@ -1901,8 +1923,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
19011923 .array_elem_val => try airArrayElemVal(f, inst),
19021924
19031925 .unwrap_errunion_payload => try airUnwrapErrUnionPay(f, inst, ""),
1904 .unwrap_errunion_err => try airUnwrapErrUnionErr(f, inst),
19051926 .unwrap_errunion_payload_ptr => try airUnwrapErrUnionPay(f, inst, "&"),
1927 .unwrap_errunion_err => try airUnwrapErrUnionErr(f, inst),
19061928 .unwrap_errunion_err_ptr => try airUnwrapErrUnionErr(f, inst),
19071929 .wrap_errunion_payload => try airWrapErrUnionPay(f, inst),
19081930 .wrap_errunion_err => try airWrapErrUnionErr(f, inst),
......@@ -2120,11 +2142,14 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
21202142fn airRet(f: *Function, inst: Air.Inst.Index) !CValue {
21212143 const un_op = f.air.instructions.items(.data)[inst].un_op;
21222144 const writer = f.object.writer();
2123 if (f.air.typeOf(un_op).isFnOrHasRuntimeBitsIgnoreComptime()) {
2145 const ret_ty = f.air.typeOf(un_op);
2146 if (ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) {
21242147 const operand = try f.resolveInst(un_op);
21252148 try writer.writeAll("return ");
21262149 try f.writeCValue(writer, operand);
21272150 try writer.writeAll(";\n");
2151 } else if (ret_ty.isError()) {
2152 try writer.writeAll("return 0;");
21282153 } else {
21292154 try writer.writeAll("return;\n");
21302155 }
......@@ -2136,13 +2161,16 @@ fn airRetLoad(f: *Function, inst: Air.Inst.Index) !CValue {
21362161 const writer = f.object.writer();
21372162 const ptr_ty = f.air.typeOf(un_op);
21382163 const ret_ty = ptr_ty.childType();
2139 if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) {
2164 if (ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) {
2165 const ptr = try f.resolveInst(un_op);
2166 try writer.writeAll("return *");
2167 try f.writeCValue(writer, ptr);
2168 try writer.writeAll(";\n");
2169 } else if (ret_ty.isError()) {
2170 try writer.writeAll("return 0;\n");
2171 } else {
21402172 try writer.writeAll("return;\n");
21412173 }
2142 const ptr = try f.resolveInst(un_op);
2143 try writer.writeAll("return *");
2144 try f.writeCValue(writer, ptr);
2145 try writer.writeAll(";\n");
21462174 return CValue.none;
21472175}
21482176
......@@ -2713,19 +2741,20 @@ fn airCall(
27132741 .Pointer => callee_ty.childType(),
27142742 else => unreachable,
27152743 };
2716 const ret_ty = fn_ty.fnReturnType();
2717 const unused_result = f.liveness.isUnused(inst);
27182744 const writer = f.object.writer();
27192745
2720 var result_local: CValue = .none;
2721 if (unused_result) {
2722 if (ret_ty.hasRuntimeBits()) {
2723 try writer.print("(void)", .{});
2746 const result_local: CValue = r: {
2747 if (f.liveness.isUnused(inst)) {
2748 if (loweredFnRetTyHasBits(fn_ty)) {
2749 try writer.print("(void)", .{});
2750 }
2751 break :r .none;
2752 } else {
2753 const local = try f.allocLocal(fn_ty.fnReturnType(), .Const);
2754 try writer.writeAll(" = ");
2755 break :r local;
27242756 }
2725 } else {
2726 result_local = try f.allocLocal(ret_ty, .Const);
2727 try writer.writeAll(" = ");
2728 }
2757 };
27292758
27302759 callee: {
27312760 known: {
......@@ -3307,7 +3336,8 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
33073336 return local;
33083337}
33093338
3310// *(E!T) -> E NOT *E
3339/// *(E!T) -> E
3340/// Note that the result is never a pointer.
33113341fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
33123342 if (f.liveness.isUnused(inst))
33133343 return CValue.none;
......@@ -3319,7 +3349,11 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
33193349 const operand_ty = f.air.typeOf(ty_op.operand);
33203350
33213351 if (operand_ty.zigTypeTag() == .Pointer) {
3322 if (!operand_ty.childType().errorUnionPayload().hasRuntimeBits()) {
3352 const err_union_ty = operand_ty.childType();
3353 if (err_union_ty.errorUnionSet().errorSetCardinality() == .zero) {
3354 return CValue{ .bytes = "0" };
3355 }
3356 if (!err_union_ty.errorUnionPayload().hasRuntimeBits()) {
33233357 return operand;
33243358 }
33253359 const local = try f.allocLocal(inst_ty, .Const);
......@@ -3328,6 +3362,9 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
33283362 try writer.writeAll(";\n");
33293363 return local;
33303364 }
3365 if (operand_ty.errorUnionSet().errorSetCardinality() == .zero) {
3366 return CValue{ .bytes = "0" };
3367 }
33313368 if (!operand_ty.errorUnionPayload().hasRuntimeBits()) {
33323369 return operand;
33333370 }
......@@ -3343,7 +3380,7 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
33433380 return local;
33443381}
33453382
3346fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: []const u8) !CValue {
3383fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: [*:0]const u8) !CValue {
33473384 if (f.liveness.isUnused(inst))
33483385 return CValue.none;
33493386
......@@ -3351,17 +3388,19 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: []cons
33513388 const writer = f.object.writer();
33523389 const operand = try f.resolveInst(ty_op.operand);
33533390 const operand_ty = f.air.typeOf(ty_op.operand);
3391 const operand_is_ptr = operand_ty.zigTypeTag() == .Pointer;
3392 const error_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;
3393
3394 if (error_union_ty.errorUnionSet().errorSetCardinality() == .zero) {
3395 return operand;
3396 }
33543397
3355 const error_union_ty = if (operand_ty.zigTypeTag() == .Pointer)
3356 operand_ty.childType()
3357 else
3358 operand_ty;
33593398 if (!error_union_ty.errorUnionPayload().hasRuntimeBits()) {
33603399 return CValue.none;
33613400 }
33623401
33633402 const inst_ty = f.air.typeOfIndex(inst);
3364 const maybe_deref = if (operand_ty.zigTypeTag() == .Pointer) "->" else ".";
3403 const maybe_deref = if (operand_is_ptr) "->" else ".";
33653404
33663405 const local = try f.allocLocal(inst_ty, .Const);
33673406 try writer.print(" = {s}(", .{maybe_addrof});
......@@ -3421,6 +3460,11 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
34213460 const error_ty = error_union_ty.errorUnionSet();
34223461 const payload_ty = error_union_ty.errorUnionPayload();
34233462
3463 if (error_ty.errorSetCardinality() == .zero) {
3464 // TODO: write undefined bytes through the pointer here
3465 return operand;
3466 }
3467
34243468 // First, set the non-error value.
34253469 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
34263470 try f.writeCValueDeref(writer, operand);
......@@ -3464,6 +3508,9 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
34643508 const operand = try f.resolveInst(ty_op.operand);
34653509
34663510 const inst_ty = f.air.typeOfIndex(inst);
3511 if (inst_ty.errorUnionSet().errorSetCardinality() == .zero) {
3512 return operand;
3513 }
34673514 const local = try f.allocLocal(inst_ty, .Const);
34683515 try writer.writeAll(" = { .error = 0, .payload = ");
34693516 try f.writeCValue(writer, operand);
......@@ -3486,16 +3533,23 @@ fn airIsErr(
34863533 const operand_ty = f.air.typeOf(un_op);
34873534 const local = try f.allocLocal(Type.initTag(.bool), .Const);
34883535 const payload_ty = operand_ty.errorUnionPayload();
3536 const error_ty = operand_ty.errorUnionSet();
3537
34893538 try writer.writeAll(" = ");
3490 if (is_ptr) {
3491 try f.writeCValueDeref(writer, operand);
3539
3540 if (error_ty.errorSetCardinality() == .zero) {
3541 try writer.print("0 {s} 0;\n", .{op_str});
34923542 } else {
3493 try f.writeCValue(writer, operand);
3494 }
3495 if (payload_ty.hasRuntimeBits()) {
3496 try writer.writeAll(".error");
3543 if (is_ptr) {
3544 try f.writeCValueDeref(writer, operand);
3545 } else {
3546 try f.writeCValue(writer, operand);
3547 }
3548 if (payload_ty.hasRuntimeBits()) {
3549 try writer.writeAll(".error");
3550 }
3551 try writer.print(" {s} 0;\n", .{op_str});
34973552 }
3498 try writer.print(" {s} 0;\n", .{op_str});
34993553 return local;
35003554}
35013555
......@@ -4129,3 +4183,14 @@ fn intMin(ty: Type, target: std.Target, buf: []u8) []const u8 {
41294183 },
41304184 }
41314185}
4186
4187fn loweredFnRetTyHasBits(fn_ty: Type) bool {
4188 const ret_ty = fn_ty.fnReturnType();
4189 if (ret_ty.hasRuntimeBitsIgnoreComptime()) {
4190 return true;
4191 }
4192 if (ret_ty.isError()) {
4193 return true;
4194 }
4195 return false;
4196}