| ... | @@ -1499,7 +1499,7 @@ pub const Object = struct { | ... | @@ -1499,7 +1499,7 @@ pub const Object = struct { |
| 1499 | break :blk fwd_decl; | 1499 | break :blk fwd_decl; |
| 1500 | }; | 1500 | }; |
| 1501 | | 1501 | |
| 1502 | const non_null_ty = Type.bool; | 1502 | const non_null_ty = Type.u8; |
| 1503 | const payload_size = child_ty.abiSize(target); | 1503 | const payload_size = child_ty.abiSize(target); |
| 1504 | const payload_align = child_ty.abiAlignment(target); | 1504 | const payload_align = child_ty.abiAlignment(target); |
| 1505 | const non_null_size = non_null_ty.abiSize(target); | 1505 | const non_null_size = non_null_ty.abiSize(target); |
| ... | @@ -2530,16 +2530,16 @@ pub const DeclGen = struct { | ... | @@ -2530,16 +2530,16 @@ pub const DeclGen = struct { |
| 2530 | var buf: Type.Payload.ElemType = undefined; | 2530 | var buf: Type.Payload.ElemType = undefined; |
| 2531 | const child_ty = t.optionalChild(&buf); | 2531 | const child_ty = t.optionalChild(&buf); |
| 2532 | if (!child_ty.hasRuntimeBitsIgnoreComptime()) { | 2532 | if (!child_ty.hasRuntimeBitsIgnoreComptime()) { |
| 2533 | return dg.context.intType(1); | 2533 | return dg.context.intType(8); |
| 2534 | } | 2534 | } |
| 2535 | const payload_llvm_ty = try dg.lowerType(child_ty); | 2535 | const payload_llvm_ty = try dg.lowerType(child_ty); |
| 2536 | if (t.optionalReprIsPayload()) { | 2536 | if (t.optionalReprIsPayload()) { |
| 2537 | return payload_llvm_ty; | 2537 | return payload_llvm_ty; |
| 2538 | } | 2538 | } |
| 2539 | | 2539 | |
| 2540 | comptime assert(optional_layout_version == 2); | 2540 | comptime assert(optional_layout_version == 3); |
| 2541 | var fields_buf: [3]*const llvm.Type = .{ | 2541 | var fields_buf: [3]*const llvm.Type = .{ |
| 2542 | payload_llvm_ty, dg.context.intType(1), undefined, | 2542 | payload_llvm_ty, dg.context.intType(8), undefined, |
| 2543 | }; | 2543 | }; |
| 2544 | const offset = child_ty.abiSize(target) + 1; | 2544 | const offset = child_ty.abiSize(target) + 1; |
| 2545 | const abi_size = t.abiSize(target); | 2545 | const abi_size = t.abiSize(target); |
| ... | @@ -3134,12 +3134,13 @@ pub const DeclGen = struct { | ... | @@ -3134,12 +3134,13 @@ pub const DeclGen = struct { |
| 3134 | else => unreachable, | 3134 | else => unreachable, |
| 3135 | }, | 3135 | }, |
| 3136 | .Optional => { | 3136 | .Optional => { |
| 3137 | comptime assert(optional_layout_version == 2); | 3137 | comptime assert(optional_layout_version == 3); |
| 3138 | var buf: Type.Payload.ElemType = undefined; | 3138 | var buf: Type.Payload.ElemType = undefined; |
| 3139 | const payload_ty = tv.ty.optionalChild(&buf); | 3139 | const payload_ty = tv.ty.optionalChild(&buf); |
| 3140 | const llvm_i1 = dg.context.intType(1); | 3140 | |
| | 3141 | const llvm_i8 = dg.context.intType(8); |
| 3141 | const is_pl = !tv.val.isNull(); | 3142 | const is_pl = !tv.val.isNull(); |
| 3142 | const non_null_bit = if (is_pl) llvm_i1.constAllOnes() else llvm_i1.constNull(); | 3143 | const non_null_bit = if (is_pl) llvm_i8.constInt(1, .False) else llvm_i8.constNull(); |
| 3143 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 3144 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { |
| 3144 | return non_null_bit; | 3145 | return non_null_bit; |
| 3145 | } | 3146 | } |
| ... | @@ -4041,10 +4042,10 @@ pub const FuncGen = struct { | ... | @@ -4041,10 +4042,10 @@ pub const FuncGen = struct { |
| 4041 | .cmp_vector => try self.airCmpVector(inst), | 4042 | .cmp_vector => try self.airCmpVector(inst), |
| 4042 | .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst), | 4043 | .cmp_lt_errors_len => try self.airCmpLtErrorsLen(inst), |
| 4043 | | 4044 | |
| 4044 | .is_non_null => try self.airIsNonNull(inst, false, false, .NE), | 4045 | .is_non_null => try self.airIsNonNull(inst, false, .NE), |
| 4045 | .is_non_null_ptr => try self.airIsNonNull(inst, true , false, .NE), | 4046 | .is_non_null_ptr => try self.airIsNonNull(inst, true , .NE), |
| 4046 | .is_null => try self.airIsNonNull(inst, false, true , .EQ), | 4047 | .is_null => try self.airIsNonNull(inst, false, .EQ), |
| 4047 | .is_null_ptr => try self.airIsNonNull(inst, true , true , .EQ), | 4048 | .is_null_ptr => try self.airIsNonNull(inst, true , .EQ), |
| 4048 | | 4049 | |
| 4049 | .is_non_err => try self.airIsErr(inst, .EQ, false), | 4050 | .is_non_err => try self.airIsErr(inst, .EQ, false), |
| 4050 | .is_non_err_ptr => try self.airIsErr(inst, .EQ, true), | 4051 | .is_non_err_ptr => try self.airIsErr(inst, .EQ, true), |
| ... | @@ -5633,7 +5634,6 @@ pub const FuncGen = struct { | ... | @@ -5633,7 +5634,6 @@ pub const FuncGen = struct { |
| 5633 | self: *FuncGen, | 5634 | self: *FuncGen, |
| 5634 | inst: Air.Inst.Index, | 5635 | inst: Air.Inst.Index, |
| 5635 | operand_is_ptr: bool, | 5636 | operand_is_ptr: bool, |
| 5636 | invert: bool, | | |
| 5637 | pred: llvm.IntPredicate, | 5637 | pred: llvm.IntPredicate, |
| 5638 | ) !?*const llvm.Value { | 5638 | ) !?*const llvm.Value { |
| 5639 | if (self.liveness.isUnused(inst)) return null; | 5639 | if (self.liveness.isUnused(inst)) return null; |
| ... | @@ -5648,20 +5648,19 @@ pub const FuncGen = struct { | ... | @@ -5648,20 +5648,19 @@ pub const FuncGen = struct { |
| 5648 | return self.builder.buildICmp(pred, loaded, optional_llvm_ty.constNull(), ""); | 5648 | return self.builder.buildICmp(pred, loaded, optional_llvm_ty.constNull(), ""); |
| 5649 | } | 5649 | } |
| 5650 | | 5650 | |
| | 5651 | comptime assert(optional_layout_version == 3); |
| | 5652 | |
| 5651 | var buf: Type.Payload.ElemType = undefined; | 5653 | var buf: Type.Payload.ElemType = undefined; |
| 5652 | const payload_ty = optional_ty.optionalChild(&buf); | 5654 | const payload_ty = optional_ty.optionalChild(&buf); |
| 5653 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 5655 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { |
| 5654 | const loaded = if (operand_is_ptr) self.builder.buildLoad(operand, "") else operand; | 5656 | const loaded = if (operand_is_ptr) self.builder.buildLoad(operand, "") else operand; |
| 5655 | if (invert) { | 5657 | const llvm_i8 = self.dg.context.intType(8); |
| 5656 | return self.builder.buildNot(loaded, ""); | 5658 | return self.builder.buildICmp(pred, loaded, llvm_i8.constNull(), ""); |
| 5657 | } else { | | |
| 5658 | return loaded; | | |
| 5659 | } | | |
| 5660 | } | 5659 | } |
| 5661 | | 5660 | |
| 5662 | const is_by_ref = operand_is_ptr or isByRef(optional_ty); | 5661 | const is_by_ref = operand_is_ptr or isByRef(optional_ty); |
| 5663 | const non_null_bit = self.optIsNonNull(operand, is_by_ref); | 5662 | const non_null_bit = self.optIsNonNull(operand, is_by_ref); |
| 5664 | if (invert) { | 5663 | if (pred == .EQ) { |
| 5665 | return self.builder.buildNot(non_null_bit, ""); | 5664 | return self.builder.buildNot(non_null_bit, ""); |
| 5666 | } else { | 5665 | } else { |
| 5667 | return non_null_bit; | 5666 | return non_null_bit; |
| ... | @@ -5740,15 +5739,17 @@ pub const FuncGen = struct { | ... | @@ -5740,15 +5739,17 @@ pub const FuncGen = struct { |
| 5740 | } | 5739 | } |
| 5741 | | 5740 | |
| 5742 | fn airOptionalPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | 5741 | fn airOptionalPayloadPtrSet(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| | 5742 | comptime assert(optional_layout_version == 3); |
| | 5743 | |
| 5743 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 5744 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 5744 | const operand = try self.resolveInst(ty_op.operand); | 5745 | const operand = try self.resolveInst(ty_op.operand); |
| 5745 | const optional_ty = self.air.typeOf(ty_op.operand).childType(); | 5746 | const optional_ty = self.air.typeOf(ty_op.operand).childType(); |
| 5746 | const result_ty = self.air.getRefType(ty_op.ty); | 5747 | const result_ty = self.air.getRefType(ty_op.ty); |
| 5747 | var buf: Type.Payload.ElemType = undefined; | 5748 | var buf: Type.Payload.ElemType = undefined; |
| 5748 | const payload_ty = optional_ty.optionalChild(&buf); | 5749 | const payload_ty = optional_ty.optionalChild(&buf); |
| 5749 | const non_null_bit = self.context.intType(1).constAllOnes(); | 5750 | const non_null_bit = self.context.intType(8).constInt(1, .False); |
| 5750 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 5751 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { |
| 5751 | // We have a pointer to a i1. We need to set it to 1 and then return the same pointer. | 5752 | // We have a pointer to a i8. We need to set it to 1 and then return the same pointer. |
| 5752 | _ = self.builder.buildStore(non_null_bit, operand); | 5753 | _ = self.builder.buildStore(non_null_bit, operand); |
| 5753 | | 5754 | |
| 5754 | // TODO once we update to LLVM 14 this bitcast won't be necessary. | 5755 | // TODO once we update to LLVM 14 this bitcast won't be necessary. |
| ... | @@ -5914,8 +5915,8 @@ pub const FuncGen = struct { | ... | @@ -5914,8 +5915,8 @@ pub const FuncGen = struct { |
| 5914 | | 5915 | |
| 5915 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 5916 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 5916 | const payload_ty = self.air.typeOf(ty_op.operand); | 5917 | const payload_ty = self.air.typeOf(ty_op.operand); |
| 5917 | const non_null_bit = self.context.intType(1).constAllOnes(); | 5918 | const non_null_bit = self.context.intType(8).constInt(1, .False); |
| 5918 | comptime assert(optional_layout_version == 2); | 5919 | comptime assert(optional_layout_version == 3); |
| 5919 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return non_null_bit; | 5920 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return non_null_bit; |
| 5920 | const operand = try self.resolveInst(ty_op.operand); | 5921 | const operand = try self.resolveInst(ty_op.operand); |
| 5921 | const optional_ty = self.air.typeOfIndex(inst); | 5922 | const optional_ty = self.air.typeOfIndex(inst); |
| ... | @@ -7345,10 +7346,12 @@ pub const FuncGen = struct { | ... | @@ -7345,10 +7346,12 @@ pub const FuncGen = struct { |
| 7345 | return self.builder.buildSelect(success_bit, payload.typeOf().constNull(), payload, ""); | 7346 | return self.builder.buildSelect(success_bit, payload.typeOf().constNull(), payload, ""); |
| 7346 | } | 7347 | } |
| 7347 | | 7348 | |
| | 7349 | comptime assert(optional_layout_version == 3); |
| 7348 | const optional_llvm_ty = try self.dg.lowerType(optional_ty); | 7350 | const optional_llvm_ty = try self.dg.lowerType(optional_ty); |
| 7349 | const non_null_bit = self.builder.buildNot(success_bit, ""); | 7351 | 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), ""); |
| 7350 | const partial = self.builder.buildInsertValue(optional_llvm_ty.getUndef(), payload, 0, ""); | 7353 | const partial = self.builder.buildInsertValue(optional_llvm_ty.getUndef(), payload, 0, ""); |
| 7351 | return self.builder.buildInsertValue(partial, non_null_bit, 1, ""); | 7354 | return self.builder.buildInsertValue(partial, non_null_field, 1, ""); |
| 7352 | } | 7355 | } |
| 7353 | | 7356 | |
| 7354 | fn airAtomicRmw(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | 7357 | fn airAtomicRmw(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| ... | @@ -8331,19 +8334,24 @@ pub const FuncGen = struct { | ... | @@ -8331,19 +8334,24 @@ pub const FuncGen = struct { |
| 8331 | | 8334 | |
| 8332 | /// Assumes the optional is not pointer-like and payload has bits. | 8335 | /// Assumes the optional is not pointer-like and payload has bits. |
| 8333 | fn optIsNonNull(self: *FuncGen, opt_handle: *const llvm.Value, is_by_ref: bool) *const llvm.Value { | 8336 | fn optIsNonNull(self: *FuncGen, opt_handle: *const llvm.Value, is_by_ref: bool) *const llvm.Value { |
| 8334 | if (is_by_ref) { | 8337 | const field = b: { |
| 8335 | const index_type = self.context.intType(32); | 8338 | if (is_by_ref) { |
| | 8339 | const index_type = self.context.intType(32); |
| 8336 | | 8340 | |
| 8337 | const indices: [2]*const llvm.Value = .{ | 8341 | const indices: [2]*const llvm.Value = .{ |
| 8338 | index_type.constNull(), | 8342 | index_type.constNull(), |
| 8339 | index_type.constInt(1, .False), | 8343 | index_type.constInt(1, .False), |
| 8340 | }; | 8344 | }; |
| 8341 | | 8345 | |
| 8342 | const field_ptr = self.builder.buildInBoundsGEP(opt_handle, &indices, indices.len, ""); | 8346 | const field_ptr = self.builder.buildInBoundsGEP(opt_handle, &indices, indices.len, ""); |
| 8343 | return self.builder.buildLoad(field_ptr, ""); | 8347 | break :b self.builder.buildLoad(field_ptr, ""); |
| 8344 | } | 8348 | } |
| | 8349 | |
| | 8350 | break :b self.builder.buildExtractValue(opt_handle, 1, ""); |
| | 8351 | }; |
| | 8352 | comptime assert(optional_layout_version == 3); |
| 8345 | | 8353 | |
| 8346 | return self.builder.buildExtractValue(opt_handle, 1, ""); | 8354 | return self.builder.buildICmp(.NE, field, self.context.intType(8).constInt(0, .False), ""); |
| 8347 | } | 8355 | } |
| 8348 | | 8356 | |
| 8349 | /// Assumes the optional is not pointer-like and payload has bits. | 8357 | /// Assumes the optional is not pointer-like and payload has bits. |
| ... | @@ -9369,7 +9377,10 @@ fn intrinsicsAllowed(scalar_ty: Type, target: std.Target) bool { | ... | @@ -9369,7 +9377,10 @@ fn intrinsicsAllowed(scalar_ty: Type, target: std.Target) bool { |
| 9369 | /// We can do this because for all types, Zig ABI alignment >= LLVM ABI | 9377 | /// We can do this because for all types, Zig ABI alignment >= LLVM ABI |
| 9370 | /// alignment. | 9378 | /// alignment. |
| 9371 | const struct_layout_version = 2; | 9379 | const struct_layout_version = 2; |
| 9372 | const optional_layout_version = 2; | 9380 | |
| | 9381 | // TODO: Restore the non_null field to i1 once |
| | 9382 | // https://github.com/llvm/llvm-project/issues/56585/ is fixed |
| | 9383 | const optional_layout_version = 3; |
| 9373 | | 9384 | |
| 9374 | /// We use the least significant bit of the pointer address to tell us | 9385 | /// We use the least significant bit of the pointer address to tell us |
| 9375 | /// whether the type is fully resolved. Types that are only fwd declared | 9386 | /// whether the type is fully resolved. Types that are only fwd declared |