[FunctionAttrs] Handle ConstantRange overflow in memset initializes inference (#145739)
Avoid constructing invalid ConstantRange when Offset + Length in memset overflows signed 64-bit integer space. This prevents assertion failures when inferring the initializes attribute. Fixes #140345
This commit is contained in:
parent
3702d64801
commit
e44fbea0a1
@ -675,14 +675,24 @@ ArgumentAccessInfo getArgumentAccessInfo(const Instruction *I,
|
|||||||
[](Value *Length,
|
[](Value *Length,
|
||||||
std::optional<int64_t> Offset) -> std::optional<ConstantRange> {
|
std::optional<int64_t> Offset) -> std::optional<ConstantRange> {
|
||||||
auto *ConstantLength = dyn_cast<ConstantInt>(Length);
|
auto *ConstantLength = dyn_cast<ConstantInt>(Length);
|
||||||
if (ConstantLength && Offset &&
|
if (ConstantLength && Offset) {
|
||||||
ConstantLength->getValue().isStrictlyPositive()) {
|
int64_t Len = ConstantLength->getSExtValue();
|
||||||
return ConstantRange(
|
|
||||||
APInt(64, *Offset, true),
|
// Reject zero or negative lengths
|
||||||
APInt(64, *Offset + ConstantLength->getSExtValue(), true));
|
if (Len <= 0)
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
APInt Low(64, *Offset, true);
|
||||||
|
bool Overflow;
|
||||||
|
APInt High = Low.sadd_ov(APInt(64, Len, true), Overflow);
|
||||||
|
if (Overflow)
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
return ConstantRange(Low, High);
|
||||||
}
|
}
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (auto *SI = dyn_cast<StoreInst>(I)) {
|
if (auto *SI = dyn_cast<StoreInst>(I)) {
|
||||||
if (SI->isSimple() && &SI->getOperandUse(1) == ArgUse.U) {
|
if (SI->isSimple() && &SI->getOperandUse(1) == ArgUse.U) {
|
||||||
// Get the fixed type size of "SI". Since the access range of a write
|
// Get the fixed type size of "SI". Since the access range of a write
|
||||||
|
@ -649,3 +649,17 @@ define void @range_overflows_signed_64_bit_int(ptr %arg) {
|
|||||||
store i32 0, ptr %getelementptr
|
store i32 0, ptr %getelementptr
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
; We should bail if the memset range overflows a signed 64-bit int.
|
||||||
|
define void @memset_large_offset_nonzero_size(ptr %dst) {
|
||||||
|
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
|
||||||
|
; CHECK-LABEL: define void @memset_large_offset_nonzero_size(
|
||||||
|
; CHECK-SAME: ptr writeonly captures(none) [[DST:%.*]]) #[[ATTR0]] {
|
||||||
|
; CHECK-NEXT: [[OFFSET:%.*]] = getelementptr inbounds i8, ptr [[DST]], i64 9223372036854775805
|
||||||
|
; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr [[OFFSET]], i8 0, i64 3, i1 false)
|
||||||
|
; CHECK-NEXT: ret void
|
||||||
|
;
|
||||||
|
%offset = getelementptr inbounds i8, ptr %dst, i64 9223372036854775805
|
||||||
|
call void @llvm.memset.p0.i64(ptr %offset, i8 0, i64 3, i1 false)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user