diff --git a/llvm/lib/Transforms/Scalar/SCCP.cpp b/llvm/lib/Transforms/Scalar/SCCP.cpp --- a/llvm/lib/Transforms/Scalar/SCCP.cpp +++ b/llvm/lib/Transforms/Scalar/SCCP.cpp @@ -2054,9 +2054,40 @@ for (const auto &I : Solver.getTrackedRetVals()) { Function *F = I.first; - if (isOverdefined(I.second) || F->getReturnType()->isVoidTy()) + const ValueLatticeElement &ReturnValue = I.second; + + // If there is a known constant range for the return value, add !range + // metadata to the function's call sites. + if (ReturnValue.isConstantRange() && + !ReturnValue.getConstantRange().isSingleElement()) { + // Do not add range metadata if the return value may include undef. + if (ReturnValue.isConstantRangeIncludingUndef()) + continue; + + auto &CR = ReturnValue.getConstantRange(); + for (User *User : F->users()) { + auto *CB = dyn_cast(User); + if (!CB || CB->getCalledFunction() != F) + continue; + + // Do not touch existing metadata for now. + // TODO: We should be able to take the intersection of the existing + // metadata and the inferred range. + if (CB->getMetadata(LLVMContext::MD_range)) + continue; + + LLVMContext &Context = CB->getParent()->getContext(); + Metadata *RangeMD[] = { + ConstantAsMetadata::get(ConstantInt::get(Context, CR.getLower())), + ConstantAsMetadata::get(ConstantInt::get(Context, CR.getUpper()))}; + CB->setMetadata(LLVMContext::MD_range, MDNode::get(Context, RangeMD)); + } continue; - findReturnsToZap(*F, ReturnsToZap, Solver); + } + if (F->getReturnType()->isVoidTy()) + continue; + if (isConstant(ReturnValue) || ReturnValue.isUnknownOrUndef()) + findReturnsToZap(*F, ReturnsToZap, Solver); } for (auto F : Solver.getMRVFunctionsTracked()) { diff --git a/llvm/test/Transforms/SCCP/ip-add-range-to-call.ll b/llvm/test/Transforms/SCCP/ip-add-range-to-call.ll --- a/llvm/test/Transforms/SCCP/ip-add-range-to-call.ll +++ b/llvm/test/Transforms/SCCP/ip-add-range-to-call.ll @@ -1,4 +1,3 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -ipsccp -S %s | FileCheck %s ; Test 1. @@ -13,8 +12,8 @@ define i32 @caller1() { ; CHECK-LABEL: @caller1( -; CHECK-NEXT: [[C1:%.*]] = call i32 @callee(i32 10) -; CHECK-NEXT: [[C2:%.*]] = call i32 @callee(i32 20) +; CHECK-NEXT: [[C1:%.*]] = call i32 @callee(i32 10), !range [[RANGE_10_21:![0-9]+]] +; CHECK-NEXT: [[C2:%.*]] = call i32 @callee(i32 20), !range [[RANGE_10_21]] ; CHECK-NEXT: [[A:%.*]] = add i32 [[C1]], [[C2]] ; CHECK-NEXT: ret i32 [[A]] ; @@ -27,7 +26,7 @@ define i32 @caller2(i32 %x) { ; CHECK-LABEL: @caller2( ; CHECK-NEXT: [[X_15:%.*]] = and i32 [[X:%.*]], 15 -; CHECK-NEXT: [[C:%.*]] = call i32 @callee(i32 [[X_15]]) +; CHECK-NEXT: [[C:%.*]] = call i32 @callee(i32 [[X_15]]), !range [[RANGE_10_21]] ; CHECK-NEXT: ret i32 [[C]] ; %x.15 = and i32 %x, 15 @@ -52,7 +51,9 @@ define void @caller_cb1() { ; CHECK-LABEL: @caller_cb1( ; CHECK-NEXT: [[C1:%.*]] = call i32 @callee2(i32 9) +; CHECK-NOT: !range ; CHECK-NEXT: [[C2:%.*]] = call i32 @callee2(i32 10) +; CHECK-NOT: !range ; CHECK-NEXT: call void @use_cb1(i32 (i32)* @callee2) ; CHECK-NEXT: ret void ; @@ -82,8 +83,8 @@ define void @caller_cb2() { ; CHECK-LABEL: @caller_cb2( -; CHECK-NEXT: [[C1:%.*]] = call i32 @callee3(i32 9) -; CHECK-NEXT: [[C2:%.*]] = call i32 @callee3(i32 10) +; CHECK-NEXT: [[C1:%.*]] = call i32 @callee3(i32 9), !range [[RANGE_500_601:![0-9]+]] +; CHECK-NEXT: [[C2:%.*]] = call i32 @callee3(i32 10), !range [[RANGE_500_601]] ; CHECK-NEXT: call void @use_cb2(i32 (i32)* @callee3) ; CHECK-NEXT: ret void ; @@ -113,7 +114,9 @@ define void @caller_cb3() { ; CHECK-LABEL: @caller_cb3( ; CHECK-NEXT: [[C1:%.*]] = call i32 @callee4(i32 11, i32 30) +; CHECK-NOT: !range ; CHECK-NEXT: [[C2:%.*]] = call i32 @callee4(i32 12, i32 40) +; CHECK-NOT: !range ; CHECK-NEXT: call void @use_cb3(i32 (i32, i32)* @callee4) ; CHECK-NEXT: ret void ; @@ -155,7 +158,9 @@ define i32 @caller5() { ; CHECK-LABEL: @caller5( ; CHECK-NEXT: [[C1:%.*]] = call i32 @callee5(i32 10, i32 100) +; CHECK-NOT: !range ; CHECK-NEXT: [[C2:%.*]] = call i32 @callee5(i32 20, i32 200) +; CHECK-NOT: !range ; CHECK-NEXT: [[A:%.*]] = add i32 [[C1]], [[C2]] ; CHECK-NEXT: ret i32 [[A]] ; @@ -164,3 +169,6 @@ %a = add i32 %c1, %c2 ret i32 %a } + +; CHECK: [[RANGE_10_21]] = !{i32 0, i32 21} +; CHECK: [[RANGE_500_601]] = !{i32 500, i32 601}