From 89f6ff177178dba4e66680227a02de7b4068123c Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Sat, 19 Feb 2022 15:24:22 +0200 Subject: stage2: correct use of .unwrap_err_union_* in LLVM and C backend --- src/codegen/c.zig | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) (limited to 'src/codegen/c.zig') diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 776cec6457..f6e2d467a7 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -3090,17 +3090,18 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { const operand = try f.resolveInst(ty_op.operand); const operand_ty = f.air.typeOf(ty_op.operand); - const payload_ty = operand_ty.errorUnionPayload(); - if (!payload_ty.hasRuntimeBits()) { - if (operand_ty.zigTypeTag() == .Pointer) { - const local = try f.allocLocal(inst_ty, .Const); - try writer.writeAll(" = *"); - try f.writeCValue(writer, operand); - try writer.writeAll(";\n"); - return local; - } else { + if (operand_ty.zigTypeTag() == .Pointer) { + if (!operand_ty.childType().errorUnionPayload().hasRuntimeBits()) { return operand; } + const local = try f.allocLocal(inst_ty, .Const); + try writer.writeAll(" = *"); + try f.writeCValue(writer, operand); + try writer.writeAll(";\n"); + return local; + } + if (!operand_ty.errorUnionPayload().hasRuntimeBits()) { + return operand; } const local = try f.allocLocal(inst_ty, .Const); @@ -3123,8 +3124,11 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: []cons const operand = try f.resolveInst(ty_op.operand); const operand_ty = f.air.typeOf(ty_op.operand); - const payload_ty = operand_ty.errorUnionPayload(); - if (!payload_ty.hasRuntimeBits()) { + const error_union_ty = if (operand_ty.zigTypeTag() == .Pointer) + operand_ty.childType() + else + operand_ty; + if (!error_union_ty.errorUnionPayload().hasRuntimeBits()) { return CValue.none; } -- cgit v1.2.3 From 27c63bf433f27b06bed92111cbc96e8574de8d11 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Sat, 19 Feb 2022 19:21:49 +0200 Subject: stage2: implement errunion_payload_ptr_set --- src/Air.zig | 4 ++++ src/Liveness.zig | 1 + src/Sema.zig | 8 +++++++- src/arch/aarch64/CodeGen.zig | 7 +++++++ src/arch/arm/CodeGen.zig | 7 +++++++ src/arch/riscv64/CodeGen.zig | 7 +++++++ src/arch/wasm/CodeGen.zig | 1 + src/arch/x86_64/CodeGen.zig | 10 ++++++++++ src/codegen/c.zig | 7 +++++++ src/codegen/llvm.zig | 32 ++++++++++++++++++++++++++++++++ src/print_air.zig | 1 + test/behavior.zig | 2 +- 12 files changed, 85 insertions(+), 2 deletions(-) (limited to 'src/codegen/c.zig') diff --git a/src/Air.zig b/src/Air.zig index 070b43ac49..b9a565ad2e 100644 --- a/src/Air.zig +++ b/src/Air.zig @@ -429,6 +429,9 @@ pub const Inst = struct { /// *(E!T) -> E. If the value is not an error, undefined behavior. /// Uses the `ty_op` field. unwrap_errunion_err_ptr, + /// *(E!T) => *T. Sets the value to non-error with an undefined payload value. + /// Uses the `ty_op` field. + errunion_payload_ptr_set, /// wrap from T to E!T /// Uses the `ty_op` field. wrap_errunion_payload, @@ -865,6 +868,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { .optional_payload, .optional_payload_ptr, .optional_payload_ptr_set, + .errunion_payload_ptr_set, .wrap_optional, .unwrap_errunion_payload, .unwrap_errunion_err, diff --git a/src/Liveness.zig b/src/Liveness.zig index 71f1221b23..5a329d2a7a 100644 --- a/src/Liveness.zig +++ b/src/Liveness.zig @@ -293,6 +293,7 @@ fn analyzeInst( .optional_payload, .optional_payload_ptr, .optional_payload_ptr_set, + .errunion_payload_ptr_set, .wrap_optional, .unwrap_errunion_payload, .unwrap_errunion_err, diff --git a/src/Sema.zig b/src/Sema.zig index acccc0e3bf..2d9381493a 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -1636,7 +1636,13 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE return sema.fail(block, src, "TODO coerce_result_ptr wrap_errunion_err", .{}); }, .wrap_errunion_payload => { - return sema.fail(block, src, "TODO coerce_result_ptr wrap_errunion_payload", .{}); + const ty_op = air_datas[trash_inst].ty_op; + const payload_ty = sema.getTmpAir().typeOf(ty_op.operand); + const ptr_payload_ty = try Type.ptr(sema.arena, .{ + .pointee_type = payload_ty, + .@"addrspace" = addr_space, + }); + new_ptr = try block.addTyOp(.errunion_payload_ptr_set, ptr_payload_ty, new_ptr); }, else => { if (std.debug.runtime_safety) { diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 7a3d049ae6..2267a156f9 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -662,6 +662,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst), .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst), .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst), + .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst), .wrap_optional => try self.airWrapOptional(inst), .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), @@ -1443,6 +1444,12 @@ fn airUnwrapErrPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } +fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { + const ty_op = self.air.instructions.items(.data)[inst].ty_op; + const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement .errunion_payload_ptr_set for {}", .{self.target.cpu.arch}); + return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); +} + fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 6f87c56503..3633b5ccd0 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -646,6 +646,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst), .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst), .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst), + .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst), .wrap_optional => try self.airWrapOptional(inst), .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), @@ -1128,6 +1129,12 @@ fn airUnwrapErrPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } +fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { + const ty_op = self.air.instructions.items(.data)[inst].ty_op; + const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement .errunion_payload_ptr_set for {}", .{self.target.cpu.arch}); + return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); +} + fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index d73e083dbc..10764ad6cd 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -633,6 +633,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst), .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst), .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst), + .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst), .wrap_optional => try self.airWrapOptional(inst), .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), @@ -1065,6 +1066,12 @@ fn airUnwrapErrPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } +fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { + const ty_op = self.air.instructions.items(.data)[inst].ty_op; + const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement .errunion_payload_ptr_set for {}", .{self.target.cpu.arch}); + return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); +} + fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 2bd6b92963..b776f30346 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -1725,6 +1725,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { .atomic_rmw, .tag_name, .error_name, + .errunion_payload_ptr_set, // For these 4, probably best to wait until https://github.com/ziglang/zig/issues/10248 // is implemented in the frontend before implementing them here in the wasm backend. diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 441af51de2..d7d6ac9da8 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -727,6 +727,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .unwrap_errunion_payload => try self.airUnwrapErrPayload(inst), .unwrap_errunion_err_ptr => try self.airUnwrapErrErrPtr(inst), .unwrap_errunion_payload_ptr=> try self.airUnwrapErrPayloadPtr(inst), + .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst), .wrap_optional => try self.airWrapOptional(inst), .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), @@ -1406,6 +1407,15 @@ fn airUnwrapErrPayloadPtr(self: *Self, inst: Air.Inst.Index) !void { return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } +fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void { + const ty_op = self.air.instructions.items(.data)[inst].ty_op; + const result: MCValue = if (self.liveness.isUnused(inst)) + .dead + else + return self.fail("TODO implement .errunion_payload_ptr_set for {}", .{self.target.cpu.arch}); + return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); +} + fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { const ty_op = self.air.instructions.items(.data)[inst].ty_op; const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: { diff --git a/src/codegen/c.zig b/src/codegen/c.zig index f6e2d467a7..fe0184849d 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -1753,6 +1753,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO .unwrap_errunion_err_ptr => try airUnwrapErrUnionErr(f, inst), .wrap_errunion_payload => try airWrapErrUnionPay(f, inst), .wrap_errunion_err => try airWrapErrUnionErr(f, inst), + .errunion_payload_ptr_set => try airErrUnionPayloadPtrSet(f, inst), // zig fmt: on }; switch (result_value) { @@ -3164,6 +3165,7 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue { try writer.writeAll("};\n"); return local; } + fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { if (f.liveness.isUnused(inst)) return CValue.none; @@ -3183,6 +3185,11 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { return local; } +fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue { + _ = inst; + return f.fail("TODO: C backend: implement airErrUnionPayloadPtrSet", .{}); +} + fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue { if (f.liveness.isUnused(inst)) return CValue.none; diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 8af74fce64..d8c19fba71 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -2238,6 +2238,7 @@ pub const FuncGen = struct { .unwrap_errunion_payload_ptr => try self.airErrUnionPayload(inst, true), .unwrap_errunion_err => try self.airErrUnionErr(inst, false), .unwrap_errunion_err_ptr => try self.airErrUnionErr(inst, true), + .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst), .wrap_optional => try self.airWrapOptional(inst), .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), @@ -3202,6 +3203,37 @@ pub const FuncGen = struct { return self.builder.buildExtractValue(operand, 0, ""); } + fn airErrUnionPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { + const ty_op = self.air.instructions.items(.data)[inst].ty_op; + const operand = try self.resolveInst(ty_op.operand); + const error_set_ty = self.air.typeOf(ty_op.operand).childType(); + + const error_ty = error_set_ty.errorUnionSet(); + const payload_ty = error_set_ty.errorUnionPayload(); + const non_error_val = try self.dg.genTypedValue(.{ .ty = error_ty, .val = Value.zero }); + if (!payload_ty.hasRuntimeBits()) { + // We have a pointer to a i1. We need to set it to 1 and then return the same pointer. + _ = self.builder.buildStore(non_error_val, operand); + return operand; + } + const index_type = self.context.intType(32); + { + // First set the non-error value. + const indices: [2]*const llvm.Value = .{ + index_type.constNull(), // dereference the pointer + index_type.constNull(), // first field is the payload + }; + const non_null_ptr = self.builder.buildInBoundsGEP(operand, &indices, indices.len, ""); + _ = self.builder.buildStore(non_error_val, non_null_ptr); + } + // Then return the payload pointer. + const indices: [2]*const llvm.Value = .{ + index_type.constNull(), // dereference the pointer + index_type.constInt(1, .False), // second field is the payload + }; + return self.builder.buildInBoundsGEP(operand, &indices, indices.len, ""); + } + fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { if (self.liveness.isUnused(inst)) return null; diff --git a/src/print_air.zig b/src/print_air.zig index 5dc8219b12..289fcca669 100644 --- a/src/print_air.zig +++ b/src/print_air.zig @@ -189,6 +189,7 @@ const Writer = struct { .optional_payload, .optional_payload_ptr, .optional_payload_ptr_set, + .errunion_payload_ptr_set, .wrap_optional, .unwrap_errunion_payload, .unwrap_errunion_err, diff --git a/test/behavior.zig b/test/behavior.zig index 5b575ba190..68d0c40cd6 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -118,6 +118,7 @@ test { _ = @import("behavior/sizeof_and_typeof.zig"); _ = @import("behavior/switch.zig"); _ = @import("behavior/widening.zig"); + _ = @import("behavior/bugs/1442.zig"); if (builtin.zig_backend == .stage1) { // Tests that only pass for the stage1 backend. @@ -134,7 +135,6 @@ test { _ = @import("behavior/bugs/920.zig"); _ = @import("behavior/bugs/1120.zig"); _ = @import("behavior/bugs/1421.zig"); - _ = @import("behavior/bugs/1442.zig"); _ = @import("behavior/bugs/1607.zig"); _ = @import("behavior/bugs/1851.zig"); _ = @import("behavior/bugs/2114.zig"); -- cgit v1.2.3