Skip to content

Commit 24fe1d4

Browse files
authored
[SCCP] Infer return attributes in SCCP as well (#106732)
We can infer the range/nonnull attributes in non-interprocedural SCCP as well. The results may be better after the function has been simplified.
1 parent 87d9048 commit 24fe1d4

File tree

9 files changed

+57
-47
lines changed

9 files changed

+57
-47
lines changed

clang/test/CodeGen/attr-counted-by.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -639,7 +639,7 @@ void test6(struct anon_struct *p, int index) {
639639
p->array[index] = __builtin_dynamic_object_size(p->array, 1);
640640
}
641641

642-
// SANITIZE-WITH-ATTR-LABEL: define dso_local i64 @test6_bdos(
642+
// SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 0, -3) i64 @test6_bdos(
643643
// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]]) local_unnamed_addr #[[ATTR2]] {
644644
// SANITIZE-WITH-ATTR-NEXT: entry:
645645
// 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) {
649649
// SANITIZE-WITH-ATTR-NEXT: [[TMP1:%.*]] = select i1 [[DOTINV]], i64 0, i64 [[TMP0]]
650650
// SANITIZE-WITH-ATTR-NEXT: ret i64 [[TMP1]]
651651
//
652-
// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local i64 @test6_bdos(
652+
// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 0, -3) i64 @test6_bdos(
653653
// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]]) local_unnamed_addr #[[ATTR2]] {
654654
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
655655
// 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) {
955955
p->bytes[index] = (unsigned char)__builtin_dynamic_object_size(p->bytes, 1);
956956
}
957957

958-
// SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 -2147483648, 2147483648) i64 @test10_bdos(
958+
// SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 0, 2147483648) i64 @test10_bdos(
959959
// SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]]) local_unnamed_addr #[[ATTR2]] {
960960
// SANITIZE-WITH-ATTR-NEXT: entry:
961961
// 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) {
964964
// SANITIZE-WITH-ATTR-NEXT: [[TMP0:%.*]] = zext nneg i32 [[NARROW]] to i64
965965
// SANITIZE-WITH-ATTR-NEXT: ret i64 [[TMP0]]
966966
//
967-
// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 -2147483648, 2147483648) i64 @test10_bdos(
967+
// NO-SANITIZE-WITH-ATTR-LABEL: define dso_local range(i64 0, 2147483648) i64 @test10_bdos(
968968
// NO-SANITIZE-WITH-ATTR-SAME: ptr nocapture noundef readonly [[P:%.*]]) local_unnamed_addr #[[ATTR2]] {
969969
// NO-SANITIZE-WITH-ATTR-NEXT: entry:
970970
// NO-SANITIZE-WITH-ATTR-NEXT: [[DOT_COUNTED_BY_GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 8

