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 {...@@ -749,6 +749,12 @@ pub const DeclGen = struct {
749 const error_type = ty.errorUnionSet();749 const error_type = ty.errorUnionSet();
750 const payload_type = ty.errorUnionPayload();750 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
752 if (!payload_type.hasRuntimeBits()) {758 if (!payload_type.hasRuntimeBits()) {
753 // We use the error type directly as the type.759 // We use the error type directly as the type.
754 const err_val = if (val.errorUnionIsPayload()) Value.initTag(.zero) else val;760 const err_val = if (val.errorUnionIsPayload()) Value.initTag(.zero) else val;
...@@ -894,10 +900,12 @@ pub const DeclGen = struct {...@@ -894,10 +900,12 @@ pub const DeclGen = struct {
894 try w.writeAll("ZIG_COLD ");900 try w.writeAll("ZIG_COLD ");
895 }901 }
896 }902 }
897 const return_ty = dg.decl.ty.fnReturnType();903 const fn_info = dg.decl.ty.fnInfo();
898 if (return_ty.hasRuntimeBits()) {904 if (fn_info.return_type.hasRuntimeBits()) {
899 try dg.renderType(w, return_ty);905 try dg.renderType(w, fn_info.return_type);
900 } else if (return_ty.zigTypeTag() == .NoReturn) {906 } else if (fn_info.return_type.isError()) {
907 try dg.renderType(w, Type.anyerror);
908 } else if (fn_info.return_type.zigTypeTag() == .NoReturn) {
901 try w.writeAll("zig_noreturn void");909 try w.writeAll("zig_noreturn void");
902 } else {910 } else {
903 try w.writeAll("void");911 try w.writeAll("void");
...@@ -905,22 +913,19 @@ pub const DeclGen = struct {...@@ -905,22 +913,19 @@ pub const DeclGen = struct {
905 try w.writeAll(" ");913 try w.writeAll(" ");
906 try dg.renderDeclName(w, dg.decl_index);914 try dg.renderDeclName(w, dg.decl_index);
907 try w.writeAll("(");915 try w.writeAll("(");
908 const param_len = dg.decl.ty.fnParamLen();
909916
910 var index: usize = 0;
911 var params_written: usize = 0;917 var params_written: usize = 0;
912 while (index < param_len) : (index += 1) {918 for (fn_info.param_types) |param_type, index| {
913 const param_type = dg.decl.ty.fnParamType(index);
914 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;919 if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
915 if (params_written > 0) {920 if (params_written > 0) {
916 try w.writeAll(", ");921 try w.writeAll(", ");
917 }922 }
918 const name = CValue{ .arg = index };923 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);
920 params_written += 1;925 params_written += 1;
921 }926 }
922927
923 if (dg.decl.ty.fnIsVarArgs()) {928 if (fn_info.is_var_args) {
924 if (params_written != 0) try w.writeAll(", ");929 if (params_written != 0) try w.writeAll(", ");
925 try w.writeAll("...");930 try w.writeAll("...");
926 } else if (params_written == 0) {931 } else if (params_written == 0) {
...@@ -1156,26 +1161,36 @@ pub const DeclGen = struct {...@@ -1156,26 +1161,36 @@ pub const DeclGen = struct {
1156 }1161 }
11571162
1158 fn renderErrorUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {1163 fn renderErrorUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
1159 const child_type = t.errorUnionPayload();1164 const payload_ty = t.errorUnionPayload();
1160 const err_set_type = t.errorUnionSet();1165 const error_ty = t.errorUnionSet();
11611166
1162 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);1167 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
1163 defer buffer.deinit();1168 defer buffer.deinit();
1164 const bw = buffer.writer();1169 const bw = buffer.writer();
11651170
1166 try bw.writeAll("typedef struct { ");
1167 const payload_name = CValue{ .bytes = "payload" };1171 const payload_name = CValue{ .bytes = "payload" };
1168 try dg.renderTypeAndName(bw, child_type, payload_name, .Mut, 0);1172 const target = dg.module.getTarget();
1169 try bw.writeAll("; uint16_t error; } ");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
1170 const name_index = buffer.items.len;1185 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| {
1172 const func = inf_err_set_payload.data.func;1187 const func = inf_err_set_payload.data.func;
1173 try bw.writeAll("zig_E_");1188 try bw.writeAll("zig_E_");
1174 try dg.renderDeclName(bw, func.owner_decl);1189 try dg.renderDeclName(bw, func.owner_decl);
1175 try bw.writeAll(";\n");1190 try bw.writeAll(";\n");
1176 } else {1191 } else {
1177 try bw.print("zig_E_{s}_{s};\n", .{1192 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),
1179 });1194 });
1180 }1195 }
11811196
...@@ -1359,12 +1374,19 @@ pub const DeclGen = struct {...@@ -1359,12 +1374,19 @@ pub const DeclGen = struct {
1359 return w.writeAll(name);1374 return w.writeAll(name);
1360 },1375 },
1361 .ErrorSet => {1376 .ErrorSet => {
1362 comptime assert(Type.initTag(.anyerror).abiSize(builtin.target) == 2);1377 comptime assert(Type.anyerror.abiSize(builtin.target) == 2);
1363 return w.writeAll("uint16_t");1378 return w.writeAll("uint16_t");
1364 },1379 },
1365 .ErrorUnion => {1380 .ErrorUnion => {
1366 if (t.errorUnionPayload().abiSize(target) == 0) {1381 const error_ty = t.errorUnionSet();
1367 return dg.renderType(w, 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);
1368 }1390 }
13691391
1370 const name = dg.getTypedefName(t) orelse1392 const name = dg.getTypedefName(t) orelse
...@@ -1901,8 +1923,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -1901,8 +1923,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1901 .array_elem_val => try airArrayElemVal(f, inst),1923 .array_elem_val => try airArrayElemVal(f, inst),
19021924
1903 .unwrap_errunion_payload => try airUnwrapErrUnionPay(f, inst, ""),1925 .unwrap_errunion_payload => try airUnwrapErrUnionPay(f, inst, ""),
1904 .unwrap_errunion_err => try airUnwrapErrUnionErr(f, inst),
1905 .unwrap_errunion_payload_ptr => try airUnwrapErrUnionPay(f, inst, "&"),1926 .unwrap_errunion_payload_ptr => try airUnwrapErrUnionPay(f, inst, "&"),
1927 .unwrap_errunion_err => try airUnwrapErrUnionErr(f, inst),
1906 .unwrap_errunion_err_ptr => try airUnwrapErrUnionErr(f, inst),1928 .unwrap_errunion_err_ptr => try airUnwrapErrUnionErr(f, inst),
1907 .wrap_errunion_payload => try airWrapErrUnionPay(f, inst),1929 .wrap_errunion_payload => try airWrapErrUnionPay(f, inst),
1908 .wrap_errunion_err => try airWrapErrUnionErr(f, inst),1930 .wrap_errunion_err => try airWrapErrUnionErr(f, inst),
...@@ -2120,11 +2142,14 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2120,11 +2142,14 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
2120fn airRet(f: *Function, inst: Air.Inst.Index) !CValue {2142fn airRet(f: *Function, inst: Air.Inst.Index) !CValue {
2121 const un_op = f.air.instructions.items(.data)[inst].un_op;2143 const un_op = f.air.instructions.items(.data)[inst].un_op;
2122 const writer = f.object.writer();2144 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()) {
2124 const operand = try f.resolveInst(un_op);2147 const operand = try f.resolveInst(un_op);
2125 try writer.writeAll("return ");2148 try writer.writeAll("return ");
2126 try f.writeCValue(writer, operand);2149 try f.writeCValue(writer, operand);
2127 try writer.writeAll(";\n");2150 try writer.writeAll(";\n");
2151 } else if (ret_ty.isError()) {
2152 try writer.writeAll("return 0;");
2128 } else {2153 } else {
2129 try writer.writeAll("return;\n");2154 try writer.writeAll("return;\n");
2130 }2155 }
...@@ -2136,13 +2161,16 @@ fn airRetLoad(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2136,13 +2161,16 @@ fn airRetLoad(f: *Function, inst: Air.Inst.Index) !CValue {
2136 const writer = f.object.writer();2161 const writer = f.object.writer();
2137 const ptr_ty = f.air.typeOf(un_op);2162 const ptr_ty = f.air.typeOf(un_op);
2138 const ret_ty = ptr_ty.childType();2163 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 {
2140 try writer.writeAll("return;\n");2172 try writer.writeAll("return;\n");
2141 }2173 }
2142 const ptr = try f.resolveInst(un_op);
2143 try writer.writeAll("return *");
2144 try f.writeCValue(writer, ptr);
2145 try writer.writeAll(";\n");
2146 return CValue.none;2174 return CValue.none;
2147}2175}
21482176
...@@ -2713,19 +2741,20 @@ fn airCall(...@@ -2713,19 +2741,20 @@ fn airCall(
2713 .Pointer => callee_ty.childType(),2741 .Pointer => callee_ty.childType(),
2714 else => unreachable,2742 else => unreachable,
2715 };2743 };
2716 const ret_ty = fn_ty.fnReturnType();
2717 const unused_result = f.liveness.isUnused(inst);
2718 const writer = f.object.writer();2744 const writer = f.object.writer();
27192745
2720 var result_local: CValue = .none;2746 const result_local: CValue = r: {
2721 if (unused_result) {2747 if (f.liveness.isUnused(inst)) {
2722 if (ret_ty.hasRuntimeBits()) {2748 if (loweredFnRetTyHasBits(fn_ty)) {
2723 try writer.print("(void)", .{});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;
2724 }2756 }
2725 } else {2757 };
2726 result_local = try f.allocLocal(ret_ty, .Const);
2727 try writer.writeAll(" = ");
2728 }
27292758
2730 callee: {2759 callee: {
2731 known: {2760 known: {
...@@ -3307,7 +3336,8 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3307,7 +3336,8 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
3307 return local;3336 return local;
3308}3337}
33093338
3310// *(E!T) -> E NOT *E3339/// *(E!T) -> E
3340/// Note that the result is never a pointer.
3311fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {3341fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
3312 if (f.liveness.isUnused(inst))3342 if (f.liveness.isUnused(inst))
3313 return CValue.none;3343 return CValue.none;
...@@ -3319,7 +3349,11 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3319,7 +3349,11 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
3319 const operand_ty = f.air.typeOf(ty_op.operand);3349 const operand_ty = f.air.typeOf(ty_op.operand);
33203350
3321 if (operand_ty.zigTypeTag() == .Pointer) {3351 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()) {
3323 return operand;3357 return operand;
3324 }3358 }
3325 const local = try f.allocLocal(inst_ty, .Const);3359 const local = try f.allocLocal(inst_ty, .Const);
...@@ -3328,6 +3362,9 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3328,6 +3362,9 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
3328 try writer.writeAll(";\n");3362 try writer.writeAll(";\n");
3329 return local;3363 return local;
3330 }3364 }
3365 if (operand_ty.errorUnionSet().errorSetCardinality() == .zero) {
3366 return CValue{ .bytes = "0" };
3367 }
3331 if (!operand_ty.errorUnionPayload().hasRuntimeBits()) {3368 if (!operand_ty.errorUnionPayload().hasRuntimeBits()) {
3332 return operand;3369 return operand;
3333 }3370 }
...@@ -3343,7 +3380,7 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3343,7 +3380,7 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
3343 return local;3380 return local;
3344}3381}
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 {
3347 if (f.liveness.isUnused(inst))3384 if (f.liveness.isUnused(inst))
3348 return CValue.none;3385 return CValue.none;
33493386
...@@ -3351,17 +3388,19 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: []cons...@@ -3351,17 +3388,19 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: []cons
3351 const writer = f.object.writer();3388 const writer = f.object.writer();
3352 const operand = try f.resolveInst(ty_op.operand);3389 const operand = try f.resolveInst(ty_op.operand);
3353 const operand_ty = f.air.typeOf(ty_op.operand);3390 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;
3359 if (!error_union_ty.errorUnionPayload().hasRuntimeBits()) {3398 if (!error_union_ty.errorUnionPayload().hasRuntimeBits()) {
3360 return CValue.none;3399 return CValue.none;
3361 }3400 }
33623401
3363 const inst_ty = f.air.typeOfIndex(inst);3402 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
3366 const local = try f.allocLocal(inst_ty, .Const);3405 const local = try f.allocLocal(inst_ty, .Const);
3367 try writer.print(" = {s}(", .{maybe_addrof});3406 try writer.print(" = {s}(", .{maybe_addrof});
...@@ -3421,6 +3460,11 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3421,6 +3460,11 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
3421 const error_ty = error_union_ty.errorUnionSet();3460 const error_ty = error_union_ty.errorUnionSet();
3422 const payload_ty = error_union_ty.errorUnionPayload();3461 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
3424 // First, set the non-error value.3468 // First, set the non-error value.
3425 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {3469 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
3426 try f.writeCValueDeref(writer, operand);3470 try f.writeCValueDeref(writer, operand);
...@@ -3464,6 +3508,9 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3464,6 +3508,9 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
3464 const operand = try f.resolveInst(ty_op.operand);3508 const operand = try f.resolveInst(ty_op.operand);
34653509
3466 const inst_ty = f.air.typeOfIndex(inst);3510 const inst_ty = f.air.typeOfIndex(inst);
3511 if (inst_ty.errorUnionSet().errorSetCardinality() == .zero) {
3512 return operand;
3513 }
3467 const local = try f.allocLocal(inst_ty, .Const);3514 const local = try f.allocLocal(inst_ty, .Const);
3468 try writer.writeAll(" = { .error = 0, .payload = ");3515 try writer.writeAll(" = { .error = 0, .payload = ");
3469 try f.writeCValue(writer, operand);3516 try f.writeCValue(writer, operand);
...@@ -3486,16 +3533,23 @@ fn airIsErr(...@@ -3486,16 +3533,23 @@ fn airIsErr(
3486 const operand_ty = f.air.typeOf(un_op);3533 const operand_ty = f.air.typeOf(un_op);
3487 const local = try f.allocLocal(Type.initTag(.bool), .Const);3534 const local = try f.allocLocal(Type.initTag(.bool), .Const);
3488 const payload_ty = operand_ty.errorUnionPayload();3535 const payload_ty = operand_ty.errorUnionPayload();
3536 const error_ty = operand_ty.errorUnionSet();
3537
3489 try writer.writeAll(" = ");3538 try writer.writeAll(" = ");
3490 if (is_ptr) {3539
3491 try f.writeCValueDeref(writer, operand);3540 if (error_ty.errorSetCardinality() == .zero) {
3541 try writer.print("0 {s} 0;\n", .{op_str});
3492 } else {3542 } else {
3493 try f.writeCValue(writer, operand);3543 if (is_ptr) {
3494 }3544 try f.writeCValueDeref(writer, operand);
3495 if (payload_ty.hasRuntimeBits()) {3545 } else {
3496 try writer.writeAll(".error");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});
3497 }3552 }
3498 try writer.print(" {s} 0;\n", .{op_str});
3499 return local;3553 return local;
3500}3554}
35013555
...@@ -4129,3 +4183,14 @@ fn intMin(ty: Type, target: std.Target, buf: []u8) []const u8 {...@@ -4129,3 +4183,14 @@ fn intMin(ty: Type, target: std.Target, buf: []u8) []const u8 {
4129 },4183 },
4130 }4184 }
4131}4185}
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}