diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2021-08-07 20:34:28 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-08-07 20:34:28 -0700 |
| commit | 799fedf612aa8742c446b015c12d21707a1dbec0 (patch) | |
| tree | 1d9efbc4cb3f6dda9631160784a074e58d6bd479 /src/codegen/llvm.zig | |
| parent | f81b2531cb4904064446f84a06f6e09e4120e28a (diff) | |
| download | zig-799fedf612aa8742c446b015c12d21707a1dbec0.tar.gz zig-799fedf612aa8742c446b015c12d21707a1dbec0.zip | |
stage2: pass some error union tests
* Value: rename `error_union` to `eu_payload` and clarify the intended
usage in the doc comments. The way error unions is represented with
Value is fixed to not have ambiguous values.
* Fix codegen for error union constants in all the backends.
* Implement the AIR instructions having to do with error unions in the
LLVM backend.
Diffstat (limited to 'src/codegen/llvm.zig')
| -rw-r--r-- | src/codegen/llvm.zig | 78 |
1 files changed, 51 insertions, 27 deletions
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index eccd5fa04f..7cfbc8da5e 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -593,7 +593,7 @@ pub const DeclGen = struct { try self.llvmType(ptr_type), try self.llvmType(Type.initTag(.usize)), }; - return self.context.structType(&fields, 2, .False); + return self.context.structType(&fields, fields.len, .False); } else { const elem_type = try self.llvmType(t.elemType()); return elem_type.pointerType(0); @@ -621,10 +621,14 @@ pub const DeclGen = struct { .ErrorUnion => { const error_type = t.errorUnionSet(); const payload_type = t.errorUnionPayload(); + const llvm_error_type = try self.llvmType(error_type); if (!payload_type.hasCodeGenBits()) { - return self.llvmType(error_type); + return llvm_error_type; } - return self.todo("implement llvmType for error unions", .{}); + const llvm_payload_type = try self.llvmType(payload_type); + + const fields: [2]*const llvm.Type = .{ llvm_error_type, llvm_payload_type }; + return self.context.structType(&fields, fields.len, .False); }, .ErrorSet => { return self.context.intType(16); @@ -846,14 +850,25 @@ pub const DeclGen = struct { .ErrorUnion => { const error_type = tv.ty.errorUnionSet(); const payload_type = tv.ty.errorUnionPayload(); - const sub_val = tv.val.castTag(.error_union).?.data; + const is_pl = tv.val.errorUnionIsPayload(); if (!payload_type.hasCodeGenBits()) { // We use the error type directly as the type. - return self.genTypedValue(.{ .ty = error_type, .val = sub_val }); + const err_val = if (!is_pl) tv.val else Value.initTag(.zero); + return self.genTypedValue(.{ .ty = error_type, .val = err_val }); } - return self.todo("implement error union const of type '{}'", .{tv.ty}); + const fields: [2]*const llvm.Value = .{ + try self.genTypedValue(.{ + .ty = error_type, + .val = if (is_pl) Value.initTag(.zero) else tv.val, + }), + try self.genTypedValue(.{ + .ty = payload_type, + .val = if (tv.val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef), + }), + }; + return self.context.constStruct(&fields, fields.len, .False); }, .Struct => { const fields_len = tv.ty.structFieldCount(); @@ -984,10 +999,10 @@ pub const FuncGen = struct { .is_non_null_ptr => try self.airIsNonNull(inst, true), .is_null => try self.airIsNull(inst, false), .is_null_ptr => try self.airIsNull(inst, true), - .is_non_err => try self.airIsErr(inst, true, false), - .is_non_err_ptr => try self.airIsErr(inst, true, true), - .is_err => try self.airIsErr(inst, false, false), - .is_err_ptr => try self.airIsErr(inst, false, true), + .is_non_err => try self.airIsErr(inst, .EQ, false), + .is_non_err_ptr => try self.airIsErr(inst, .EQ, true), + .is_err => try self.airIsErr(inst, .NE, false), + .is_err_ptr => try self.airIsErr(inst, .NE, true), .alloc => try self.airAlloc(inst), .arg => try self.airArg(inst), @@ -1098,7 +1113,7 @@ pub const FuncGen = struct { const inst_ty = self.air.typeOfIndex(inst); switch (self.air.typeOf(bin_op.lhs).zigTypeTag()) { - .Int, .Bool, .Pointer => { + .Int, .Bool, .Pointer, .ErrorSet => { const is_signed = inst_ty.isSignedInt(); const operation = switch (op) { .eq => .EQ, @@ -1256,12 +1271,7 @@ pub const FuncGen = struct { const rhs = try self.resolveInst(bin_op.rhs); const base_ptr = ptr: { - const index_type = self.context.intType(32); - const indices: [2]*const llvm.Value = .{ - index_type.constNull(), - index_type.constInt(0, .False), - }; - const ptr_field_ptr = self.builder.buildInBoundsGEP(lhs, &indices, 2, ""); + const ptr_field_ptr = self.builder.buildStructGEP(lhs, 0, ""); break :ptr self.builder.buildLoad(ptr_field_ptr, ""); }; @@ -1472,7 +1482,7 @@ pub const FuncGen = struct { index_type.constInt(1, .False), }; - return self.builder.buildLoad(self.builder.buildInBoundsGEP(operand, &indices, 2, ""), ""); + return self.builder.buildLoad(self.builder.buildInBoundsGEP(operand, &indices, indices.len, ""), ""); } else { return self.builder.buildExtractValue(operand, 1, ""); } @@ -1488,7 +1498,7 @@ pub const FuncGen = struct { fn airIsErr( self: *FuncGen, inst: Air.Inst.Index, - invert_logic: bool, + op: llvm.IntPredicate, operand_is_ptr: bool, ) !?*const llvm.Value { if (self.liveness.isUnused(inst)) @@ -1498,16 +1508,22 @@ pub const FuncGen = struct { const operand = try self.resolveInst(un_op); const err_union_ty = self.air.typeOf(un_op); const payload_ty = err_union_ty.errorUnionPayload(); + const err_set_ty = try self.dg.llvmType(Type.initTag(.anyerror)); + const zero = err_set_ty.constNull(); if (!payload_ty.hasCodeGenBits()) { const loaded = if (operand_is_ptr) self.builder.buildLoad(operand, "") else operand; - const op: llvm.IntPredicate = if (invert_logic) .EQ else .NE; - const err_set_ty = try self.dg.llvmType(Type.initTag(.anyerror)); - const zero = err_set_ty.constNull(); return self.builder.buildICmp(op, loaded, zero, ""); } - return self.todo("implement 'airIsErr' for error unions with nonzero payload", .{}); + if (operand_is_ptr) { + const err_field_ptr = self.builder.buildStructGEP(operand, 0, ""); + const loaded = self.builder.buildLoad(err_field_ptr, ""); + return self.builder.buildICmp(op, loaded, zero, ""); + } + + const loaded = self.builder.buildExtractValue(operand, 0, ""); + return self.builder.buildICmp(op, loaded, zero, ""); } fn airOptionalPayload( @@ -1552,9 +1568,11 @@ pub const FuncGen = struct { return null; } - _ = operand; - _ = operand_is_ptr; - return self.todo("implement llvm codegen for 'airErrUnionPayload' for type {}", .{self.air.typeOf(ty_op.operand)}); + if (operand_is_ptr) { + return self.builder.buildStructGEP(operand, 1, ""); + } + + return self.builder.buildExtractValue(operand, 1, ""); } fn airErrUnionErr( @@ -1574,7 +1592,13 @@ pub const FuncGen = struct { if (!operand_is_ptr) return operand; return self.builder.buildLoad(operand, ""); } - return self.todo("implement llvm codegen for 'airErrUnionErr'", .{}); + + if (operand_is_ptr) { + const err_field_ptr = self.builder.buildStructGEP(operand, 0, ""); + return self.builder.buildLoad(err_field_ptr, ""); + } + + return self.builder.buildExtractValue(operand, 0, ""); } fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