llvm/include/llvm/Transforms/Utils/SCCPSolver.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ class SCCPSolver {
137137
const ValueLatticeElement &getLatticeValueFor(Value *V) const;
138138

139139
/// getTrackedRetVals - Get the inferred return value map.
140-
const MapVector<Function *, ValueLatticeElement> &getTrackedRetVals();
140+
const MapVector<Function *, ValueLatticeElement> &getTrackedRetVals() const;
141141

142142
/// getTrackedGlobals - Get and return the set of inferred initializers for
143143
/// global variables.
@@ -190,6 +190,8 @@ class SCCPSolver {
190190
bool removeNonFeasibleEdges(BasicBlock *BB, DomTreeUpdater &DTU,
191191
BasicBlock *&NewUnreachableBB) const;
192192

193+
void inferReturnAttributes() const;
194+
193195
bool tryToReplaceWithConstant(Value *V);
194196

195197
// Helper to check if \p LV is either a constant or a constant

llvm/lib/Transforms/IPO/SCCP.cpp

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -277,34 +277,10 @@ static bool runIPSCCP(
277277
// whether other functions are optimizable.
278278
SmallVector<ReturnInst*, 8> ReturnsToZap;
279279

280-
for (const auto &I : Solver.getTrackedRetVals()) {
281-
Function *F = I.first;
282-
const ValueLatticeElement &ReturnValue = I.second;
283-
284-
// If there is a known constant range for the return value, add range
285-
// attribute to the return value.
286-
if (ReturnValue.isConstantRange() &&
287-
!ReturnValue.getConstantRange().isSingleElement()) {
288-
// Do not add range metadata if the return value may include undef.
289-
if (ReturnValue.isConstantRangeIncludingUndef())
290-
continue;
291-
292-
// Take the intersection of the existing attribute and the inferred range.
293-
ConstantRange CR = ReturnValue.getConstantRange();
294-
if (F->hasRetAttribute(Attribute::Range))
295-
CR = CR.intersectWith(F->getRetAttribute(Attribute::Range).getRange());
296-
F->addRangeRetAttr(CR);
297-
continue;
298-
}
299-
// Infer nonnull return attribute.
300-
if (F->getReturnType()->isPointerTy() && ReturnValue.isNotConstant() &&
301-
ReturnValue.getNotConstant()->isNullValue() &&
302-
!F->hasRetAttribute(Attribute::NonNull)) {
303-
F->addRetAttr(Attribute::NonNull);
304-
continue;
305-
}
306-
if (F->getReturnType()->isVoidTy())
307-
continue;
280+
Solver.inferReturnAttributes();
281+
for (const auto &[F, ReturnValue] : Solver.getTrackedRetVals()) {
282+
assert(!F->getReturnType()->isVoidTy() &&
283+
"should not track void functions");
308284
if (SCCPSolver::isConstant(ReturnValue) || ReturnValue.isUnknownOrUndef())
309285
findReturnsToZap(*F, ReturnsToZap, Solver);
310286
}

llvm/lib/Transforms/Scalar/SCCP.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "llvm/Analysis/DomTreeUpdater.h"
2525
#include "llvm/Analysis/GlobalsModRef.h"
2626
#include "llvm/Analysis/TargetLibraryInfo.h"
27+
#include "llvm/Analysis/ValueLatticeUtils.h"
2728
#include "llvm/Analysis/ValueTracking.h"
2829
#include "llvm/IR/BasicBlock.h"
2930
#include "llvm/IR/Constant.h"
@@ -66,6 +67,11 @@ static bool runSCCP(Function &F, const DataLayout &DL,
6667
DL, [TLI](Function &F) -> const TargetLibraryInfo & { return *TLI; },
6768
F.getContext());
6869

70+
// While we don't do any actual inter-procedural analysis, still track
71+
// return values so we can infer attributes.
72+
if (canTrackReturnsInterprocedurally(&F))
73+
Solver.addTrackedFunction(&F);
74+
6975
// Mark the first block of the function as being executable.
7076
Solver.markBlockExecutable(&F.front());
7177

@@ -115,6 +121,8 @@ static bool runSCCP(Function &F, const DataLayout &DL,
115121
if (!DeadBB->hasAddressTaken())
116122
DTU.deleteBB(DeadBB);
117123

124+
Solver.inferReturnAttributes();
125+
118126
return MadeChanges;
119127
}
120128

llvm/lib/Transforms/Utils/SCCPSolver.cpp

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,34 @@ bool SCCPSolver::removeNonFeasibleEdges(BasicBlock *BB, DomTreeUpdater &DTU,
354354
return true;
355355
}
356356

357+
void SCCPSolver::inferReturnAttributes() const {
358+
for (const auto &[F, ReturnValue] : getTrackedRetVals()) {
359+
360+
// If there is a known constant range for the return value, add range
361+
// attribute to the return value.
362+
if (ReturnValue.isConstantRange() &&
363+
!ReturnValue.getConstantRange().isSingleElement()) {
364+
// Do not add range metadata if the return value may include undef.
365+
if (ReturnValue.isConstantRangeIncludingUndef())
366+
continue;
367+
368+
// Take the intersection of the existing attribute and the inferred range.
369+
ConstantRange CR = ReturnValue.getConstantRange();
370+
if (F->hasRetAttribute(Attribute::Range))
371+
CR = CR.intersectWith(F->getRetAttribute(Attribute::Range).getRange());
372+
F->addRangeRetAttr(CR);
373+
continue;
374+
}
375+
// Infer nonnull return attribute.
376+
if (F->getReturnType()->isPointerTy() && ReturnValue.isNotConstant() &&
377+
ReturnValue.getNotConstant()->isNullValue() &&
378+
!F->hasRetAttribute(Attribute::NonNull)) {
379+
F->addRetAttr(Attribute::NonNull);
380+
continue;
381+
}
382+
}
383+
}
384+
357385
/// Helper class for SCCPSolver. This implements the instruction visitor and
358386
/// holds all the state.
359387
class SCCPInstVisitor : public InstVisitor<SCCPInstVisitor> {
@@ -2168,7 +2196,7 @@ const ValueLatticeElement &SCCPSolver::getLatticeValueFor(Value *V) const {
21682196
}
21692197

21702198
const MapVector<Function *, ValueLatticeElement> &
2171-
SCCPSolver::getTrackedRetVals() {
2199+
SCCPSolver::getTrackedRetVals() const {
21722200
return Visitor->getTrackedRetVals();
21732201
}
21742202

llvm/test/Transforms/PhaseOrdering/icmp-ashr-breaking-select-idiom.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
; RUN: opt -O1 -S < %s | FileCheck %s
33

44
define i32 @testa(i32 %mul) {
5-
; CHECK-LABEL: define range(i32 -65536, 65536) i32 @testa(
5+
; CHECK-LABEL: define range(i32 -65536, 32768) i32 @testa(
66
; CHECK-SAME: i32 [[MUL:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
77
; CHECK-NEXT: [[SHR:%.*]] = ashr i32 [[MUL]], 15
88
; CHECK-NEXT: [[SPEC_SELECT_I:%.*]] = tail call i32 @llvm.smin.i32(i32 [[SHR]], i32 32767)
@@ -16,7 +16,7 @@ define i32 @testa(i32 %mul) {
1616
}
1717

1818
define i32 @testb(i32 %mul) {
19-
; CHECK-LABEL: define range(i32 -16777216, 16777216) i32 @testb(
19+
; CHECK-LABEL: define range(i32 -128, 128) i32 @testb(
2020
; CHECK-SAME: i32 [[MUL:%.*]]) local_unnamed_addr #[[ATTR0]] {
2121
; CHECK-NEXT: [[SHR102:%.*]] = ashr i32 [[MUL]], 7
2222
; CHECK-NEXT: [[TMP1:%.*]] = tail call i32 @llvm.smax.i32(i32 [[SHR102]], i32 -128)

llvm/test/Transforms/SCCP/exact-flags.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
; RUN: opt -passes=sccp < %s -S | FileCheck %s
33

44
define i8 @ashr_to_lshr(i8 %x, i8 %y) {
5-
; CHECK-LABEL: define i8 @ashr_to_lshr(
5+
; CHECK-LABEL: define range(i8 0, -128) i8 @ashr_to_lshr(
66
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
77
; CHECK-NEXT: [[P:%.*]] = and i8 [[X]], 127
88
; CHECK-NEXT: [[R:%.*]] = lshr exact i8 [[P]], [[Y]]
@@ -14,7 +14,7 @@ define i8 @ashr_to_lshr(i8 %x, i8 %y) {
1414
}
1515

1616
define i8 @sdiv_to_udiv(i8 %x, i8 %y) {
17-
; CHECK-LABEL: define i8 @sdiv_to_udiv(
17+
; CHECK-LABEL: define range(i8 0, -128) i8 @sdiv_to_udiv(
1818
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
1919
; CHECK-NEXT: [[X1:%.*]] = and i8 [[X]], 127
2020
; CHECK-NEXT: [[Y1:%.*]] = and i8 [[Y]], 127

llvm/test/Transforms/SCCP/phis.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ end:
100100
}
101101

102102
define <2 x i16> @phi_vector_merge1(i1 %c, <2 x i8> %a) {
103-
; CHECK-LABEL: define <2 x i16> @phi_vector_merge1(
103+
; CHECK-LABEL: define range(i16 2, 259) <2 x i16> @phi_vector_merge1(
104104
; CHECK-SAME: i1 [[C:%.*]], <2 x i8> [[A:%.*]]) {
105105
; CHECK-NEXT: [[ENTRY:.*]]:
106106
; CHECK-NEXT: [[ZEXT:%.*]] = zext <2 x i8> [[A]] to <2 x i16>
@@ -126,7 +126,7 @@ join:
126126
}
127127

128128
define <2 x i16> @phi_vector_merge2(i1 %c, <2 x i8> %a) {
129-
; CHECK-LABEL: define <2 x i16> @phi_vector_merge2(
129+
; CHECK-LABEL: define range(i16 2, 259) <2 x i16> @phi_vector_merge2(
130130
; CHECK-SAME: i1 [[C:%.*]], <2 x i8> [[A:%.*]]) {
131131
; CHECK-NEXT: [[ENTRY:.*]]:
132132
; CHECK-NEXT: [[ZEXT:%.*]] = zext <2 x i8> [[A]] to <2 x i16>

llvm/test/Transforms/SCCP/pointer-nonnull.ll

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -232,13 +232,9 @@ define i1 @ip_test_nonnull_caller(ptr %p) {
232232
}
233233

234234
define ptr @ret_nonnull_pointer(ptr nonnull %p) {
235-
; SCCP-LABEL: define ptr @ret_nonnull_pointer(
236-
; SCCP-SAME: ptr nonnull [[P:%.*]]) {
237-
; SCCP-NEXT: ret ptr [[P]]
238-
;
239-
; IPSCCP-LABEL: define nonnull ptr @ret_nonnull_pointer(
240-
; IPSCCP-SAME: ptr nonnull [[P:%.*]]) {
241-
; IPSCCP-NEXT: ret ptr [[P]]
235+
; CHECK-LABEL: define nonnull ptr @ret_nonnull_pointer(
236+
; CHECK-SAME: ptr nonnull [[P:%.*]]) {
237+
; CHECK-NEXT: ret ptr [[P]]
242238
;
243239
ret ptr %p
244240
}

0 commit comments

Comments
 (0)