https://github.com/nikic updated https://github.com/llvm/llvm-project/pull/106732
>From 50efbbd59ed639d9604f3b13faf1fb8be60161e7 Mon Sep 17 00:00:00 2001 From: Nikita Popov <npo...@redhat.com> Date: Fri, 30 Aug 2024 12:46:53 +0200 Subject: [PATCH 1/3] [SCCP] Infer return attributes in SCCP as well We can infer the range/nonnull attributes in non-interprocedural SCCP as well. The results may be better after the function has been simplified. --- .../llvm/Transforms/Utils/SCCPSolver.h | 4 ++- llvm/lib/Transforms/IPO/SCCP.cpp | 28 ++-------------- llvm/lib/Transforms/Scalar/SCCP.cpp | 8 +++++ llvm/lib/Transforms/Utils/SCCPSolver.cpp | 32 ++++++++++++++++++- .../icmp-ashr-breaking-select-idiom.ll | 4 +-- llvm/test/Transforms/SCCP/exact-flags.ll | 4 +-- llvm/test/Transforms/SCCP/phis.ll | 4 +-- llvm/test/Transforms/SCCP/pointer-nonnull.ll | 10 ++---- 8 files changed, 54 insertions(+), 40 deletions(-) diff --git a/llvm/include/llvm/Transforms/Utils/SCCPSolver.h b/llvm/include/llvm/Transforms/Utils/SCCPSolver.h index 1f959311295258..61a500b82875fb 100644 --- a/llvm/include/llvm/Transforms/Utils/SCCPSolver.h +++ b/llvm/include/llvm/Transforms/Utils/SCCPSolver.h @@ -137,7 +137,7 @@ class SCCPSolver { const ValueLatticeElement &getLatticeValueFor(Value *V) const; /// getTrackedRetVals - Get the inferred return value map. - const MapVector<Function *, ValueLatticeElement> &getTrackedRetVals(); + const MapVector<Function *, ValueLatticeElement> &getTrackedRetVals() const; /// getTrackedGlobals - Get and return the set of inferred initializers for /// global variables. @@ -190,6 +190,8 @@ class SCCPSolver { bool removeNonFeasibleEdges(BasicBlock *BB, DomTreeUpdater &DTU, BasicBlock *&NewUnreachableBB) const; + void inferReturnAttributes() const; + bool tryToReplaceWithConstant(Value *V); // Helper to check if \p LV is either a constant or a constant diff --git a/llvm/lib/Transforms/IPO/SCCP.cpp b/llvm/lib/Transforms/IPO/SCCP.cpp index 5ef08c4a2d725d..cbf511c53d29da 100644 --- a/llvm/lib/Transforms/IPO/SCCP.cpp +++ b/llvm/lib/Transforms/IPO/SCCP.cpp @@ -277,34 +277,12 @@ static bool runIPSCCP( // whether other functions are optimizable. SmallVector<ReturnInst*, 8> ReturnsToZap; + Solver.inferReturnAttributes(); for (const auto &I : Solver.getTrackedRetVals()) { Function *F = I.first; const ValueLatticeElement &ReturnValue = I.second; - - // If there is a known constant range for the return value, add range - // attribute to the return value. - if (ReturnValue.isConstantRange() && - !ReturnValue.getConstantRange().isSingleElement()) { - // Do not add range metadata if the return value may include undef. - if (ReturnValue.isConstantRangeIncludingUndef()) - continue; - - // Take the intersection of the existing attribute and the inferred range. - ConstantRange CR = ReturnValue.getConstantRange(); - if (F->hasRetAttribute(Attribute::Range)) - CR = CR.intersectWith(F->getRetAttribute(Attribute::Range).getRange()); - F->addRangeRetAttr(CR); - continue; - } - // Infer nonnull return attribute. - if (F->getReturnType()->isPointerTy() && ReturnValue.isNotConstant() && - ReturnValue.getNotConstant()->isNullValue() && - !F->hasRetAttribute(Attribute::NonNull)) { - F->addRetAttr(Attribute::NonNull); - continue; - } - if (F->getReturnType()->isVoidTy()) - continue; + assert(!F->getReturnType()->isVoidTy() && + "should not track void functions"); if (SCCPSolver::isConstant(ReturnValue) || ReturnValue.isUnknownOrUndef()) findReturnsToZap(*F, ReturnsToZap, Solver); } diff --git a/llvm/lib/Transforms/Scalar/SCCP.cpp b/llvm/lib/Transforms/Scalar/SCCP.cpp index caf9f890418e29..0330460e7df8ab 100644 --- a/llvm/lib/Transforms/Scalar/SCCP.cpp +++ b/llvm/lib/Transforms/Scalar/SCCP.cpp @@ -24,6 +24,7 @@ #include "llvm/Analysis/DomTreeUpdater.h" #include "llvm/Analysis/GlobalsModRef.h" #include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/Analysis/ValueLatticeUtils.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constant.h" @@ -66,6 +67,11 @@ static bool runSCCP(Function &F, const DataLayout &DL, DL, [TLI](Function &F) -> const TargetLibraryInfo & { return *TLI; }, F.getContext()); + // While we don't do any actual inter-procedural analysis, still track + // return values so we can infer attributes. + if (canTrackReturnsInterprocedurally(&F)) + Solver.addTrackedFunction(&F); + // Mark the first block of the function as being executable. Solver.markBlockExecutable(&F.front()); @@ -115,6 +121,8 @@ static bool runSCCP(Function &F, const DataLayout &DL, if (!DeadBB->hasAddressTaken()) DTU.deleteBB(DeadBB); + Solver.inferReturnAttributes(); + return MadeChanges; } diff --git a/llvm/lib/Transforms/Utils/SCCPSolver.cpp b/llvm/lib/Transforms/Utils/SCCPSolver.cpp index 59775d2199ca61..5cb0fc3ec5d633 100644 --- a/llvm/lib/Transforms/Utils/SCCPSolver.cpp +++ b/llvm/lib/Transforms/Utils/SCCPSolver.cpp @@ -354,6 +354,36 @@ bool SCCPSolver::removeNonFeasibleEdges(BasicBlock *BB, DomTreeUpdater &DTU, return true; } +void SCCPSolver::inferReturnAttributes() const { + for (const auto &I : getTrackedRetVals()) { + Function *F = I.first; + const ValueLatticeElement &ReturnValue = I.second; + + // If there is a known constant range for the return value, add range + // attribute to the return value. + if (ReturnValue.isConstantRange() && + !ReturnValue.getConstantRange().isSingleElement()) { + // Do not add range metadata if the return value may include undef. + if (ReturnValue.isConstantRangeIncludingUndef()) + continue; + + // Take the intersection of the existing attribute and the inferred range. + ConstantRange CR = ReturnValue.getConstantRange(); + if (F->hasRetAttribute(Attribute::Range)) + CR = CR.intersectWith(F->getRetAttribute(Attribute::Range).getRange()); + F->addRangeRetAttr(CR); + continue; + } + // Infer nonnull return attribute. + if (F->getReturnType()->isPointerTy() && ReturnValue.isNotConstant() && + ReturnValue.getNotConstant()->isNullValue() && + !F->hasRetAttribute(Attribute::NonNull)) { + F->addRetAttr(Attribute::NonNull); + continue; + } + } +} + /// Helper class for SCCPSolver. This implements the instruction visitor and /// holds all the state. class SCCPInstVisitor : public InstVisitor<SCCPInstVisitor> { @@ -2168,7 +2198,7 @@ const ValueLatticeElement &SCCPSolver::getLatticeValueFor(Value *V) const { } const MapVector<Function *, ValueLatticeElement> & -SCCPSolver::getTrackedRetVals() { +SCCPSolver::getTrackedRetVals() const { return Visitor->getTrackedRetVals(); } diff --git a/llvm/test/Transforms/PhaseOrdering/icmp-ashr-breaking-select-idiom.ll b/llvm/test/Transforms/PhaseOrdering/icmp-ashr-breaking-select-idiom.ll index 35d5ceeb91950f..871615dbd62852 100644 --- a/llvm/test/Transforms/PhaseOrdering/icmp-ashr-breaking-select-idiom.ll +++ b/llvm/test/Transforms/PhaseOrdering/icmp-ashr-breaking-select-idiom.ll @@ -2,7 +2,7 @@ ; RUN: opt -O1 -S < %s | FileCheck %s define i32 @testa(i32 %mul) { -; CHECK-LABEL: define range(i32 -65536, 65536) i32 @testa( +; CHECK-LABEL: define range(i32 -65536, 32768) i32 @testa( ; CHECK-SAME: i32 [[MUL:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { ; CHECK-NEXT: [[SHR:%.*]] = ashr i32 [[MUL]], 15 ; CHECK-NEXT: [[SPEC_SELECT_I:%.*]] = tail call i32 @llvm.smin.i32(i32 [[SHR]], i32 32767) @@ -16,7 +16,7 @@ define i32 @testa(i32 %mul) { } define i32 @testb(i32 %mul) { -; CHECK-LABEL: define range(i32 -16777216, 16777216) i32 @testb( +; CHECK-LABEL: define range(i32 -128, 128) i32 @testb( ; CHECK-SAME: i32 [[MUL:%.*]]) local_unnamed_addr #[[ATTR0]] { ; CHECK-NEXT: [[SHR102:%.*]] = ashr i32 [[MUL]], 7 ; CHECK-NEXT: [[TMP1:%.*]] = tail call i32 @llvm.smax.i32(i32 [[SHR102]], i32 -128) diff --git a/llvm/test/Transforms/SCCP/exact-flags.ll b/llvm/test/Transforms/SCCP/exact-flags.ll index a5e3bf111bbd9d..f860ddb6fe9cfb 100644 --- a/llvm/test/Transforms/SCCP/exact-flags.ll +++ b/llvm/test/Transforms/SCCP/exact-flags.ll @@ -2,7 +2,7 @@ ; RUN: opt -passes=sccp < %s -S | FileCheck %s define i8 @ashr_to_lshr(i8 %x, i8 %y) { -; CHECK-LABEL: define i8 @ashr_to_lshr( +; CHECK-LABEL: define range(i8 0, -128) i8 @ashr_to_lshr( ; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) { ; CHECK-NEXT: [[P:%.*]] = and i8 [[X]], 127 ; CHECK-NEXT: [[R:%.*]] = lshr exact i8 [[P]], [[Y]] @@ -14,7 +14,7 @@ define i8 @ashr_to_lshr(i8 %x, i8 %y) { } define i8 @sdiv_to_udiv(i8 %x, i8 %y) { -; CHECK-LABEL: define i8 @sdiv_to_udiv( +; CHECK-LABEL: define range(i8 0, -128) i8 @sdiv_to_udiv( ; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) { ; CHECK-NEXT: [[X1:%.*]] = and i8 [[X]], 127 ; CHECK-NEXT: [[Y1:%.*]] = and i8 [[Y]], 127 diff --git a/llvm/test/Transforms/SCCP/phis.ll b/llvm/test/Transforms/SCCP/phis.ll index 9264a6eaefb85d..dae843ca955955 100644 --- a/llvm/test/Transforms/SCCP/phis.ll +++ b/llvm/test/Transforms/SCCP/phis.ll @@ -100,7 +100,7 @@ end: } define <2 x i16> @phi_vector_merge1(i1 %c, <2 x i8> %a) { -; CHECK-LABEL: define <2 x i16> @phi_vector_merge1( +; CHECK-LABEL: define range(i16 2, 259) <2 x i16> @phi_vector_merge1( ; CHECK-SAME: i1 [[C:%.*]], <2 x i8> [[A:%.*]]) { ; CHECK-NEXT: [[ENTRY:.*]]: ; CHECK-NEXT: [[ZEXT:%.*]] = zext <2 x i8> [[A]] to <2 x i16> @@ -126,7 +126,7 @@ join: } define <2 x i16> @phi_vector_merge2(i1 %c, <2 x i8> %a) { -; CHECK-LABEL: define <2 x i16> @phi_vector_merge2( +; CHECK-LABEL: define range(i16 2, 259) <2 x i16> @phi_vector_merge2( ; CHECK-SAME: i1 [[C:%.*]], <2 x i8> [[A:%.*]]) { ; CHECK-NEXT: [[ENTRY:.*]]: ; CHECK-NEXT: [[ZEXT:%.*]] = zext <2 x i8> [[A]] to <2 x i16> diff --git a/llvm/test/Transforms/SCCP/pointer-nonnull.ll b/llvm/test/Transforms/SCCP/pointer-nonnull.ll index 08d4a76345bb63..c3a6a762e31744 100644 --- a/llvm/test/Transforms/SCCP/pointer-nonnull.ll +++ b/llvm/test/Transforms/SCCP/pointer-nonnull.ll @@ -232,13 +232,9 @@ define i1 @ip_test_nonnull_caller(ptr %p) { } define ptr @ret_nonnull_pointer(ptr nonnull %p) { -; SCCP-LABEL: define ptr @ret_nonnull_pointer( -; SCCP-SAME: ptr nonnull [[P:%.*]]) { -; SCCP-NEXT: ret ptr [[P]] -; -; IPSCCP-LABEL: define nonnull ptr @ret_nonnull_pointer( -; IPSCCP-SAME: ptr nonnull [[P:%.*]]) { -; IPSCCP-NEXT: ret ptr [[P]] +; CHECK-LABEL: define nonnull ptr @ret_nonnull_pointer( +; CHECK-SAME: ptr nonnull [[P:%.*]]) { +; CHECK-NEXT: ret ptr [[P]] ; ret ptr %p } >From 9eaece6cbfd90618ab2683fa5f2d0ade2c03258c Mon Sep 17 00:00:00 2001 From: Nikita Popov <npo...@redhat.com> Date: Fri, 30 Aug 2024 17:15:32 +0200 Subject: [PATCH 2/3] Update clang test --- clang/test/CodeGen/attr-counted-by.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clang/test/CodeGen/attr-counted-by.c b/clang/test/CodeGen/attr-counted-by.c index 3ed8b6f0c71861..ab36b6e7720ba3 100644 --- a/clang/test/CodeGen/attr-counted-by.c +++ b/clang/test/CodeGen/attr-counted-by.c @@ -639,7 +639,7 @@ void test6(struct anon_struct *p, int index) { p->array[index] = __builtin_dynamic_object_size(p->array, 1); } -// SANITIZE-WITH-ATTR-LABEL: define dso_local i64 @test6_bdos( +// SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 0, -3) i64 @test6_bdos( // SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]]) local_unnamed_addr #[[ATTR2]] { // SANITIZE-WITH-ATTR-NEXT: entry: // SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8 @@ -649,7 +649,7 @@ void test6(struct anon_struct *p, int index) { // SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = select i1 [[DOTINV]], i64 0, i64 [[TMP0]] // SANITIZE-WITH-ATTR-NEXT: ret i64 [[TMP1]] // -// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i64 @test6_bdos( +// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 0, -3) i64 @test6_bdos( // NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]]) local_unnamed_addr #[[ATTR2]] { // NO-SANITIZE-WITH-ATTR-NEXT: entry: // NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8 @@ -955,7 +955,7 @@ void test10(struct union_of_fams *p, int index) { p->bytes[index] = (unsigned char)__builtin_dynamic_object_size(p->bytes, 1); } -// SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 -2147483648, 2147483648) i64 @test10_bdos( +// SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 0, 2147483648) i64 @test10_bdos( // SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]]) local_unnamed_addr #[[ATTR2]] { // SANITIZE-WITH-ATTR-NEXT: entry: // SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8 @@ -964,7 +964,7 @@ void test10(struct union_of_fams *p, int index) { // SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = zext nneg i32 [[NARROW]] to i64 // SANITIZE-WITH-ATTR-NEXT: ret i64 [[TMP0]] // -// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 -2147483648, 2147483648) i64 @test10_bdos( +// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 0, 2147483648) i64 @test10_bdos( // NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]]) local_unnamed_addr #[[ATTR2]] { // NO-SANITIZE-WITH-ATTR-NEXT: entry: // NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8 >From 5e3508fb1b91829a5e639974c35da13c18c94f5d Mon Sep 17 00:00:00 2001 From: Nikita Popov <git...@npopov.com> Date: Mon, 2 Sep 2024 09:48:08 +0200 Subject: [PATCH 3/3] Apply suggestions from code review Co-authored-by: Yingwei Zheng <dtcx...@qq.com> --- llvm/lib/Transforms/IPO/SCCP.cpp | 4 +--- llvm/lib/Transforms/Utils/SCCPSolver.cpp | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/llvm/lib/Transforms/IPO/SCCP.cpp b/llvm/lib/Transforms/IPO/SCCP.cpp index cbf511c53d29da..f0d75a2016363a 100644 --- a/llvm/lib/Transforms/IPO/SCCP.cpp +++ b/llvm/lib/Transforms/IPO/SCCP.cpp @@ -278,9 +278,7 @@ static bool runIPSCCP( SmallVector<ReturnInst*, 8> ReturnsToZap; Solver.inferReturnAttributes(); - for (const auto &I : Solver.getTrackedRetVals()) { - Function *F = I.first; - const ValueLatticeElement &ReturnValue = I.second; + for (const auto &[F, ReturnValue] : Solver.getTrackedRetVals()) { assert(!F->getReturnType()->isVoidTy() && "should not track void functions"); if (SCCPSolver::isConstant(ReturnValue) || ReturnValue.isUnknownOrUndef()) diff --git a/llvm/lib/Transforms/Utils/SCCPSolver.cpp b/llvm/lib/Transforms/Utils/SCCPSolver.cpp index 5cb0fc3ec5d633..56e1f90f46cfd1 100644 --- a/llvm/lib/Transforms/Utils/SCCPSolver.cpp +++ b/llvm/lib/Transforms/Utils/SCCPSolver.cpp @@ -355,9 +355,7 @@ bool SCCPSolver::removeNonFeasibleEdges(BasicBlock *BB, DomTreeUpdater &DTU, } void SCCPSolver::inferReturnAttributes() const { - for (const auto &I : getTrackedRetVals()) { - Function *F = I.first; - const ValueLatticeElement &ReturnValue = I.second; + for (const auto &[F, ReturnValue] : getTrackedRetVals()) { // If there is a known constant range for the return value, add range // attribute to the return value. _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits