diff options
Diffstat (limited to 'src/codegen/c.zig')
| -rw-r--r-- | src/codegen/c.zig | 169 |
1 files changed, 117 insertions, 52 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 5f61f8586e..63082d46be 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -749,6 +749,12 @@ pub const DeclGen = struct { const error_type = ty.errorUnionSet(); const payload_type = ty.errorUnionPayload(); + if (error_type.errorSetCardinality() == .zero) { + // We use the payload directly as the type. + const payload_val = val.castTag(.eu_payload).?.data; + return dg.renderValue(writer, payload_type, payload_val, location); + } + if (!payload_type.hasRuntimeBits()) { // We use the error type directly as the type. const err_val = if (val.errorUnionIsPayload()) Value.initTag(.zero) else val; @@ -894,10 +900,12 @@ pub const DeclGen = struct { try w.writeAll("ZIG_COLD "); } } - const return_ty = dg.decl.ty.fnReturnType(); - if (return_ty.hasRuntimeBits()) { - try dg.renderType(w, return_ty); - } else if (return_ty.zigTypeTag() == .NoReturn) { + const fn_info = dg.decl.ty.fnInfo(); + if (fn_info.return_type.hasRuntimeBits()) { + try dg.renderType(w, fn_info.return_type); + } else if (fn_info.return_type.isError()) { + try dg.renderType(w, Type.anyerror); + } else if (fn_info.return_type.zigTypeTag() == .NoReturn) { try w.writeAll("zig_noreturn void"); } else { try w.writeAll("void"); @@ -905,22 +913,19 @@ pub const DeclGen = struct { try w.writeAll(" "); try dg.renderDeclName(w, dg.decl_index); try w.writeAll("("); - const param_len = dg.decl.ty.fnParamLen(); - var index: usize = 0; var params_written: usize = 0; - while (index < param_len) : (index += 1) { - const param_type = dg.decl.ty.fnParamType(index); + for (fn_info.param_types) |param_type, index| { if (!param_type.hasRuntimeBitsIgnoreComptime()) continue; if (params_written > 0) { try w.writeAll(", "); } const name = CValue{ .arg = index }; - try dg.renderTypeAndName(w, dg.decl.ty.fnParamType(index), name, .Mut, 0); + try dg.renderTypeAndName(w, param_type, name, .Mut, 0); params_written += 1; } - if (dg.decl.ty.fnIsVarArgs()) { + if (fn_info.is_var_args) { if (params_written != 0) try w.writeAll(", "); try w.writeAll("..."); } else if (params_written == 0) { @@ -1156,26 +1161,36 @@ pub const DeclGen = struct { } fn renderErrorUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { - const child_type = t.errorUnionPayload(); - const err_set_type = t.errorUnionSet(); + const payload_ty = t.errorUnionPayload(); + const error_ty = t.errorUnionSet(); var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); defer buffer.deinit(); const bw = buffer.writer(); - try bw.writeAll("typedef struct { "); const payload_name = CValue{ .bytes = "payload" }; - try dg.renderTypeAndName(bw, child_type, payload_name, .Mut, 0); - try bw.writeAll("; uint16_t error; } "); + const target = dg.module.getTarget(); + const payload_align = payload_ty.abiAlignment(target); + const error_align = Type.anyerror.abiAlignment(target); + if (error_align > payload_align) { + try bw.writeAll("typedef struct { "); + try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0); + try bw.writeAll("; uint16_t error; } "); + } else { + try bw.writeAll("typedef struct { uint16_t error; "); + try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0); + try bw.writeAll("; } "); + } + const name_index = buffer.items.len; - if (err_set_type.castTag(.error_set_inferred)) |inf_err_set_payload| { + if (error_ty.castTag(.error_set_inferred)) |inf_err_set_payload| { const func = inf_err_set_payload.data.func; try bw.writeAll("zig_E_"); try dg.renderDeclName(bw, func.owner_decl); try bw.writeAll(";\n"); } else { try bw.print("zig_E_{s}_{s};\n", .{ - typeToCIdentifier(err_set_type, dg.module), typeToCIdentifier(child_type, dg.module), + typeToCIdentifier(error_ty, dg.module), typeToCIdentifier(payload_ty, dg.module), }); } @@ -1359,12 +1374,19 @@ pub const DeclGen = struct { return w.writeAll(name); }, .ErrorSet => { - comptime assert(Type.initTag(.anyerror).abiSize(builtin.target) == 2); + comptime assert(Type.anyerror.abiSize(builtin.target) == 2); return w.writeAll("uint16_t"); }, .ErrorUnion => { - if (t.errorUnionPayload().abiSize(target) == 0) { - return dg.renderType(w, t.errorUnionSet()); + const error_ty = t.errorUnionSet(); + const payload_ty = t.errorUnionPayload(); + + if (error_ty.errorSetCardinality() == .zero) { + return dg.renderType(w, payload_ty); + } + + if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { + return dg.renderType(w, Type.anyerror); } const name = dg.getTypedefName(t) orelse @@ -1901,8 +1923,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO .array_elem_val => try airArrayElemVal(f, inst), .unwrap_errunion_payload => try airUnwrapErrUnionPay(f, inst, ""), - .unwrap_errunion_err => try airUnwrapErrUnionErr(f, inst), .unwrap_errunion_payload_ptr => try airUnwrapErrUnionPay(f, inst, "&"), + .unwrap_errunion_err => try airUnwrapErrUnionErr(f, inst), .unwrap_errunion_err_ptr => try airUnwrapErrUnionErr(f, inst), .wrap_errunion_payload => try airWrapErrUnionPay(f, inst), .wrap_errunion_err => try airWrapErrUnionErr(f, inst), @@ -2120,11 +2142,14 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { fn airRet(f: *Function, inst: Air.Inst.Index) !CValue { const un_op = f.air.instructions.items(.data)[inst].un_op; const writer = f.object.writer(); - if (f.air.typeOf(un_op).isFnOrHasRuntimeBitsIgnoreComptime()) { + const ret_ty = f.air.typeOf(un_op); + if (ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) { const operand = try f.resolveInst(un_op); try writer.writeAll("return "); try f.writeCValue(writer, operand); try writer.writeAll(";\n"); + } else if (ret_ty.isError()) { + try writer.writeAll("return 0;"); } else { try writer.writeAll("return;\n"); } @@ -2136,13 +2161,16 @@ fn airRetLoad(f: *Function, inst: Air.Inst.Index) !CValue { const writer = f.object.writer(); const ptr_ty = f.air.typeOf(un_op); const ret_ty = ptr_ty.childType(); - if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) { + if (ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) { + const ptr = try f.resolveInst(un_op); + try writer.writeAll("return *"); + try f.writeCValue(writer, ptr); + try writer.writeAll(";\n"); + } else if (ret_ty.isError()) { + try writer.writeAll("return 0;\n"); + } else { try writer.writeAll("return;\n"); } - const ptr = try f.resolveInst(un_op); - try writer.writeAll("return *"); - try f.writeCValue(writer, ptr); - try writer.writeAll(";\n"); return CValue.none; } @@ -2713,19 +2741,20 @@ fn airCall( .Pointer => callee_ty.childType(), else => unreachable, }; - const ret_ty = fn_ty.fnReturnType(); - const unused_result = f.liveness.isUnused(inst); const writer = f.object.writer(); - var result_local: CValue = .none; - if (unused_result) { - if (ret_ty.hasRuntimeBits()) { - try writer.print("(void)", .{}); + const result_local: CValue = r: { + if (f.liveness.isUnused(inst)) { + if (loweredFnRetTyHasBits(fn_ty)) { + try writer.print("(void)", .{}); + } + break :r .none; + } else { + const local = try f.allocLocal(fn_ty.fnReturnType(), .Const); + try writer.writeAll(" = "); + break :r local; } - } else { - result_local = try f.allocLocal(ret_ty, .Const); - try writer.writeAll(" = "); - } + }; callee: { known: { @@ -3307,7 +3336,8 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { return local; } -// *(E!T) -> E NOT *E +/// *(E!T) -> E +/// Note that the result is never a pointer. fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { if (f.liveness.isUnused(inst)) return CValue.none; @@ -3319,7 +3349,11 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { const operand_ty = f.air.typeOf(ty_op.operand); if (operand_ty.zigTypeTag() == .Pointer) { - if (!operand_ty.childType().errorUnionPayload().hasRuntimeBits()) { + const err_union_ty = operand_ty.childType(); + if (err_union_ty.errorUnionSet().errorSetCardinality() == .zero) { + return CValue{ .bytes = "0" }; + } + if (!err_union_ty.errorUnionPayload().hasRuntimeBits()) { return operand; } const local = try f.allocLocal(inst_ty, .Const); @@ -3328,6 +3362,9 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { try writer.writeAll(";\n"); return local; } + if (operand_ty.errorUnionSet().errorSetCardinality() == .zero) { + return CValue{ .bytes = "0" }; + } if (!operand_ty.errorUnionPayload().hasRuntimeBits()) { return operand; } @@ -3343,7 +3380,7 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { return local; } -fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: []const u8) !CValue { +fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: [*:0]const u8) !CValue { if (f.liveness.isUnused(inst)) return CValue.none; @@ -3351,17 +3388,19 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: []cons const writer = f.object.writer(); const operand = try f.resolveInst(ty_op.operand); const operand_ty = f.air.typeOf(ty_op.operand); + const operand_is_ptr = operand_ty.zigTypeTag() == .Pointer; + const error_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty; + + if (error_union_ty.errorUnionSet().errorSetCardinality() == .zero) { + return operand; + } - const error_union_ty = if (operand_ty.zigTypeTag() == .Pointer) - operand_ty.childType() - else - operand_ty; if (!error_union_ty.errorUnionPayload().hasRuntimeBits()) { return CValue.none; } const inst_ty = f.air.typeOfIndex(inst); - const maybe_deref = if (operand_ty.zigTypeTag() == .Pointer) "->" else "."; + const maybe_deref = if (operand_is_ptr) "->" else "."; const local = try f.allocLocal(inst_ty, .Const); try writer.print(" = {s}(", .{maybe_addrof}); @@ -3421,6 +3460,11 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue { const error_ty = error_union_ty.errorUnionSet(); const payload_ty = error_union_ty.errorUnionPayload(); + if (error_ty.errorSetCardinality() == .zero) { + // TODO: write undefined bytes through the pointer here + return operand; + } + // First, set the non-error value. if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { try f.writeCValueDeref(writer, operand); @@ -3464,6 +3508,9 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue { const operand = try f.resolveInst(ty_op.operand); const inst_ty = f.air.typeOfIndex(inst); + if (inst_ty.errorUnionSet().errorSetCardinality() == .zero) { + return operand; + } const local = try f.allocLocal(inst_ty, .Const); try writer.writeAll(" = { .error = 0, .payload = "); try f.writeCValue(writer, operand); @@ -3486,16 +3533,23 @@ fn airIsErr( const operand_ty = f.air.typeOf(un_op); const local = try f.allocLocal(Type.initTag(.bool), .Const); const payload_ty = operand_ty.errorUnionPayload(); + const error_ty = operand_ty.errorUnionSet(); + try writer.writeAll(" = "); - if (is_ptr) { - try f.writeCValueDeref(writer, operand); + + if (error_ty.errorSetCardinality() == .zero) { + try writer.print("0 {s} 0;\n", .{op_str}); } else { - try f.writeCValue(writer, operand); - } - if (payload_ty.hasRuntimeBits()) { - try writer.writeAll(".error"); + if (is_ptr) { + try f.writeCValueDeref(writer, operand); + } else { + try f.writeCValue(writer, operand); + } + if (payload_ty.hasRuntimeBits()) { + try writer.writeAll(".error"); + } + try writer.print(" {s} 0;\n", .{op_str}); } - try writer.print(" {s} 0;\n", .{op_str}); return local; } @@ -4129,3 +4183,14 @@ fn intMin(ty: Type, target: std.Target, buf: []u8) []const u8 { }, } } + +fn loweredFnRetTyHasBits(fn_ty: Type) bool { + const ret_ty = fn_ty.fnReturnType(); + if (ret_ty.hasRuntimeBitsIgnoreComptime()) { + return true; + } + if (ret_ty.isError()) { + return true; + } + return false; +} |
