Index: lib/Transforms/Utils/SimplifyLibCalls.cpp =================================================================== --- lib/Transforms/Utils/SimplifyLibCalls.cpp +++ lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -189,15 +189,22 @@ static void annotateDereferenceableBytes(CallInst *CI, ArrayRef ArgNos, uint64_t DereferenceableBytes) { + Function *F = CI->getFunction(); + if (!F) + return; for (unsigned ArgNo : ArgNos) { - uint64_t DerefBytes = std::max( - CI->getDereferenceableOrNullBytes(ArgNo + AttributeList::FirstArgIndex), - DereferenceableBytes); + uint64_t DerefBytes = DereferenceableBytes; + unsigned AS = CI->getArgOperand(ArgNo)->getType()->getPointerAddressSpace(); + if (!llvm::NullPointerIsDefined(F, AS)) + DerefBytes = std::max(CI->getDereferenceableOrNullBytes( + ArgNo + AttributeList::FirstArgIndex), + DereferenceableBytes); if (CI->getDereferenceableBytes(ArgNo + AttributeList::FirstArgIndex) < DerefBytes) { CI->removeParamAttr(ArgNo, Attribute::Dereferenceable); - CI->removeParamAttr(ArgNo, Attribute::DereferenceableOrNull); + if (llvm::NullPointerIsDefined(F, AS)) + CI->removeParamAttr(ArgNo, Attribute::DereferenceableOrNull); CI->addParamAttr(ArgNo, Attribute::getWithDereferenceableBytes( CI->getContext(), DerefBytes)); } Index: test/Transforms/InstCombine/mem-deref-bytes-addrspaces.ll =================================================================== --- test/Transforms/InstCombine/mem-deref-bytes-addrspaces.ll +++ test/Transforms/InstCombine/mem-deref-bytes-addrspaces.ll @@ -0,0 +1,13 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -instcombine -S < %s | FileCheck %s + +declare i32 @memcmp(i8 addrspace(1)* nocapture, i8* nocapture, i64) + +define i32 @memcmp_const_size_update_deref8(i8 addrspace(1)* nocapture readonly %d, i8* nocapture readonly %s) "null-pointer-is-valid"="true" { +; CHECK-LABEL: @memcmp_const_size_update_deref8( +; CHECK-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8 addrspace(1)* dereferenceable(16) [[D:%.*]], i8* dereferenceable(16) [[S:%.*]], i64 16) +; CHECK-NEXT: ret i32 [[CALL]] +; + %call = tail call i32 @memcmp(i8 addrspace(1)* dereferenceable_or_null(40) %d, i8* %s, i64 16) + ret i32 %call +} Index: test/Transforms/InstCombine/mem-deref-bytes.ll =================================================================== --- test/Transforms/InstCombine/mem-deref-bytes.ll +++ test/Transforms/InstCombine/mem-deref-bytes.ll @@ -30,7 +30,7 @@ define i32 @memcmp_const_size_update_deref2(i8* nocapture readonly %d, i8* nocapture readonly %s) { ; CHECK-LABEL: @memcmp_const_size_update_deref2( -; CHECK-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8* dereferenceable(16) [[D:%.*]], i8* dereferenceable(16) [[S:%.*]], i64 16) +; CHECK-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8* dereferenceable(16) [[D:%.*]], i8* dereferenceable(16) dereferenceable_or_null(8) [[S:%.*]], i64 16) ; CHECK-NEXT: ret i32 [[CALL]] ; %call = tail call i32 @memcmp(i8* %d, i8* dereferenceable_or_null(8) %s, i64 16) @@ -48,16 +48,25 @@ define i32 @memcmp_const_size_update_deref4(i8* nocapture readonly %d, i8* nocapture readonly %s) { ; CHECK-LABEL: @memcmp_const_size_update_deref4( -; CHECK-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8* dereferenceable(16) [[D:%.*]], i8* dereferenceable(16) [[S:%.*]], i64 16) +; CHECK-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8* dereferenceable(16) dereferenceable_or_null(16) [[D:%.*]], i8* dereferenceable(16) [[S:%.*]], i64 16) ; CHECK-NEXT: ret i32 [[CALL]] ; %call = tail call i32 @memcmp(i8* dereferenceable_or_null(16) %d, i8* %s, i64 16) ret i32 %call } -define i32 @memcmp_const_size_update_deref5(i8* nocapture readonly %d, i8* nocapture readonly %s) { +define i32 @memcmp_const_size_update_deref5(i8* nocapture readonly %d, i8* nocapture readonly %s) "null-pointer-is-valid"="false" { ; CHECK-LABEL: @memcmp_const_size_update_deref5( -; CHECK-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8* dereferenceable(40) [[D:%.*]], i8* dereferenceable(16) [[S:%.*]], i64 16) +; CHECK-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8* dereferenceable(40) dereferenceable_or_null(40) [[D:%.*]], i8* dereferenceable(16) [[S:%.*]], i64 16) +; CHECK-NEXT: ret i32 [[CALL]] +; + %call = tail call i32 @memcmp(i8* dereferenceable_or_null(40) %d, i8* %s, i64 16) + ret i32 %call +} + +define i32 @memcmp_const_size_update_deref6(i8* nocapture readonly %d, i8* nocapture readonly %s) "null-pointer-is-valid"="true" { +; CHECK-LABEL: @memcmp_const_size_update_deref6( +; CHECK-NEXT: [[CALL:%.*]] = tail call i32 @memcmp(i8* dereferenceable(16) [[D:%.*]], i8* dereferenceable(16) [[S:%.*]], i64 16) ; CHECK-NEXT: ret i32 [[CALL]] ; %call = tail call i32 @memcmp(i8* dereferenceable_or_null(40) %d, i8* %s, i64 16)