diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2021-11-09 22:58:27 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-11-09 23:01:35 -0700 |
| commit | cb785b9c6ba705fcb507fdfa470e27b5e82ce1c5 (patch) | |
| tree | 59bd1aa803f9669ba434aa7e7890c8c5cd283055 /src/codegen/llvm.zig | |
| parent | 008b0ec5e58fc7e31f3b989868a7d1ea4df3f41d (diff) | |
| download | zig-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.zig | 40 |
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; |
