aboutsummaryrefslogtreecommitdiff
path: root/src/codegen/llvm.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-11-09 22:58:27 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-11-09 23:01:35 -0700
commitcb785b9c6ba705fcb507fdfa470e27b5e82ce1c5 (patch)
tree59bd1aa803f9669ba434aa7e7890c8c5cd283055 /src/codegen/llvm.zig
parent008b0ec5e58fc7e31f3b989868a7d1ea4df3f41d (diff)
downloadzig-cb785b9c6ba705fcb507fdfa470e27b5e82ce1c5.tar.gz
zig-cb785b9c6ba705fcb507fdfa470e27b5e82ce1c5.zip
Sema: implement coerce_result_ptr for optionals
New AIR instruction: `optional_payload_ptr_set` It's like `optional_payload_ptr` except it sets the non-null bit. When storing to the payload via a result location that is an optional, `optional_payload_ptr_set` is now emitted. There is a new algorithm in `zirCoerceResultPtr` which stores a dummy value through the result pointer into a temporary block, and then pops off the AIR instructions from the temporary block in order to determine how to transform the result location pointer in case any in-between coercions need to happen. Fixes a couple of behavior tests regarding optionals.
Diffstat (limited to 'src/codegen/llvm.zig')
-rw-r--r--src/codegen/llvm.zig40
1 files changed, 38 insertions, 2 deletions
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index c59c9058ba..99d0aadc99 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -1796,8 +1796,9 @@ pub const FuncGen = struct {
.ptr_elem_val => try self.airPtrElemVal(inst),
.ptr_elem_ptr => try self.airPtrElemPtr(inst),
- .optional_payload => try self.airOptionalPayload(inst),
- .optional_payload_ptr => try self.airOptionalPayloadPtr(inst),
+ .optional_payload => try self.airOptionalPayload(inst),
+ .optional_payload_ptr => try self.airOptionalPayloadPtr(inst),
+ .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst),
.unwrap_errunion_payload => try self.airErrUnionPayload(inst, false),
.unwrap_errunion_payload_ptr => try self.airErrUnionPayload(inst, true),
@@ -2572,6 +2573,41 @@ pub const FuncGen = struct {
return self.builder.buildInBoundsGEP(operand, &indices, indices.len, "");
}
+ fn airOptionalPayloadPtrSet(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 optional_ty = self.air.typeOf(ty_op.operand).childType();
+ var buf: Type.Payload.ElemType = undefined;
+ const payload_ty = optional_ty.optionalChild(&buf);
+ const non_null_bit = self.context.intType(1).constAllOnes();
+ if (!payload_ty.hasCodeGenBits()) {
+ // We have a pointer to a i1. We need to set it to 1 and then return the same pointer.
+ _ = self.builder.buildStore(non_null_bit, operand);
+ return operand;
+ }
+ if (optional_ty.isPtrLikeOptional()) {
+ // The payload and the optional are the same value.
+ // Setting to non-null will be done when the payload is set.
+ return operand;
+ }
+ const index_type = self.context.intType(32);
+ {
+ // First set the non-null bit.
+ const indices: [2]*const llvm.Value = .{
+ index_type.constNull(), // dereference the pointer
+ index_type.constInt(1, .False), // second field is the payload
+ };
+ const non_null_ptr = self.builder.buildInBoundsGEP(operand, &indices, indices.len, "");
+ _ = self.builder.buildStore(non_null_bit, non_null_ptr);
+ }
+ // Then return the payload pointer.
+ const indices: [2]*const llvm.Value = .{
+ index_type.constNull(), // dereference the pointer
+ index_type.constNull(), // first field is the payload
+ };
+ return self.builder.buildInBoundsGEP(operand, &indices, indices.len, "");
+ }
+
fn airOptionalPayload(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
if (self.liveness.isUnused(inst)) return null;