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 @@ -33,6 +33,7 @@ #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/ValueLattice.h" #include "llvm/Analysis/ValueLatticeUtils.h" +#include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" @@ -2021,9 +2022,47 @@ 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; + + // Limit to cases where the return value is guaranteed to be neither + // poison nor undef. Poison will be outside any range and currently + // values outside of the specified range cause immediate undefined + // behavior. + if (!isGuaranteedNotToBeUndefOrPoison(CB, CB)) + 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,10 +1,9 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -ipsccp -S %s | FileCheck %s ; Test 1. ; Both arguments and return value of @callee can be tracked. The inferred range ; can be added to call sites. -define internal i32 @callee(i32 %x) { +define internal noundef i32 @callee(i32 %x) { ; CHECK-LABEL: @callee( ; CHECK-NEXT: ret i32 [[X:%.*]] ; @@ -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 @@ -42,7 +41,7 @@ declare void @use_cb1(i32 (i32)*) -define internal i32 @callee2(i32 %x) { +define internal noundef i32 @callee2(i32 %x) { ; CHECK-LABEL: @callee2( ; CHECK-NEXT: ret i32 [[X:%.*]] ; @@ -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 ; @@ -69,7 +70,7 @@ declare void @use_cb2(i32 (i32)*) -define internal i32 @callee3(i32 %x) { +define internal noundef i32 @callee3(i32 %x) { ; CHECK-LABEL: @callee3( ; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[X:%.*]], 10 ; CHECK-NEXT: [[S:%.*]] = select i1 [[C]], i32 500, i32 600 @@ -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 ; @@ -99,7 +100,7 @@ declare void @use_cb3(i32 (i32, i32)*) -define internal i32 @callee4(i32 %x, i32 %y) { +define internal noundef i32 @callee4(i32 %x, i32 %y) { ; CHECK-LABEL: @callee4( ; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[X:%.*]], 10 ; CHECK-NEXT: [[S:%.*]] = select i1 [[C]], i32 500, i32 [[Y:%.*]] @@ -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 ; @@ -126,7 +129,7 @@ ; Test 5. ; Range for the return value of callee5 includes undef. No range metadata ; should be added at call sites. -define internal i32 @callee5(i32 %x, i32 %y) { +define internal noundef i32 @callee5(i32 %x, i32 %y) { ; CHECK-LABEL: @callee5( ; CHECK-NEXT: [[C:%.*]] = icmp slt i32 [[X:%.*]], 15 ; CHECK-NEXT: br i1 [[C]], label [[BB1:%.*]], label [[BB2:%.*]] @@ -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}