| ... | @@ -4539,7 +4539,7 @@ pub const FuncGen = struct { | ... | @@ -4539,7 +4539,7 @@ pub const FuncGen = struct { |
| 4539 | } | 4539 | } |
| 4540 | // We need to emit instructions to check for equality/inequality | 4540 | // We need to emit instructions to check for equality/inequality |
| 4541 | // of optionals that are not pointers. | 4541 | // of optionals that are not pointers. |
| 4542 | const is_by_ref = isByRef(operand_ty); | 4542 | const is_by_ref = isByRef(scalar_ty); |
| 4543 | const lhs_non_null = self.optIsNonNull(lhs, is_by_ref); | 4543 | const lhs_non_null = self.optIsNonNull(lhs, is_by_ref); |
| 4544 | const rhs_non_null = self.optIsNonNull(rhs, is_by_ref); | 4544 | const rhs_non_null = self.optIsNonNull(rhs, is_by_ref); |
| 4545 | const llvm_i2 = self.context.intType(2); | 4545 | const llvm_i2 = self.context.intType(2); |
| ... | @@ -4564,8 +4564,8 @@ pub const FuncGen = struct { | ... | @@ -4564,8 +4564,8 @@ pub const FuncGen = struct { |
| 4564 | _ = self.builder.buildBr(end_block); | 4564 | _ = self.builder.buildBr(end_block); |
| 4565 | | 4565 | |
| 4566 | self.builder.positionBuilderAtEnd(both_pl_block); | 4566 | self.builder.positionBuilderAtEnd(both_pl_block); |
| 4567 | const lhs_payload = self.optPayloadHandle(lhs, is_by_ref); | 4567 | const lhs_payload = self.optPayloadHandle(lhs, scalar_ty); |
| 4568 | const rhs_payload = self.optPayloadHandle(rhs, is_by_ref); | 4568 | const rhs_payload = self.optPayloadHandle(rhs, scalar_ty); |
| 4569 | const payload_cmp = try self.cmp(lhs_payload, rhs_payload, payload_ty, op); | 4569 | const payload_cmp = try self.cmp(lhs_payload, rhs_payload, payload_ty, op); |
| 4570 | _ = self.builder.buildBr(end_block); | 4570 | _ = self.builder.buildBr(end_block); |
| 4571 | const both_pl_block_end = self.builder.getInsertBlock(); | 4571 | const both_pl_block_end = self.builder.getInsertBlock(); |
| ... | @@ -4740,12 +4740,14 @@ pub const FuncGen = struct { | ... | @@ -4740,12 +4740,14 @@ pub const FuncGen = struct { |
| 4740 | const err_set_ty = try fg.dg.lowerType(Type.anyerror); | 4740 | const err_set_ty = try fg.dg.lowerType(Type.anyerror); |
| 4741 | const zero = err_set_ty.constNull(); | 4741 | const zero = err_set_ty.constNull(); |
| 4742 | if (!payload_has_bits) { | 4742 | if (!payload_has_bits) { |
| | 4743 | // TODO add alignment to this load |
| 4743 | const loaded = if (operand_is_ptr) fg.builder.buildLoad(err_union, "") else err_union; | 4744 | const loaded = if (operand_is_ptr) fg.builder.buildLoad(err_union, "") else err_union; |
| 4744 | break :err fg.builder.buildICmp(.NE, loaded, zero, ""); | 4745 | break :err fg.builder.buildICmp(.NE, loaded, zero, ""); |
| 4745 | } | 4746 | } |
| 4746 | const err_field_index = errUnionErrorOffset(payload_ty, target); | 4747 | const err_field_index = errUnionErrorOffset(payload_ty, target); |
| 4747 | if (operand_is_ptr or isByRef(err_union_ty)) { | 4748 | if (operand_is_ptr or isByRef(err_union_ty)) { |
| 4748 | const err_field_ptr = fg.builder.buildStructGEP(err_union, err_field_index, ""); | 4749 | const err_field_ptr = fg.builder.buildStructGEP(err_union, err_field_index, ""); |
| | 4750 | // TODO add alignment to this load |
| 4749 | const loaded = fg.builder.buildLoad(err_field_ptr, ""); | 4751 | const loaded = fg.builder.buildLoad(err_field_ptr, ""); |
| 4750 | break :err fg.builder.buildICmp(.NE, loaded, zero, ""); | 4752 | break :err fg.builder.buildICmp(.NE, loaded, zero, ""); |
| 4751 | } | 4753 | } |
| ... | @@ -4765,13 +4767,22 @@ pub const FuncGen = struct { | ... | @@ -4765,13 +4767,22 @@ pub const FuncGen = struct { |
| 4765 | if (!payload_has_bits) { | 4767 | if (!payload_has_bits) { |
| 4766 | if (!operand_is_ptr) return null; | 4768 | if (!operand_is_ptr) return null; |
| 4767 | | 4769 | |
| 4768 | // TODO once we update to LLVM 14 this bitcast won't be necessary. | 4770 | // TODO once we update to an LLVM version with opaque pointers |
| | 4771 | // this bitcast won't be necessary. |
| 4769 | const res_ptr_ty = try fg.dg.lowerType(result_ty); | 4772 | const res_ptr_ty = try fg.dg.lowerType(result_ty); |
| 4770 | return fg.builder.buildBitCast(err_union, res_ptr_ty, ""); | 4773 | return fg.builder.buildBitCast(err_union, res_ptr_ty, ""); |
| 4771 | } | 4774 | } |
| 4772 | const offset = errUnionPayloadOffset(payload_ty, target); | 4775 | const offset = errUnionPayloadOffset(payload_ty, target); |
| 4773 | if (operand_is_ptr or isByRef(payload_ty)) { | 4776 | if (operand_is_ptr or isByRef(payload_ty)) { |
| 4774 | return fg.builder.buildStructGEP(err_union, offset, ""); | 4777 | return fg.builder.buildStructGEP(err_union, offset, ""); |
| | 4778 | } else if (isByRef(err_union_ty)) { |
| | 4779 | const payload_ptr = fg.builder.buildStructGEP(err_union, offset, ""); |
| | 4780 | if (isByRef(payload_ty)) { |
| | 4781 | return payload_ptr; |
| | 4782 | } |
| | 4783 | const load_inst = fg.builder.buildLoad(payload_ptr, ""); |
| | 4784 | load_inst.setAlignment(payload_ty.abiAlignment(target)); |
| | 4785 | return load_inst; |
| 4775 | } | 4786 | } |
| 4776 | return fg.builder.buildExtractValue(err_union, offset, ""); | 4787 | return fg.builder.buildExtractValue(err_union, offset, ""); |
| 4777 | } | 4788 | } |
| ... | @@ -5730,12 +5741,7 @@ pub const FuncGen = struct { | ... | @@ -5730,12 +5741,7 @@ pub const FuncGen = struct { |
| 5730 | // The payload and the optional are the same value. | 5741 | // The payload and the optional are the same value. |
| 5731 | return operand; | 5742 | return operand; |
| 5732 | } | 5743 | } |
| 5733 | const index_type = self.context.intType(32); | 5744 | return self.builder.buildStructGEP(operand, 0, ""); |
| 5734 | const indices: [2]*const llvm.Value = .{ | | |
| 5735 | index_type.constNull(), // dereference the pointer | | |
| 5736 | index_type.constNull(), // first field is the payload | | |
| 5737 | }; | | |
| 5738 | return self.builder.buildInBoundsGEP(operand, &indices, indices.len, ""); | | |
| 5739 | } | 5745 | } |
| 5740 | | 5746 | |
| 5741 | fn airOptionalPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | 5747 | fn airOptionalPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| ... | @@ -5761,24 +5767,17 @@ pub const FuncGen = struct { | ... | @@ -5761,24 +5767,17 @@ pub const FuncGen = struct { |
| 5761 | // Setting to non-null will be done when the payload is set. | 5767 | // Setting to non-null will be done when the payload is set. |
| 5762 | return operand; | 5768 | return operand; |
| 5763 | } | 5769 | } |
| 5764 | const index_type = self.context.intType(32); | 5770 | |
| 5765 | { | 5771 | // First set the non-null bit. |
| 5766 | // First set the non-null bit. | 5772 | const non_null_ptr = self.builder.buildStructGEP(operand, 1, ""); |
| 5767 | const indices: [2]*const llvm.Value = .{ | 5773 | // TODO set alignment on this store |
| 5768 | index_type.constNull(), // dereference the pointer | 5774 | _ = self.builder.buildStore(non_null_bit, non_null_ptr); |
| 5769 | index_type.constInt(1, .False), // second field is the non-null bit | 5775 | |
| 5770 | }; | | |
| 5771 | const non_null_ptr = self.builder.buildInBoundsGEP(operand, &indices, indices.len, ""); | | |
| 5772 | _ = self.builder.buildStore(non_null_bit, non_null_ptr); | | |
| 5773 | } | | |
| 5774 | // Then return the payload pointer (only if it's used). | 5776 | // Then return the payload pointer (only if it's used). |
| 5775 | if (self.liveness.isUnused(inst)) | 5777 | if (self.liveness.isUnused(inst)) |
| 5776 | return null; | 5778 | return null; |
| 5777 | const indices: [2]*const llvm.Value = .{ | 5779 | |
| 5778 | index_type.constNull(), // dereference the pointer | 5780 | return self.builder.buildStructGEP(operand, 0, ""); |
| 5779 | index_type.constNull(), // first field is the payload | | |
| 5780 | }; | | |
| 5781 | return self.builder.buildInBoundsGEP(operand, &indices, indices.len, ""); | | |
| 5782 | } | 5781 | } |
| 5783 | | 5782 | |
| 5784 | fn airOptionalPayload(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | 5783 | fn airOptionalPayload(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| ... | @@ -5795,7 +5794,7 @@ pub const FuncGen = struct { | ... | @@ -5795,7 +5794,7 @@ pub const FuncGen = struct { |
| 5795 | return operand; | 5794 | return operand; |
| 5796 | } | 5795 | } |
| 5797 | | 5796 | |
| 5798 | return self.optPayloadHandle(operand, isByRef(payload_ty)); | 5797 | return self.optPayloadHandle(operand, optional_ty); |
| 5799 | } | 5798 | } |
| 5800 | | 5799 | |
| 5801 | fn airErrUnionPayload( | 5800 | fn airErrUnionPayload( |
| ... | @@ -5807,6 +5806,8 @@ pub const FuncGen = struct { | ... | @@ -5807,6 +5806,8 @@ pub const FuncGen = struct { |
| 5807 | | 5806 | |
| 5808 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 5807 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 5809 | const operand = try self.resolveInst(ty_op.operand); | 5808 | const operand = try self.resolveInst(ty_op.operand); |
| | 5809 | const operand_ty = self.air.typeOf(ty_op.operand); |
| | 5810 | const err_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty; |
| 5810 | const result_ty = self.air.typeOfIndex(inst); | 5811 | const result_ty = self.air.typeOfIndex(inst); |
| 5811 | const payload_ty = if (operand_is_ptr) result_ty.childType() else result_ty; | 5812 | const payload_ty = if (operand_is_ptr) result_ty.childType() else result_ty; |
| 5812 | const target = self.dg.module.getTarget(); | 5813 | const target = self.dg.module.getTarget(); |
| ... | @@ -5821,6 +5822,14 @@ pub const FuncGen = struct { | ... | @@ -5821,6 +5822,14 @@ pub const FuncGen = struct { |
| 5821 | const offset = errUnionPayloadOffset(payload_ty, target); | 5822 | const offset = errUnionPayloadOffset(payload_ty, target); |
| 5822 | if (operand_is_ptr or isByRef(payload_ty)) { | 5823 | if (operand_is_ptr or isByRef(payload_ty)) { |
| 5823 | return self.builder.buildStructGEP(operand, offset, ""); | 5824 | return self.builder.buildStructGEP(operand, offset, ""); |
| | 5825 | } else if (isByRef(err_union_ty)) { |
| | 5826 | const payload_ptr = self.builder.buildStructGEP(operand, offset, ""); |
| | 5827 | if (isByRef(payload_ty)) { |
| | 5828 | return payload_ptr; |
| | 5829 | } |
| | 5830 | const load_inst = self.builder.buildLoad(payload_ptr, ""); |
| | 5831 | load_inst.setAlignment(payload_ty.abiAlignment(target)); |
| | 5832 | return load_inst; |
| 5824 | } | 5833 | } |
| 5825 | return self.builder.buildExtractValue(operand, offset, ""); | 5834 | return self.builder.buildExtractValue(operand, offset, ""); |
| 5826 | } | 5835 | } |
| ... | @@ -5874,16 +5883,11 @@ pub const FuncGen = struct { | ... | @@ -5874,16 +5883,11 @@ pub const FuncGen = struct { |
| 5874 | _ = self.builder.buildStore(non_error_val, operand); | 5883 | _ = self.builder.buildStore(non_error_val, operand); |
| 5875 | return operand; | 5884 | return operand; |
| 5876 | } | 5885 | } |
| 5877 | const index_type = self.context.intType(32); | | |
| 5878 | const target = self.dg.module.getTarget(); | 5886 | const target = self.dg.module.getTarget(); |
| 5879 | { | 5887 | { |
| 5880 | const error_offset = errUnionErrorOffset(payload_ty, target); | 5888 | const error_offset = errUnionErrorOffset(payload_ty, target); |
| 5881 | // First set the non-error value. | 5889 | // First set the non-error value. |
| 5882 | const indices: [2]*const llvm.Value = .{ | 5890 | const non_null_ptr = self.builder.buildStructGEP(operand, error_offset, ""); |
| 5883 | index_type.constNull(), // dereference the pointer | | |
| 5884 | index_type.constInt(error_offset, .False), | | |
| 5885 | }; | | |
| 5886 | const non_null_ptr = self.builder.buildInBoundsGEP(operand, &indices, indices.len, ""); | | |
| 5887 | const store_inst = self.builder.buildStore(non_error_val, non_null_ptr); | 5891 | const store_inst = self.builder.buildStore(non_error_val, non_null_ptr); |
| 5888 | store_inst.setAlignment(Type.anyerror.abiAlignment(target)); | 5892 | store_inst.setAlignment(Type.anyerror.abiAlignment(target)); |
| 5889 | } | 5893 | } |
| ... | @@ -5892,11 +5896,7 @@ pub const FuncGen = struct { | ... | @@ -5892,11 +5896,7 @@ pub const FuncGen = struct { |
| 5892 | return null; | 5896 | return null; |
| 5893 | | 5897 | |
| 5894 | const payload_offset = errUnionPayloadOffset(payload_ty, target); | 5898 | const payload_offset = errUnionPayloadOffset(payload_ty, target); |
| 5895 | const indices: [2]*const llvm.Value = .{ | 5899 | return self.builder.buildStructGEP(operand, payload_offset, ""); |
| 5896 | index_type.constNull(), // dereference the pointer | | |
| 5897 | index_type.constInt(payload_offset, .False), | | |
| 5898 | }; | | |
| 5899 | return self.builder.buildInBoundsGEP(operand, &indices, indices.len, ""); | | |
| 5900 | } | 5900 | } |
| 5901 | | 5901 | |
| 5902 | fn airErrReturnTrace(self: *FuncGen, _: Air.Inst.Index) !?*const llvm.Value { | 5902 | fn airErrReturnTrace(self: *FuncGen, _: Air.Inst.Index) !?*const llvm.Value { |
| ... | @@ -6391,8 +6391,30 @@ pub const FuncGen = struct { | ... | @@ -6391,8 +6391,30 @@ pub const FuncGen = struct { |
| 6391 | const overflow_bit = self.builder.buildExtractValue(result_struct, 1, ""); | 6391 | const overflow_bit = self.builder.buildExtractValue(result_struct, 1, ""); |
| 6392 | | 6392 | |
| 6393 | var ty_buf: Type.Payload.Pointer = undefined; | 6393 | var ty_buf: Type.Payload.Pointer = undefined; |
| 6394 | const partial = self.builder.buildInsertValue(llvm_dest_ty.getUndef(), result, llvmFieldIndex(dest_ty, 0, tg, &ty_buf).?, ""); | 6394 | const result_index = llvmFieldIndex(dest_ty, 0, tg, &ty_buf).?; |
| 6395 | return self.builder.buildInsertValue(partial, overflow_bit, llvmFieldIndex(dest_ty, 1, tg, &ty_buf).?, ""); | 6395 | const overflow_index = llvmFieldIndex(dest_ty, 1, tg, &ty_buf).?; |
| | 6396 | |
| | 6397 | if (isByRef(dest_ty)) { |
| | 6398 | const target = self.dg.module.getTarget(); |
| | 6399 | const alloca_inst = self.buildAlloca(llvm_dest_ty); |
| | 6400 | const result_alignment = dest_ty.abiAlignment(target); |
| | 6401 | alloca_inst.setAlignment(result_alignment); |
| | 6402 | { |
| | 6403 | const field_ptr = self.builder.buildStructGEP(alloca_inst, result_index, ""); |
| | 6404 | const store_inst = self.builder.buildStore(result, field_ptr); |
| | 6405 | store_inst.setAlignment(result_alignment); |
| | 6406 | } |
| | 6407 | { |
| | 6408 | const field_ptr = self.builder.buildStructGEP(alloca_inst, overflow_index, ""); |
| | 6409 | const store_inst = self.builder.buildStore(overflow_bit, field_ptr); |
| | 6410 | store_inst.setAlignment(1); |
| | 6411 | } |
| | 6412 | |
| | 6413 | return alloca_inst; |
| | 6414 | } |
| | 6415 | |
| | 6416 | const partial = self.builder.buildInsertValue(llvm_dest_ty.getUndef(), result, result_index, ""); |
| | 6417 | return self.builder.buildInsertValue(partial, overflow_bit, overflow_index, ""); |
| 6396 | } | 6418 | } |
| 6397 | | 6419 | |
| 6398 | fn buildElementwiseCall( | 6420 | fn buildElementwiseCall( |
| ... | @@ -6721,8 +6743,30 @@ pub const FuncGen = struct { | ... | @@ -6721,8 +6743,30 @@ pub const FuncGen = struct { |
| 6721 | const overflow_bit = self.builder.buildICmp(.NE, lhs, reconstructed, ""); | 6743 | const overflow_bit = self.builder.buildICmp(.NE, lhs, reconstructed, ""); |
| 6722 | | 6744 | |
| 6723 | var ty_buf: Type.Payload.Pointer = undefined; | 6745 | var ty_buf: Type.Payload.Pointer = undefined; |
| 6724 | const partial = self.builder.buildInsertValue(llvm_dest_ty.getUndef(), result, llvmFieldIndex(dest_ty, 0, tg, &ty_buf).?, ""); | 6746 | const result_index = llvmFieldIndex(dest_ty, 0, tg, &ty_buf).?; |
| 6725 | return self.builder.buildInsertValue(partial, overflow_bit, llvmFieldIndex(dest_ty, 1, tg, &ty_buf).?, ""); | 6747 | const overflow_index = llvmFieldIndex(dest_ty, 1, tg, &ty_buf).?; |
| | 6748 | |
| | 6749 | if (isByRef(dest_ty)) { |
| | 6750 | const target = self.dg.module.getTarget(); |
| | 6751 | const alloca_inst = self.buildAlloca(llvm_dest_ty); |
| | 6752 | const result_alignment = dest_ty.abiAlignment(target); |
| | 6753 | alloca_inst.setAlignment(result_alignment); |
| | 6754 | { |
| | 6755 | const field_ptr = self.builder.buildStructGEP(alloca_inst, result_index, ""); |
| | 6756 | const store_inst = self.builder.buildStore(result, field_ptr); |
| | 6757 | store_inst.setAlignment(result_alignment); |
| | 6758 | } |
| | 6759 | { |
| | 6760 | const field_ptr = self.builder.buildStructGEP(alloca_inst, overflow_index, ""); |
| | 6761 | const store_inst = self.builder.buildStore(overflow_bit, field_ptr); |
| | 6762 | store_inst.setAlignment(1); |
| | 6763 | } |
| | 6764 | |
| | 6765 | return alloca_inst; |
| | 6766 | } |
| | 6767 | |
| | 6768 | const partial = self.builder.buildInsertValue(llvm_dest_ty.getUndef(), result, result_index, ""); |
| | 6769 | return self.builder.buildInsertValue(partial, overflow_bit, overflow_index, ""); |
| 6726 | } | 6770 | } |
| 6727 | | 6771 | |
| 6728 | fn airAnd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | 6772 | fn airAnd(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| ... | @@ -7347,11 +7391,9 @@ pub const FuncGen = struct { | ... | @@ -7347,11 +7391,9 @@ pub const FuncGen = struct { |
| 7347 | } | 7391 | } |
| 7348 | | 7392 | |
| 7349 | comptime assert(optional_layout_version == 3); | 7393 | comptime assert(optional_layout_version == 3); |
| 7350 | const optional_llvm_ty = try self.dg.lowerType(optional_ty); | 7394 | |
| 7351 | const non_null_bit = self.builder.buildNot(success_bit, ""); | 7395 | const non_null_bit = self.builder.buildNot(success_bit, ""); |
| 7352 | const non_null_field = self.builder.buildZExt(non_null_bit, self.dg.context.intType(8), ""); | 7396 | return buildOptional(self, optional_ty, payload, non_null_bit); |
| 7353 | const partial = self.builder.buildInsertValue(optional_llvm_ty.getUndef(), payload, 0, ""); | | |
| 7354 | return self.builder.buildInsertValue(partial, non_null_field, 1, ""); | | |
| 7355 | } | 7397 | } |
| 7356 | | 7398 | |
| 7357 | fn airAtomicRmw(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | 7399 | fn airAtomicRmw(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| ... | @@ -7515,11 +7557,13 @@ pub const FuncGen = struct { | ... | @@ -7515,11 +7557,13 @@ pub const FuncGen = struct { |
| 7515 | const union_ptr = try self.resolveInst(bin_op.lhs); | 7557 | const union_ptr = try self.resolveInst(bin_op.lhs); |
| 7516 | const new_tag = try self.resolveInst(bin_op.rhs); | 7558 | const new_tag = try self.resolveInst(bin_op.rhs); |
| 7517 | if (layout.payload_size == 0) { | 7559 | if (layout.payload_size == 0) { |
| | 7560 | // TODO alignment on this store |
| 7518 | _ = self.builder.buildStore(new_tag, union_ptr); | 7561 | _ = self.builder.buildStore(new_tag, union_ptr); |
| 7519 | return null; | 7562 | return null; |
| 7520 | } | 7563 | } |
| 7521 | const tag_index = @boolToInt(layout.tag_align < layout.payload_align); | 7564 | const tag_index = @boolToInt(layout.tag_align < layout.payload_align); |
| 7522 | const tag_field_ptr = self.builder.buildStructGEP(union_ptr, tag_index, ""); | 7565 | const tag_field_ptr = self.builder.buildStructGEP(union_ptr, tag_index, ""); |
| | 7566 | // TODO alignment on this store |
| 7523 | _ = self.builder.buildStore(new_tag, tag_field_ptr); | 7567 | _ = self.builder.buildStore(new_tag, tag_field_ptr); |
| 7524 | return null; | 7568 | return null; |
| 7525 | } | 7569 | } |
| ... | @@ -8336,17 +8380,9 @@ pub const FuncGen = struct { | ... | @@ -8336,17 +8380,9 @@ pub const FuncGen = struct { |
| 8336 | fn optIsNonNull(self: *FuncGen, opt_handle: *const llvm.Value, is_by_ref: bool) *const llvm.Value { | 8380 | fn optIsNonNull(self: *FuncGen, opt_handle: *const llvm.Value, is_by_ref: bool) *const llvm.Value { |
| 8337 | const field = b: { | 8381 | const field = b: { |
| 8338 | if (is_by_ref) { | 8382 | if (is_by_ref) { |
| 8339 | const index_type = self.context.intType(32); | 8383 | const field_ptr = self.builder.buildStructGEP(opt_handle, 1, ""); |
| 8340 | | | |
| 8341 | const indices: [2]*const llvm.Value = .{ | | |
| 8342 | index_type.constNull(), | | |
| 8343 | index_type.constInt(1, .False), | | |
| 8344 | }; | | |
| 8345 | | | |
| 8346 | const field_ptr = self.builder.buildInBoundsGEP(opt_handle, &indices, indices.len, ""); | | |
| 8347 | break :b self.builder.buildLoad(field_ptr, ""); | 8384 | break :b self.builder.buildLoad(field_ptr, ""); |
| 8348 | } | 8385 | } |
| 8349 | | | |
| 8350 | break :b self.builder.buildExtractValue(opt_handle, 1, ""); | 8386 | break :b self.builder.buildExtractValue(opt_handle, 1, ""); |
| 8351 | }; | 8387 | }; |
| 8352 | comptime assert(optional_layout_version == 3); | 8388 | comptime assert(optional_layout_version == 3); |
| ... | @@ -8355,18 +8391,63 @@ pub const FuncGen = struct { | ... | @@ -8355,18 +8391,63 @@ pub const FuncGen = struct { |
| 8355 | } | 8391 | } |
| 8356 | | 8392 | |
| 8357 | /// Assumes the optional is not pointer-like and payload has bits. | 8393 | /// Assumes the optional is not pointer-like and payload has bits. |
| 8358 | fn optPayloadHandle(self: *FuncGen, opt_handle: *const llvm.Value, is_by_ref: bool) *const llvm.Value { | 8394 | fn optPayloadHandle( |
| 8359 | if (is_by_ref) { | 8395 | fg: *FuncGen, |
| | 8396 | opt_handle: *const llvm.Value, |
| | 8397 | opt_ty: Type, |
| | 8398 | ) *const llvm.Value { |
| | 8399 | var buf: Type.Payload.ElemType = undefined; |
| | 8400 | const payload_ty = opt_ty.optionalChild(&buf); |
| | 8401 | |
| | 8402 | if (isByRef(opt_ty)) { |
| 8360 | // We have a pointer and we need to return a pointer to the first field. | 8403 | // We have a pointer and we need to return a pointer to the first field. |
| 8361 | const index_type = self.context.intType(32); | 8404 | const payload_ptr = fg.builder.buildStructGEP(opt_handle, 0, ""); |
| 8362 | const indices: [2]*const llvm.Value = .{ | 8405 | |
| 8363 | index_type.constNull(), // dereference the pointer | 8406 | if (isByRef(payload_ty)) { |
| 8364 | index_type.constNull(), // first field is the payload | 8407 | return payload_ptr; |
| 8365 | }; | 8408 | } |
| 8366 | return self.builder.buildInBoundsGEP(opt_handle, &indices, indices.len, ""); | 8409 | const target = fg.dg.module.getTarget(); |
| | 8410 | const payload_alignment = payload_ty.abiAlignment(target); |
| | 8411 | const load_inst = fg.builder.buildLoad(payload_ptr, ""); |
| | 8412 | load_inst.setAlignment(payload_alignment); |
| | 8413 | return load_inst; |
| | 8414 | } |
| | 8415 | |
| | 8416 | assert(!isByRef(payload_ty)); |
| | 8417 | return fg.builder.buildExtractValue(opt_handle, 0, ""); |
| | 8418 | } |
| | 8419 | |
| | 8420 | fn buildOptional( |
| | 8421 | self: *FuncGen, |
| | 8422 | optional_ty: Type, |
| | 8423 | payload: *const llvm.Value, |
| | 8424 | non_null_bit: *const llvm.Value, |
| | 8425 | ) !?*const llvm.Value { |
| | 8426 | const optional_llvm_ty = try self.dg.lowerType(optional_ty); |
| | 8427 | const non_null_field = self.builder.buildZExt(non_null_bit, self.dg.context.intType(8), ""); |
| | 8428 | |
| | 8429 | if (isByRef(optional_ty)) { |
| | 8430 | const target = self.dg.module.getTarget(); |
| | 8431 | const alloca_inst = self.buildAlloca(optional_llvm_ty); |
| | 8432 | const payload_alignment = optional_ty.abiAlignment(target); |
| | 8433 | alloca_inst.setAlignment(payload_alignment); |
| | 8434 | |
| | 8435 | { |
| | 8436 | const field_ptr = self.builder.buildStructGEP(alloca_inst, 0, ""); |
| | 8437 | const store_inst = self.builder.buildStore(payload, field_ptr); |
| | 8438 | store_inst.setAlignment(payload_alignment); |
| | 8439 | } |
| | 8440 | { |
| | 8441 | const field_ptr = self.builder.buildStructGEP(alloca_inst, 1, ""); |
| | 8442 | const store_inst = self.builder.buildStore(non_null_field, field_ptr); |
| | 8443 | store_inst.setAlignment(1); |
| | 8444 | } |
| | 8445 | |
| | 8446 | return alloca_inst; |
| 8367 | } | 8447 | } |
| 8368 | | 8448 | |
| 8369 | return self.builder.buildExtractValue(opt_handle, 0, ""); | 8449 | const partial = self.builder.buildInsertValue(optional_llvm_ty.getUndef(), payload, 0, ""); |
| | 8450 | return self.builder.buildInsertValue(partial, non_null_field, 1, ""); |
| 8370 | } | 8451 | } |
| 8371 | | 8452 | |
| 8372 | fn fieldPtr( | 8453 | fn fieldPtr( |
| ... | @@ -9275,10 +9356,12 @@ fn ccAbiPromoteInt( | ... | @@ -9275,10 +9356,12 @@ fn ccAbiPromoteInt( |
| 9275 | return null; | 9356 | return null; |
| 9276 | } | 9357 | } |
| 9277 | | 9358 | |
| | 9359 | /// This is the one source of truth for whether a type is passed around as an LLVM pointer, |
| | 9360 | /// or as an LLVM value. |
| 9278 | fn isByRef(ty: Type) bool { | 9361 | fn isByRef(ty: Type) bool { |
| 9279 | // For tuples and structs, if there are more than this many non-void | 9362 | // For tuples and structs, if there are more than this many non-void |
| 9280 | // fields, then we make it byref, otherwise byval. | 9363 | // fields, then we make it byref, otherwise byval. |
| 9281 | const max_fields_byval = 2; | 9364 | const max_fields_byval = 0; |
| 9282 | | 9365 | |
| 9283 | switch (ty.zigTypeTag()) { | 9366 | switch (ty.zigTypeTag()) { |
| 9284 | .Type, | 9367 | .Type, |
| ... | @@ -9332,10 +9415,23 @@ fn isByRef(ty: Type) bool { | ... | @@ -9332,10 +9415,23 @@ fn isByRef(ty: Type) bool { |
| 9332 | return false; | 9415 | return false; |
| 9333 | }, | 9416 | }, |
| 9334 | .Union => return ty.hasRuntimeBits(), | 9417 | .Union => return ty.hasRuntimeBits(), |
| 9335 | .ErrorUnion => return isByRef(ty.errorUnionPayload()), | 9418 | .ErrorUnion => { |
| | 9419 | const payload_ty = ty.errorUnionPayload(); |
| | 9420 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { |
| | 9421 | return false; |
| | 9422 | } |
| | 9423 | return true; |
| | 9424 | }, |
| 9336 | .Optional => { | 9425 | .Optional => { |
| 9337 | var buf: Type.Payload.ElemType = undefined; | 9426 | var buf: Type.Payload.ElemType = undefined; |
| 9338 | return isByRef(ty.optionalChild(&buf)); | 9427 | const payload_ty = ty.optionalChild(&buf); |
| | 9428 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { |
| | 9429 | return false; |
| | 9430 | } |
| | 9431 | if (ty.optionalReprIsPayload()) { |
| | 9432 | return false; |
| | 9433 | } |
| | 9434 | return true; |
| 9339 | }, | 9435 | }, |
| 9340 | } | 9436 | } |
| 9341 | } | 9437 | } |