Skip to content

Commit b7cc3b1

Browse files
committed
[Attributor][FIX] Avoid empty bin in AAPointerInfo
This avoid creating empty bins in AAPointerInfo which can lead to segfaults. Also ensure we do not try to translate from callee to caller except if we really take the argument state and move it to the call site argument state. Fixes: llvm#55726
1 parent 0830103 commit b7cc3b1

File tree

2 files changed

+90
-19
lines changed

2 files changed

+90
-19
lines changed

llvm/lib/Transforms/IPO/AttributorAttributes.cpp

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1272,33 +1272,36 @@ struct AAPointerInfoImpl
12721272
return true;
12731273
}
12741274

1275-
ChangeStatus translateAndAddCalleeState(Attributor &A,
1276-
const AAPointerInfo &CalleeAA,
1277-
int64_t CallArgOffset, CallBase &CB) {
1275+
ChangeStatus translateAndAddState(Attributor &A, const AAPointerInfo &OtherAA,
1276+
int64_t Offset, CallBase &CB,
1277+
bool FromCallee = false) {
12781278
using namespace AA::PointerInfo;
1279-
if (!CalleeAA.getState().isValidState() || !isValidState())
1279+
if (!OtherAA.getState().isValidState() || !isValidState())
12801280
return indicatePessimisticFixpoint();
12811281

1282-
const auto &CalleeImplAA = static_cast<const AAPointerInfoImpl &>(CalleeAA);
1283-
bool IsByval = CalleeImplAA.getAssociatedArgument()->hasByValAttr();
1282+
const auto &OtherAAImpl = static_cast<const AAPointerInfoImpl &>(OtherAA);
1283+
bool IsByval =
1284+
FromCallee && OtherAAImpl.getAssociatedArgument()->hasByValAttr();
12841285

12851286
// Combine the accesses bin by bin.
12861287
ChangeStatus Changed = ChangeStatus::UNCHANGED;
1287-
for (auto &It : CalleeImplAA.getState()) {
1288+
for (auto &It : OtherAAImpl.getState()) {
12881289
OffsetAndSize OAS = OffsetAndSize::getUnknown();
1289-
if (CallArgOffset != OffsetAndSize::Unknown)
1290-
OAS = OffsetAndSize(It.first.getOffset() + CallArgOffset,
1291-
It.first.getSize());
1292-
Accesses *Bin = AccessBins[OAS];
1290+
if (Offset != OffsetAndSize::Unknown)
1291+
OAS = OffsetAndSize(It.first.getOffset() + Offset, It.first.getSize());
1292+
Accesses *Bin = AccessBins.lookup(OAS);
12931293
for (const AAPointerInfo::Access &RAcc : *It.second) {
12941294
if (IsByval && !RAcc.isRead())
12951295
continue;
12961296
bool UsedAssumedInformation = false;
1297-
Optional<Value *> Content = A.translateArgumentToCallSiteContent(
1298-
RAcc.getContent(), CB, *this, UsedAssumedInformation);
1299-
AccessKind AK =
1300-
AccessKind(RAcc.getKind() & (IsByval ? AccessKind::AK_READ
1301-
: AccessKind::AK_READ_WRITE));
1297+
AccessKind AK = RAcc.getKind();
1298+
Optional<Value *> Content = RAcc.getContent();
1299+
if (FromCallee) {
1300+
Content = A.translateArgumentToCallSiteContent(
1301+
RAcc.getContent(), CB, *this, UsedAssumedInformation);
1302+
AK = AccessKind(
1303+
AK & (IsByval ? AccessKind::AK_READ : AccessKind::AK_READ_WRITE));
1304+
}
13021305
Changed =
13031306
Changed | addAccess(A, OAS.getOffset(), OAS.getSize(), CB, Content,
13041307
AK, RAcc.getType(), RAcc.getRemoteInst(), Bin);
@@ -1493,8 +1496,8 @@ struct AAPointerInfoFloating : public AAPointerInfoImpl {
14931496
const auto &CSArgPI = A.getAAFor<AAPointerInfo>(
14941497
*this, IRPosition::callsite_argument(*CB, ArgNo),
14951498
DepClassTy::REQUIRED);
1496-
Changed = translateAndAddCalleeState(
1497-
A, CSArgPI, OffsetInfoMap[CurPtr].Offset, *CB) |
1499+
Changed = translateAndAddState(A, CSArgPI,
1500+
OffsetInfoMap[CurPtr].Offset, *CB) |
14981501
Changed;
14991502
return true;
15001503
}
@@ -1623,7 +1626,8 @@ struct AAPointerInfoCallSiteArgument final : AAPointerInfoFloating {
16231626
const IRPosition &ArgPos = IRPosition::argument(*Arg);
16241627
auto &ArgAA =
16251628
A.getAAFor<AAPointerInfo>(*this, ArgPos, DepClassTy::REQUIRED);
1626-
return translateAndAddCalleeState(A, ArgAA, 0, *cast<CallBase>(getCtxI()));
1629+
return translateAndAddState(A, ArgAA, 0, *cast<CallBase>(getCtxI()),
1630+
/* FromCallee */ true);
16271631
}
16281632

16291633
/// See AbstractAttribute::trackStatistics()
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
2+
; RUN: opt -attributor -enable-new-pm=0 -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
3+
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
4+
; RUN: opt -attributor-cgscc -enable-new-pm=0 -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
5+
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
6+
7+
%struct.test.b = type { i32, i32 }
8+
%struct.test.a = type { %struct.test.b, i32, i8*}
9+
10+
define void @foo(i8* %ptr) {
11+
; IS__TUNIT____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
12+
; IS__TUNIT____-LABEL: define {{[^@]+}}@foo
13+
; IS__TUNIT____-SAME: (i8* nocapture nofree readnone [[PTR:%.*]]) #[[ATTR0:[0-9]+]] {
14+
; IS__TUNIT____-NEXT: entry:
15+
; IS__TUNIT____-NEXT: [[TMP0:%.*]] = alloca [[STRUCT_TEST_A:%.*]], align 8
16+
; IS__TUNIT____-NEXT: br label [[CALL_BR:%.*]]
17+
; IS__TUNIT____: call.br:
18+
; IS__TUNIT____-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_TEST_A]], %struct.test.a* [[TMP0]], i64 0, i32 2
19+
; IS__TUNIT____-NEXT: tail call void @bar(%struct.test.a* noalias nocapture nofree noundef nonnull readonly byval([[STRUCT_TEST_A]]) align 8 dereferenceable(24) [[TMP0]]) #[[ATTR2:[0-9]+]]
20+
; IS__TUNIT____-NEXT: ret void
21+
;
22+
; IS__CGSCC____: Function Attrs: nofree nosync nounwind readnone willreturn
23+
; IS__CGSCC____-LABEL: define {{[^@]+}}@foo
24+
; IS__CGSCC____-SAME: (i8* nocapture nofree writeonly [[PTR:%.*]]) #[[ATTR0:[0-9]+]] {
25+
; IS__CGSCC____-NEXT: entry:
26+
; IS__CGSCC____-NEXT: [[TMP0:%.*]] = alloca [[STRUCT_TEST_A:%.*]], align 8
27+
; IS__CGSCC____-NEXT: br label [[CALL_BR:%.*]]
28+
; IS__CGSCC____: call.br:
29+
; IS__CGSCC____-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_TEST_A]], %struct.test.a* [[TMP0]], i64 0, i32 2
30+
; IS__CGSCC____-NEXT: store i8* [[PTR]], i8** [[TMP1]], align 8
31+
; IS__CGSCC____-NEXT: tail call void @bar(%struct.test.a* noalias nocapture nofree noundef nonnull readnone byval([[STRUCT_TEST_A]]) align 8 dereferenceable(24) [[TMP0]]) #[[ATTR2:[0-9]+]]
32+
; IS__CGSCC____-NEXT: ret void
33+
;
34+
entry:
35+
%0 = alloca %struct.test.a, align 8
36+
br label %call.br
37+
38+
call.br:
39+
%1 = getelementptr inbounds %struct.test.a, %struct.test.a* %0, i64 0, i32 2
40+
store i8* %ptr, i8** %1
41+
tail call void @bar(%struct.test.a* noundef byval(%struct.test.a) align 8 %0)
42+
ret void
43+
}
44+
45+
define void @bar(%struct.test.a* noundef byval(%struct.test.a) align 8 %dev) {
46+
; CHECK: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn writeonly
47+
; CHECK-LABEL: define {{[^@]+}}@bar
48+
; CHECK-SAME: (%struct.test.a* noalias nocapture nofree noundef nonnull writeonly byval([[STRUCT_TEST_A:%.*]]) align 8 dereferenceable(24) [[DEV:%.*]]) #[[ATTR1:[0-9]+]] {
49+
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_TEST_A]], %struct.test.a* [[DEV]], i64 0, i32 0
50+
; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds [[STRUCT_TEST_B:%.*]], %struct.test.b* [[TMP1]], i64 0, i32 1
51+
; CHECK-NEXT: store i32 1, i32* [[TMP2]], align 4
52+
; CHECK-NEXT: ret void
53+
;
54+
%1 = getelementptr inbounds %struct.test.a, %struct.test.a* %dev, i64 0, i32 0
55+
%2 = getelementptr inbounds %struct.test.b, %struct.test.b* %1, i64 0, i32 1
56+
store i32 1, i32* %2
57+
ret void
58+
}
59+
;.
60+
; IS__TUNIT____: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind readnone willreturn }
61+
; IS__TUNIT____: attributes #[[ATTR1]] = { argmemonly nofree norecurse nosync nounwind willreturn writeonly }
62+
; IS__TUNIT____: attributes #[[ATTR2]] = { nofree nosync nounwind willreturn writeonly }
63+
;.
64+
; IS__CGSCC____: attributes #[[ATTR0]] = { nofree nosync nounwind readnone willreturn }
65+
; IS__CGSCC____: attributes #[[ATTR1]] = { argmemonly nofree norecurse nosync nounwind willreturn writeonly }
66+
; IS__CGSCC____: attributes #[[ATTR2]] = { nounwind willreturn writeonly }
67+
;.

0 commit comments

Comments
 (0)