Skip to content

Commit e44fbea

Browse files
authored
[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
1 parent 3702d64 commit e44fbea

File tree

2 files changed

+29
-5
lines changed

2 files changed

+29
-5
lines changed

llvm/lib/Transforms/IPO/FunctionAttrs.cpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -675,14 +675,24 @@ ArgumentAccessInfo getArgumentAccessInfo(const Instruction *I,
675675
[](Value *Length,
676676
std::optional<int64_t> Offset) -> std::optional<ConstantRange> {
677677
auto *ConstantLength = dyn_cast<ConstantInt>(Length);
678-
if (ConstantLength && Offset &&
679-
ConstantLength->getValue().isStrictlyPositive()) {
680-
return ConstantRange(
681-
APInt(64, *Offset, true),
682-
APInt(64, *Offset + ConstantLength->getSExtValue(), true));
678+
if (ConstantLength && Offset) {
679+
int64_t Len = ConstantLength->getSExtValue();
680+
681+
// Reject zero or negative lengths
682+
if (Len <= 0)
683+
return std::nullopt;
684+
685+
APInt Low(64, *Offset, true);
686+
bool Overflow;
687+
APInt High = Low.sadd_ov(APInt(64, Len, true), Overflow);
688+
if (Overflow)
689+
return std::nullopt;
690+
691+
return ConstantRange(Low, High);
683692
}
684693
return std::nullopt;
685694
};
695+
686696
if (auto *SI = dyn_cast<StoreInst>(I)) {
687697
if (SI->isSimple() && &SI->getOperandUse(1) == ArgUse.U) {
688698
// Get the fixed type size of "SI". Since the access range of a write

llvm/test/Transforms/FunctionAttrs/initializes.ll

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,3 +649,17 @@ define void @range_overflows_signed_64_bit_int(ptr %arg) {
649649
store i32 0, ptr %getelementptr
650650
ret void
651651
}
652+
653+
; We should bail if the memset range overflows a signed 64-bit int.
654+
define void @memset_large_offset_nonzero_size(ptr %dst) {
655+
; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write)
656+
; CHECK-LABEL: define void @memset_large_offset_nonzero_size(
657+
; CHECK-SAME: ptr writeonly captures(none) [[DST:%.*]]) #[[ATTR0]] {
658+
; CHECK-NEXT: [[OFFSET:%.*]] = getelementptr inbounds i8, ptr [[DST]], i64 9223372036854775805
659+
; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr [[OFFSET]], i8 0, i64 3, i1 false)
660+
; CHECK-NEXT: ret void
661+
;
662+
%offset = getelementptr inbounds i8, ptr %dst, i64 9223372036854775805
663+
call void @llvm.memset.p0.i64(ptr %offset, i8 0, i64 3, i1 false)
664+
ret void
665+
}

0 commit comments

Comments
 (0)