Index: llvm/lib/Transforms/IPO/SCCP.cpp =================================================================== --- llvm/lib/Transforms/IPO/SCCP.cpp +++ llvm/lib/Transforms/IPO/SCCP.cpp @@ -83,6 +83,14 @@ return !isOverdefined(LV); }); } + + // We don't consider assume-like intrinsics to be actual address + // captures. + if (auto *II = dyn_cast(U)) { + if (II->isAssumeLikeIntrinsic()) + return true; + } + return !isOverdefined(Solver.getLatticeValueFor(U)); }) && "We can only zap functions where all live users have a concrete value"); @@ -336,10 +344,18 @@ for (Argument &A : F->args()) F->removeParamAttr(A.getArgNo(), Attribute::Returned); for (Use &U : F->uses()) { - // Skip over blockaddr users. - if (isa(U.getUser())) + CallBase *CB = dyn_cast(U.getUser()); + if (!CB) { + assert(isa(U.getUser()) || + (isa(U.getUser()) && + all_of(U.getUser()->users(), [](const User *UserUser) { + return cast(UserUser)->isAssumeLikeIntrinsic(); + }))); continue; - CallBase *CB = cast(U.getUser()); + } + + // FIXME: Could this be a ConstantExpr cast user with a use in a call site + // that needs to be handled? for (Use &Arg : CB->args()) CB->removeParamAttr(CB->getArgOperandNo(&Arg), Attribute::Returned); } Index: llvm/test/Transforms/SCCP/issue59602-assume-like-call-users.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/SCCP/issue59602-assume-like-call-users.ll @@ -0,0 +1,62 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature +; RUN: opt -S -passes=ipsccp < %s | FileCheck %s + +@extern = global i32 0 + +define i32 @call_assume_self_user() { +; CHECK-LABEL: define {{[^@]+}}@call_assume_self_user() { +; CHECK-NEXT: [[CALL:%.*]] = call i32 @assume_self_user() +; CHECK-NEXT: ret i32 0 +; + %call = call i32 @assume_self_user() + ret i32 0 +} + +; Function address direct user is assume-like intrinsic. +; +; Make sure this doesn't hit "We can only zap functions where all live +; users have a concrete value" +define internal i32 @assume_self_user() { +; CHECK-LABEL: define {{[^@]+}}@assume_self_user() { +; CHECK-NEXT: [[OBJSIZE:%.*]] = call i32 @llvm.objectsize.i32.p0(ptr @assume_self_user, i1 false, i1 false, i1 false) +; CHECK-NEXT: store i32 [[OBJSIZE]], ptr @extern, align 4 +; CHECK-NEXT: ret i32 undef +; + %objsize = call i32 @llvm.objectsize.i32.p0(ptr @assume_self_user, i1 false, i1 false, i1 false) + store i32 %objsize, ptr @extern + ret i32 0 +} + + +; The objectsize call is an "assume like intrinsic" that can be +; ignored for address taken purposes. The user of @constexpr_self_user +; is a constant expression cast, so that the use call site does not +; directly appear as a user. + +define i32 @callsite_with_returned() { +; CHECK-LABEL: define {{[^@]+}}@callsite_with_returned() { +; CHECK-NEXT: [[CALL:%.*]] = call addrspace(1) i32 @constexpr_self_user(i32 123) +; CHECK-NEXT: ret i32 0 +; + %call = call addrspace(1) i32 @constexpr_self_user(i32 returned 123) + ret i32 0 +} + +; Has constexpr cast user in an assume-like intrinsic. Make sure we +; don't assert on a cast for the user, and still remove +; returned from the caller. +define internal i32 @constexpr_self_user(i32 %arg0) addrspace(1) { +; CHECK-LABEL: define {{[^@]+}}@constexpr_self_user +; CHECK-SAME: (i32 [[ARG0:%.*]]) addrspace(1) { +; CHECK-NEXT: [[OBJSIZE:%.*]] = call i32 @llvm.objectsize.i32.p0(ptr addrspacecast (ptr addrspace(1) @constexpr_self_user to ptr), i1 false, i1 false, i1 false) +; CHECK-NEXT: store i32 [[OBJSIZE]], ptr @extern, align 4 +; CHECK-NEXT: ret i32 undef +; + %objsize = call i32 @llvm.objectsize.i32.p0(ptr addrspacecast (ptr addrspace(1) @constexpr_self_user to ptr), i1 false, i1 false, i1 false) + store i32 %objsize, ptr @extern + ret i32 %arg0 +} + +declare i32 @llvm.objectsize.i32.p0(ptr, i1 immarg, i1 immarg, i1 immarg) #0 + +attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }