| ... | @@ -1419,8 +1419,6 @@ pub const Object = struct { | ... | @@ -1419,8 +1419,6 @@ pub const Object = struct { |
| 1419 | } | 1419 | } |
| 1420 | } | 1420 | } |
| 1421 | | 1421 | |
| 1422 | function_index.setAttributes(try attributes.finish(&o.builder), &o.builder); | | |
| 1423 | | | |
| 1424 | const file, const subprogram = if (!wip.strip) debug_info: { | 1422 | const file, const subprogram = if (!wip.strip) debug_info: { |
| 1425 | const file = try o.getDebugFile(file_scope); | 1423 | const file = try o.getDebugFile(file_scope); |
| 1426 | | 1424 | |
| ... | @@ -1517,6 +1515,17 @@ pub const Object = struct { | ... | @@ -1517,6 +1515,17 @@ pub const Object = struct { |
| 1517 | else => |e| return e, | 1515 | else => |e| return e, |
| 1518 | }; | 1516 | }; |
| 1519 | | 1517 | |
| | 1518 | // If we saw any loads or stores involving `allowzero` pointers, we need to mark the whole |
| | 1519 | // function as considering null pointers valid so that LLVM's optimizers don't remove these |
| | 1520 | // operations on the assumption that they're undefined behavior. |
| | 1521 | if (fg.allowzero_access) { |
| | 1522 | try attributes.addFnAttr(.null_pointer_is_valid, &o.builder); |
| | 1523 | } else { |
| | 1524 | _ = try attributes.removeFnAttr(.null_pointer_is_valid); |
| | 1525 | } |
| | 1526 | |
| | 1527 | function_index.setAttributes(try attributes.finish(&o.builder), &o.builder); |
| | 1528 | |
| 1520 | if (fg.fuzz) |*f| { | 1529 | if (fg.fuzz) |*f| { |
| 1521 | { | 1530 | { |
| 1522 | const array_llvm_ty = try o.builder.arrayType(f.pcs.items.len, .i8); | 1531 | const array_llvm_ty = try o.builder.arrayType(f.pcs.items.len, .i8); |
| ... | @@ -4667,6 +4676,15 @@ pub const FuncGen = struct { | ... | @@ -4667,6 +4676,15 @@ pub const FuncGen = struct { |
| 4667 | | 4676 | |
| 4668 | disable_intrinsics: bool, | 4677 | disable_intrinsics: bool, |
| 4669 | | 4678 | |
| | 4679 | /// Have we seen loads or stores involving `allowzero` pointers? |
| | 4680 | allowzero_access: bool = false, |
| | 4681 | |
| | 4682 | pub fn maybeMarkAllowZeroAccess(self: *FuncGen, info: InternPool.Key.PtrType) void { |
| | 4683 | // LLVM already considers null pointers to be valid in non-generic address spaces, so avoid |
| | 4684 | // pessimizing optimization for functions with accesses to such pointers. |
| | 4685 | if (info.flags.address_space == .generic and info.flags.is_allowzero) self.allowzero_access = true; |
| | 4686 | } |
| | 4687 | |
| 4670 | const Fuzz = struct { | 4688 | const Fuzz = struct { |
| 4671 | counters_variable: Builder.Variable.Index, | 4689 | counters_variable: Builder.Variable.Index, |
| 4672 | pcs: std.ArrayListUnmanaged(Builder.Constant), | 4690 | pcs: std.ArrayListUnmanaged(Builder.Constant), |
| ... | @@ -6206,6 +6224,9 @@ pub const FuncGen = struct { | ... | @@ -6206,6 +6224,9 @@ pub const FuncGen = struct { |
| 6206 | const body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]); | 6224 | const body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]); |
| 6207 | const err_union_ty = self.typeOf(extra.data.ptr).childType(zcu); | 6225 | const err_union_ty = self.typeOf(extra.data.ptr).childType(zcu); |
| 6208 | const is_unused = self.liveness.isUnused(inst); | 6226 | const is_unused = self.liveness.isUnused(inst); |
| | 6227 | |
| | 6228 | self.maybeMarkAllowZeroAccess(self.typeOf(extra.data.ptr).ptrInfo(zcu)); |
| | 6229 | |
| 6209 | return lowerTry(self, err_union_ptr, body, err_union_ty, true, true, is_unused, err_cold); | 6230 | return lowerTry(self, err_union_ptr, body, err_union_ty, true, true, is_unused, err_cold); |
| 6210 | } | 6231 | } |
| 6211 | | 6232 | |
| ... | @@ -6751,10 +6772,14 @@ pub const FuncGen = struct { | ... | @@ -6751,10 +6772,14 @@ pub const FuncGen = struct { |
| 6751 | if (self.canElideLoad(body_tail)) | 6772 | if (self.canElideLoad(body_tail)) |
| 6752 | return ptr; | 6773 | return ptr; |
| 6753 | | 6774 | |
| | 6775 | self.maybeMarkAllowZeroAccess(slice_ty.ptrInfo(zcu)); |
| | 6776 | |
| 6754 | const elem_alignment = elem_ty.abiAlignment(zcu).toLlvm(); | 6777 | const elem_alignment = elem_ty.abiAlignment(zcu).toLlvm(); |
| 6755 | return self.loadByRef(ptr, elem_ty, elem_alignment, .normal); | 6778 | return self.loadByRef(ptr, elem_ty, elem_alignment, .normal); |
| 6756 | } | 6779 | } |
| 6757 | | 6780 | |
| | 6781 | self.maybeMarkAllowZeroAccess(slice_ty.ptrInfo(zcu)); |
| | 6782 | |
| 6758 | return self.load(ptr, slice_ty); | 6783 | return self.load(ptr, slice_ty); |
| 6759 | } | 6784 | } |
| 6760 | | 6785 | |
| ... | @@ -6824,10 +6849,15 @@ pub const FuncGen = struct { | ... | @@ -6824,10 +6849,15 @@ pub const FuncGen = struct { |
| 6824 | &.{rhs}, ""); | 6849 | &.{rhs}, ""); |
| 6825 | if (isByRef(elem_ty, zcu)) { | 6850 | if (isByRef(elem_ty, zcu)) { |
| 6826 | if (self.canElideLoad(body_tail)) return ptr; | 6851 | if (self.canElideLoad(body_tail)) return ptr; |
| | 6852 | |
| | 6853 | self.maybeMarkAllowZeroAccess(ptr_ty.ptrInfo(zcu)); |
| | 6854 | |
| 6827 | const elem_alignment = elem_ty.abiAlignment(zcu).toLlvm(); | 6855 | const elem_alignment = elem_ty.abiAlignment(zcu).toLlvm(); |
| 6828 | return self.loadByRef(ptr, elem_ty, elem_alignment, .normal); | 6856 | return self.loadByRef(ptr, elem_ty, elem_alignment, .normal); |
| 6829 | } | 6857 | } |
| 6830 | | 6858 | |
| | 6859 | self.maybeMarkAllowZeroAccess(ptr_ty.ptrInfo(zcu)); |
| | 6860 | |
| 6831 | return self.load(ptr, ptr_ty); | 6861 | return self.load(ptr, ptr_ty); |
| 6832 | } | 6862 | } |
| 6833 | | 6863 | |
| ... | @@ -7235,6 +7265,8 @@ pub const FuncGen = struct { | ... | @@ -7235,6 +7265,8 @@ pub const FuncGen = struct { |
| 7235 | }), | 7265 | }), |
| 7236 | } | 7266 | } |
| 7237 | | 7267 | |
| | 7268 | self.maybeMarkAllowZeroAccess(output_ty.ptrInfo(zcu)); |
| | 7269 | |
| 7238 | // Pass any non-return outputs indirectly, if the constraint accepts a memory location | 7270 | // Pass any non-return outputs indirectly, if the constraint accepts a memory location |
| 7239 | is_indirect.* = constraintAllowsMemory(constraint); | 7271 | is_indirect.* = constraintAllowsMemory(constraint); |
| 7240 | if (is_indirect.*) { | 7272 | if (is_indirect.*) { |
| ... | @@ -7341,10 +7373,11 @@ pub const FuncGen = struct { | ... | @@ -7341,10 +7373,11 @@ pub const FuncGen = struct { |
| 7341 | | 7373 | |
| 7342 | // In the case of indirect inputs, LLVM requires the callsite to have | 7374 | // In the case of indirect inputs, LLVM requires the callsite to have |
| 7343 | // an elementtype(<ty>) attribute. | 7375 | // an elementtype(<ty>) attribute. |
| 7344 | llvm_param_attrs[llvm_param_i] = if (constraint[0] == '*') | 7376 | llvm_param_attrs[llvm_param_i] = if (constraint[0] == '*') blk: { |
| 7345 | try o.lowerPtrElemTy(if (is_by_ref) arg_ty else arg_ty.childType(zcu)) | 7377 | if (!is_by_ref) self.maybeMarkAllowZeroAccess(arg_ty.ptrInfo(zcu)); |
| 7346 | else | 7378 | |
| 7347 | .none; | 7379 | break :blk try o.lowerPtrElemTy(if (is_by_ref) arg_ty else arg_ty.childType(zcu)); |
| | 7380 | } else .none; |
| 7348 | | 7381 | |
| 7349 | llvm_param_i += 1; | 7382 | llvm_param_i += 1; |
| 7350 | total_i += 1; | 7383 | total_i += 1; |
| ... | @@ -7530,7 +7563,6 @@ pub const FuncGen = struct { | ... | @@ -7530,7 +7563,6 @@ pub const FuncGen = struct { |
| 7530 | if (output != .none) { | 7563 | if (output != .none) { |
| 7531 | const output_ptr = try self.resolveInst(output); | 7564 | const output_ptr = try self.resolveInst(output); |
| 7532 | const output_ptr_ty = self.typeOf(output); | 7565 | const output_ptr_ty = self.typeOf(output); |
| 7533 | | | |
| 7534 | const alignment = output_ptr_ty.ptrAlignment(zcu).toLlvm(); | 7566 | const alignment = output_ptr_ty.ptrAlignment(zcu).toLlvm(); |
| 7535 | _ = try self.wip.store(.normal, output_value, output_ptr, alignment); | 7567 | _ = try self.wip.store(.normal, output_value, output_ptr, alignment); |
| 7536 | } else { | 7568 | } else { |
| ... | @@ -7557,6 +7589,9 @@ pub const FuncGen = struct { | ... | @@ -7557,6 +7589,9 @@ pub const FuncGen = struct { |
| 7557 | const optional_ty = if (operand_is_ptr) operand_ty.childType(zcu) else operand_ty; | 7589 | const optional_ty = if (operand_is_ptr) operand_ty.childType(zcu) else operand_ty; |
| 7558 | const optional_llvm_ty = try o.lowerType(optional_ty); | 7590 | const optional_llvm_ty = try o.lowerType(optional_ty); |
| 7559 | const payload_ty = optional_ty.optionalChild(zcu); | 7591 | const payload_ty = optional_ty.optionalChild(zcu); |
| | 7592 | |
| | 7593 | if (operand_is_ptr) self.maybeMarkAllowZeroAccess(operand_ty.ptrInfo(zcu)); |
| | 7594 | |
| 7560 | if (optional_ty.optionalReprIsPayload(zcu)) { | 7595 | if (optional_ty.optionalReprIsPayload(zcu)) { |
| 7561 | const loaded = if (operand_is_ptr) | 7596 | const loaded = if (operand_is_ptr) |
| 7562 | try self.wip.load(.normal, optional_llvm_ty, operand, .default, "") | 7597 | try self.wip.load(.normal, optional_llvm_ty, operand, .default, "") |
| ... | @@ -7613,6 +7648,8 @@ pub const FuncGen = struct { | ... | @@ -7613,6 +7648,8 @@ pub const FuncGen = struct { |
| 7613 | return val.toValue(); | 7648 | return val.toValue(); |
| 7614 | } | 7649 | } |
| 7615 | | 7650 | |
| | 7651 | if (operand_is_ptr) self.maybeMarkAllowZeroAccess(operand_ty.ptrInfo(zcu)); |
| | 7652 | |
| 7616 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) { | 7653 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) { |
| 7617 | const loaded = if (operand_is_ptr) | 7654 | const loaded = if (operand_is_ptr) |
| 7618 | try self.wip.load(.normal, try o.lowerType(err_union_ty), operand, .default, "") | 7655 | try self.wip.load(.normal, try o.lowerType(err_union_ty), operand, .default, "") |
| ... | @@ -7664,6 +7701,8 @@ pub const FuncGen = struct { | ... | @@ -7664,6 +7701,8 @@ pub const FuncGen = struct { |
| 7664 | const payload_ty = optional_ty.optionalChild(zcu); | 7701 | const payload_ty = optional_ty.optionalChild(zcu); |
| 7665 | const non_null_bit = try o.builder.intValue(.i8, 1); | 7702 | const non_null_bit = try o.builder.intValue(.i8, 1); |
| 7666 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) { | 7703 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) { |
| | 7704 | self.maybeMarkAllowZeroAccess(self.typeOf(ty_op.operand).ptrInfo(zcu)); |
| | 7705 | |
| 7667 | // We have a pointer to a i8. We need to set it to 1 and then return the same pointer. | 7706 | // We have a pointer to a i8. We need to set it to 1 and then return the same pointer. |
| 7668 | _ = try self.wip.store(.normal, non_null_bit, operand, .default); | 7707 | _ = try self.wip.store(.normal, non_null_bit, operand, .default); |
| 7669 | return operand; | 7708 | return operand; |
| ... | @@ -7677,6 +7716,9 @@ pub const FuncGen = struct { | ... | @@ -7677,6 +7716,9 @@ pub const FuncGen = struct { |
| 7677 | // First set the non-null bit. | 7716 | // First set the non-null bit. |
| 7678 | const optional_llvm_ty = try o.lowerType(optional_ty); | 7717 | const optional_llvm_ty = try o.lowerType(optional_ty); |
| 7679 | const non_null_ptr = try self.wip.gepStruct(optional_llvm_ty, operand, 1, ""); | 7718 | const non_null_ptr = try self.wip.gepStruct(optional_llvm_ty, operand, 1, ""); |
| | 7719 | |
| | 7720 | self.maybeMarkAllowZeroAccess(self.typeOf(ty_op.operand).ptrInfo(zcu)); |
| | 7721 | |
| 7680 | // TODO set alignment on this store | 7722 | // TODO set alignment on this store |
| 7681 | _ = try self.wip.store(.normal, non_null_bit, non_null_ptr, .default); | 7723 | _ = try self.wip.store(.normal, non_null_bit, non_null_ptr, .default); |
| 7682 | | 7724 | |
| ... | @@ -7767,12 +7809,17 @@ pub const FuncGen = struct { | ... | @@ -7767,12 +7809,17 @@ pub const FuncGen = struct { |
| 7767 | const payload_ty = err_union_ty.errorUnionPayload(zcu); | 7809 | const payload_ty = err_union_ty.errorUnionPayload(zcu); |
| 7768 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) { | 7810 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) { |
| 7769 | if (!operand_is_ptr) return operand; | 7811 | if (!operand_is_ptr) return operand; |
| | 7812 | |
| | 7813 | self.maybeMarkAllowZeroAccess(operand_ty.ptrInfo(zcu)); |
| | 7814 | |
| 7770 | return self.wip.load(.normal, error_type, operand, .default, ""); | 7815 | return self.wip.load(.normal, error_type, operand, .default, ""); |
| 7771 | } | 7816 | } |
| 7772 | | 7817 | |
| 7773 | const offset = try errUnionErrorOffset(payload_ty, pt); | 7818 | const offset = try errUnionErrorOffset(payload_ty, pt); |
| 7774 | | 7819 | |
| 7775 | if (operand_is_ptr or isByRef(err_union_ty, zcu)) { | 7820 | if (operand_is_ptr or isByRef(err_union_ty, zcu)) { |
| | 7821 | if (operand_is_ptr) self.maybeMarkAllowZeroAccess(operand_ty.ptrInfo(zcu)); |
| | 7822 | |
| 7776 | const err_union_llvm_ty = try o.lowerType(err_union_ty); | 7823 | const err_union_llvm_ty = try o.lowerType(err_union_ty); |
| 7777 | const err_field_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, offset, ""); | 7824 | const err_field_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, offset, ""); |
| 7778 | return self.wip.load(.normal, error_type, err_field_ptr, .default, ""); | 7825 | return self.wip.load(.normal, error_type, err_field_ptr, .default, ""); |
| ... | @@ -7792,11 +7839,15 @@ pub const FuncGen = struct { | ... | @@ -7792,11 +7839,15 @@ pub const FuncGen = struct { |
| 7792 | const payload_ty = err_union_ty.errorUnionPayload(zcu); | 7839 | const payload_ty = err_union_ty.errorUnionPayload(zcu); |
| 7793 | const non_error_val = try o.builder.intValue(try o.errorIntType(), 0); | 7840 | const non_error_val = try o.builder.intValue(try o.errorIntType(), 0); |
| 7794 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) { | 7841 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) { |
| | 7842 | self.maybeMarkAllowZeroAccess(self.typeOf(ty_op.operand).ptrInfo(zcu)); |
| | 7843 | |
| 7795 | _ = try self.wip.store(.normal, non_error_val, operand, .default); | 7844 | _ = try self.wip.store(.normal, non_error_val, operand, .default); |
| 7796 | return operand; | 7845 | return operand; |
| 7797 | } | 7846 | } |
| 7798 | const err_union_llvm_ty = try o.lowerType(err_union_ty); | 7847 | const err_union_llvm_ty = try o.lowerType(err_union_ty); |
| 7799 | { | 7848 | { |
| | 7849 | self.maybeMarkAllowZeroAccess(self.typeOf(ty_op.operand).ptrInfo(zcu)); |
| | 7850 | |
| 7800 | const err_int_ty = try pt.errorIntType(); | 7851 | const err_int_ty = try pt.errorIntType(); |
| 7801 | const error_alignment = err_int_ty.abiAlignment(zcu).toLlvm(); | 7852 | const error_alignment = err_int_ty.abiAlignment(zcu).toLlvm(); |
| 7802 | const error_offset = try errUnionErrorOffset(payload_ty, pt); | 7853 | const error_offset = try errUnionErrorOffset(payload_ty, pt); |
| ... | @@ -8017,6 +8068,8 @@ pub const FuncGen = struct { | ... | @@ -8017,6 +8068,8 @@ pub const FuncGen = struct { |
| 8017 | const index = try self.resolveInst(extra.lhs); | 8068 | const index = try self.resolveInst(extra.lhs); |
| 8018 | const operand = try self.resolveInst(extra.rhs); | 8069 | const operand = try self.resolveInst(extra.rhs); |
| 8019 | | 8070 | |
| | 8071 | self.maybeMarkAllowZeroAccess(vector_ptr_ty.ptrInfo(zcu)); |
| | 8072 | |
| 8020 | const access_kind: Builder.MemoryAccessKind = | 8073 | const access_kind: Builder.MemoryAccessKind = |
| 8021 | if (vector_ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal; | 8074 | if (vector_ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal; |
| 8022 | const elem_llvm_ty = try o.lowerType(vector_ptr_ty.childType(zcu)); | 8075 | const elem_llvm_ty = try o.lowerType(vector_ptr_ty.childType(zcu)); |
| ... | @@ -9482,6 +9535,8 @@ pub const FuncGen = struct { | ... | @@ -9482,6 +9535,8 @@ pub const FuncGen = struct { |
| 9482 | return .none; | 9535 | return .none; |
| 9483 | } | 9536 | } |
| 9484 | | 9537 | |
| | 9538 | self.maybeMarkAllowZeroAccess(ptr_info); |
| | 9539 | |
| 9485 | const len = try o.builder.intValue(try o.lowerType(Type.usize), operand_ty.abiSize(zcu)); | 9540 | const len = try o.builder.intValue(try o.lowerType(Type.usize), operand_ty.abiSize(zcu)); |
| 9486 | _ = try self.wip.callMemSet( | 9541 | _ = try self.wip.callMemSet( |
| 9487 | dest_ptr, | 9542 | dest_ptr, |
| ... | @@ -9497,6 +9552,8 @@ pub const FuncGen = struct { | ... | @@ -9497,6 +9552,8 @@ pub const FuncGen = struct { |
| 9497 | return .none; | 9552 | return .none; |
| 9498 | } | 9553 | } |
| 9499 | | 9554 | |
| | 9555 | self.maybeMarkAllowZeroAccess(ptr_ty.ptrInfo(zcu)); |
| | 9556 | |
| 9500 | const src_operand = try self.resolveInst(bin_op.rhs); | 9557 | const src_operand = try self.resolveInst(bin_op.rhs); |
| 9501 | try self.store(dest_ptr, ptr_ty, src_operand, .none); | 9558 | try self.store(dest_ptr, ptr_ty, src_operand, .none); |
| 9502 | return .none; | 9559 | return .none; |
| ... | @@ -9539,6 +9596,9 @@ pub const FuncGen = struct { | ... | @@ -9539,6 +9596,9 @@ pub const FuncGen = struct { |
| 9539 | if (!canElideLoad(fg, body_tail)) break :elide; | 9596 | if (!canElideLoad(fg, body_tail)) break :elide; |
| 9540 | return ptr; | 9597 | return ptr; |
| 9541 | } | 9598 | } |
| | 9599 | |
| | 9600 | fg.maybeMarkAllowZeroAccess(ptr_info); |
| | 9601 | |
| 9542 | return fg.load(ptr, ptr_ty); | 9602 | return fg.load(ptr, ptr_ty); |
| 9543 | } | 9603 | } |
| 9544 | | 9604 | |
| ... | @@ -9598,6 +9658,8 @@ pub const FuncGen = struct { | ... | @@ -9598,6 +9658,8 @@ pub const FuncGen = struct { |
| 9598 | new_value = try self.wip.conv(signedness, new_value, llvm_abi_ty, ""); | 9658 | new_value = try self.wip.conv(signedness, new_value, llvm_abi_ty, ""); |
| 9599 | } | 9659 | } |
| 9600 | | 9660 | |
| | 9661 | self.maybeMarkAllowZeroAccess(ptr_ty.ptrInfo(zcu)); |
| | 9662 | |
| 9601 | const result = try self.wip.cmpxchg( | 9663 | const result = try self.wip.cmpxchg( |
| 9602 | kind, | 9664 | kind, |
| 9603 | if (ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal, | 9665 | if (ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal, |
| ... | @@ -9649,6 +9711,8 @@ pub const FuncGen = struct { | ... | @@ -9649,6 +9711,8 @@ pub const FuncGen = struct { |
| 9649 | if (ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal; | 9711 | if (ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal; |
| 9650 | const ptr_alignment = ptr_ty.ptrAlignment(zcu).toLlvm(); | 9712 | const ptr_alignment = ptr_ty.ptrAlignment(zcu).toLlvm(); |
| 9651 | | 9713 | |
| | 9714 | self.maybeMarkAllowZeroAccess(ptr_ty.ptrInfo(zcu)); |
| | 9715 | |
| 9652 | if (llvm_abi_ty != .none) { | 9716 | if (llvm_abi_ty != .none) { |
| 9653 | // operand needs widening and truncating or bitcasting. | 9717 | // operand needs widening and truncating or bitcasting. |
| 9654 | return self.wip.cast(if (is_float) .bitcast else .trunc, try self.wip.atomicrmw( | 9718 | return self.wip.cast(if (is_float) .bitcast else .trunc, try self.wip.atomicrmw( |
| ... | @@ -9712,6 +9776,8 @@ pub const FuncGen = struct { | ... | @@ -9712,6 +9776,8 @@ pub const FuncGen = struct { |
| 9712 | if (info.flags.is_volatile) .@"volatile" else .normal; | 9776 | if (info.flags.is_volatile) .@"volatile" else .normal; |
| 9713 | const elem_llvm_ty = try o.lowerType(elem_ty); | 9777 | const elem_llvm_ty = try o.lowerType(elem_ty); |
| 9714 | | 9778 | |
| | 9779 | self.maybeMarkAllowZeroAccess(info); |
| | 9780 | |
| 9715 | if (llvm_abi_ty != .none) { | 9781 | if (llvm_abi_ty != .none) { |
| 9716 | // operand needs widening and truncating | 9782 | // operand needs widening and truncating |
| 9717 | const loaded = try self.wip.loadAtomic( | 9783 | const loaded = try self.wip.loadAtomic( |
| ... | @@ -9761,6 +9827,9 @@ pub const FuncGen = struct { | ... | @@ -9761,6 +9827,9 @@ pub const FuncGen = struct { |
| 9761 | "", | 9827 | "", |
| 9762 | ); | 9828 | ); |
| 9763 | } | 9829 | } |
| | 9830 | |
| | 9831 | self.maybeMarkAllowZeroAccess(ptr_ty.ptrInfo(zcu)); |
| | 9832 | |
| 9764 | try self.store(ptr, ptr_ty, element, ordering); | 9833 | try self.store(ptr, ptr_ty, element, ordering); |
| 9765 | return .none; | 9834 | return .none; |
| 9766 | } | 9835 | } |
| ... | @@ -9778,6 +9847,8 @@ pub const FuncGen = struct { | ... | @@ -9778,6 +9847,8 @@ pub const FuncGen = struct { |
| 9778 | const access_kind: Builder.MemoryAccessKind = | 9847 | const access_kind: Builder.MemoryAccessKind = |
| 9779 | if (ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal; | 9848 | if (ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal; |
| 9780 | | 9849 | |
| | 9850 | self.maybeMarkAllowZeroAccess(ptr_ty.ptrInfo(zcu)); |
| | 9851 | |
| 9781 | if (try self.air.value(bin_op.rhs, pt)) |elem_val| { | 9852 | if (try self.air.value(bin_op.rhs, pt)) |elem_val| { |
| 9782 | if (elem_val.isUndefDeep(zcu)) { | 9853 | if (elem_val.isUndefDeep(zcu)) { |
| 9783 | // Even if safety is disabled, we still emit a memset to undefined since it conveys | 9854 | // Even if safety is disabled, we still emit a memset to undefined since it conveys |
| ... | @@ -9916,6 +9987,9 @@ pub const FuncGen = struct { | ... | @@ -9916,6 +9987,9 @@ pub const FuncGen = struct { |
| 9916 | const access_kind: Builder.MemoryAccessKind = if (src_ptr_ty.isVolatilePtr(zcu) or | 9987 | const access_kind: Builder.MemoryAccessKind = if (src_ptr_ty.isVolatilePtr(zcu) or |
| 9917 | dest_ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal; | 9988 | dest_ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal; |
| 9918 | | 9989 | |
| | 9990 | self.maybeMarkAllowZeroAccess(dest_ptr_ty.ptrInfo(zcu)); |
| | 9991 | self.maybeMarkAllowZeroAccess(src_ptr_ty.ptrInfo(zcu)); |
| | 9992 | |
| 9919 | _ = try self.wip.callMemCpy( | 9993 | _ = try self.wip.callMemCpy( |
| 9920 | dest_ptr, | 9994 | dest_ptr, |
| 9921 | dest_ptr_ty.ptrAlignment(zcu).toLlvm(), | 9995 | dest_ptr_ty.ptrAlignment(zcu).toLlvm(), |
| ... | @@ -9962,6 +10036,9 @@ pub const FuncGen = struct { | ... | @@ -9962,6 +10036,9 @@ pub const FuncGen = struct { |
| 9962 | const un_ty = self.typeOf(bin_op.lhs).childType(zcu); | 10036 | const un_ty = self.typeOf(bin_op.lhs).childType(zcu); |
| 9963 | const layout = un_ty.unionGetLayout(zcu); | 10037 | const layout = un_ty.unionGetLayout(zcu); |
| 9964 | if (layout.tag_size == 0) return .none; | 10038 | if (layout.tag_size == 0) return .none; |
| | 10039 | |
| | 10040 | self.maybeMarkAllowZeroAccess(self.typeOf(bin_op.lhs).ptrInfo(zcu)); |
| | 10041 | |
| 9965 | const union_ptr = try self.resolveInst(bin_op.lhs); | 10042 | const union_ptr = try self.resolveInst(bin_op.lhs); |
| 9966 | const new_tag = try self.resolveInst(bin_op.rhs); | 10043 | const new_tag = try self.resolveInst(bin_op.rhs); |
| 9967 | if (layout.payload_size == 0) { | 10044 | if (layout.payload_size == 0) { |