aboutsummaryrefslogtreecommitdiff
path: root/src/codegen/llvm.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-08-07 20:34:28 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-08-07 20:34:28 -0700
commit799fedf612aa8742c446b015c12d21707a1dbec0 (patch)
tree1d9efbc4cb3f6dda9631160784a074e58d6bd479 /src/codegen/llvm.zig
parentf81b2531cb4904064446f84a06f6e09e4120e28a (diff)
downloadzig-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.zig78
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 {