diff --git a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp index f918d7e059b6..f43202eea630 100644 --- a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp +++ b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp @@ -675,14 +675,24 @@ ArgumentAccessInfo getArgumentAccessInfo(const Instruction *I, [](Value *Length, std::optional Offset) -> std::optional { auto *ConstantLength = dyn_cast(Length); - if (ConstantLength && Offset && - ConstantLength->getValue().isStrictlyPositive()) { - return ConstantRange( - APInt(64, *Offset, true), - APInt(64, *Offset + ConstantLength->getSExtValue(), true)); + if (ConstantLength && Offset) { + int64_t Len = ConstantLength->getSExtValue(); + + // Reject zero or negative lengths + 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; }; + if (auto *SI = dyn_cast(I)) { if (SI->isSimple() && &SI->getOperandUse(1) == ArgUse.U) { // Get the fixed type size of "SI". Since the access range of a write diff --git a/llvm/test/Transforms/FunctionAttrs/initializes.ll b/llvm/test/Transforms/FunctionAttrs/initializes.ll index 5800bc1ca786..193d0fd58988 100644 --- a/llvm/test/Transforms/FunctionAttrs/initializes.ll +++ b/llvm/test/Transforms/FunctionAttrs/initializes.ll @@ -649,3 +649,17 @@ define void @range_overflows_signed_64_bit_int(ptr %arg) { store i32 0, ptr %getelementptr 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 +}