Skip to content

Commit 11a9cd9

Browse files
committed
Consider isInvisibleToCallerOnUnwind while checking an argument in CB is dead on unwind
1 parent 634948e commit 11a9cd9

File tree

2 files changed

+101
-76
lines changed

2 files changed

+101
-76
lines changed

llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp

Lines changed: 82 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -853,7 +853,7 @@ bool hasInitializesAttr(Instruction *I) {
853853

854854
struct ArgumentInitInfo {
855855
unsigned Idx;
856-
bool HasDeadOnUnwindAttr;
856+
bool IsDeadOnUnwind;
857857
ConstantRangeList Inits;
858858
};
859859

@@ -869,89 +869,19 @@ ConstantRangeList getIntersectedInitRangeList(ArrayRef<ArgumentInitInfo> Args,
869869
// To address unwind, the function should have nounwind attribute or the
870870
// arguments have dead_on_unwind attribute. Otherwise, return empty.
871871
for (const auto &Arg : Args) {
872-
if (!CallHasNoUnwindAttr && !Arg.HasDeadOnUnwindAttr)
872+
if (!CallHasNoUnwindAttr && !Arg.IsDeadOnUnwind)
873873
return {};
874874
if (Arg.Inits.empty())
875875
return {};
876876
}
877877

878-
if (Args.size() == 1)
879-
return Args[0].Inits;
880-
881878
ConstantRangeList IntersectedIntervals = Args.front().Inits;
882879
for (auto &Arg : Args.drop_front())
883880
IntersectedIntervals = IntersectedIntervals.intersectWith(Arg.Inits);
884881

885882
return IntersectedIntervals;
886883
}
887884

888-
// Return the locations written by the initializes attribute.
889-
// Note that this function considers:
890-
// 1. Unwind edge: apply "initializes" attribute only if the callee has
891-
// "nounwind" attribute or the argument has "dead_on_unwind" attribute.
892-
// 2. Argument alias: for aliasing arguments, the "initializes" attribute is
893-
// the intersected range list of their "initializes" attributes.
894-
SmallVector<MemoryLocation, 1>
895-
getInitializesArgMemLoc(const Instruction *I, BatchAAResults &BatchAA) {
896-
const CallBase *CB = dyn_cast<CallBase>(I);
897-
if (!CB)
898-
return {};
899-
900-
// Collect aliasing arguments and their initializes ranges.
901-
SmallMapVector<Value *, SmallVector<ArgumentInitInfo, 2>, 2> Arguments;
902-
for (unsigned Idx = 0, Count = CB->arg_size(); Idx < Count; ++Idx) {
903-
ConstantRangeList Inits;
904-
Attribute InitializesAttr = CB->getParamAttr(Idx, Attribute::Initializes);
905-
if (InitializesAttr.isValid())
906-
Inits = InitializesAttr.getValueAsConstantRangeList();
907-
908-
bool HasDeadOnUnwindAttr = CB->paramHasAttr(Idx, Attribute::DeadOnUnwind);
909-
ArgumentInitInfo InitInfo{Idx, HasDeadOnUnwindAttr, Inits};
910-
Value *CurArg = CB->getArgOperand(Idx);
911-
bool FoundAliasing = false;
912-
for (auto &[Arg, AliasList] : Arguments) {
913-
auto AAR = BatchAA.alias(MemoryLocation::getBeforeOrAfter(Arg),
914-
MemoryLocation::getBeforeOrAfter(CurArg));
915-
if (AAR == AliasResult::NoAlias) {
916-
continue;
917-
} else if (AAR == AliasResult::MustAlias) {
918-
FoundAliasing = true;
919-
AliasList.push_back(InitInfo);
920-
} else {
921-
// For PartialAlias and MayAlias, there is an offset or may be an
922-
// unknown offset between the arguments and we insert an empty init
923-
// range to discard the entire initializes info while intersecting.
924-
FoundAliasing = true;
925-
AliasList.push_back(
926-
ArgumentInitInfo{Idx, HasDeadOnUnwindAttr, ConstantRangeList()});
927-
}
928-
}
929-
if (!FoundAliasing)
930-
Arguments[CurArg] = {InitInfo};
931-
}
932-
933-
SmallVector<MemoryLocation, 1> Locations;
934-
for (const auto &[_, Args] : Arguments) {
935-
auto IntersectedRanges =
936-
getIntersectedInitRangeList(Args, CB->doesNotThrow());
937-
if (IntersectedRanges.empty())
938-
continue;
939-
940-
for (const auto &Arg : Args) {
941-
for (const auto &Range : IntersectedRanges) {
942-
int64_t Start = Range.getLower().getSExtValue();
943-
int64_t End = Range.getUpper().getSExtValue();
944-
// For now, we only handle locations starting at offset 0.
945-
if (Start == 0)
946-
Locations.push_back(MemoryLocation(CB->getArgOperand(Arg.Idx),
947-
LocationSize::precise(End - Start),
948-
CB->getAAMetadata()));
949-
}
950-
}
951-
}
952-
return Locations;
953-
}
954-
955885
struct DSEState {
956886
Function &F;
957887
AliasAnalysis &AA;
@@ -1281,7 +1211,7 @@ struct DSEState {
12811211
Locations.push_back(std::make_pair(*Loc, false));
12821212

12831213
if (ConsiderInitializesAttr) {
1284-
for (auto &MemLoc : getInitializesArgMemLoc(I, BatchAA)) {
1214+
for (auto &MemLoc : getInitializesArgMemLoc(I)) {
12851215
Locations.push_back(std::make_pair(MemLoc, true));
12861216
}
12871217
}
@@ -2312,6 +2242,16 @@ struct DSEState {
23122242
return MadeChange;
23132243
}
23142244

2245+
// Return the locations written by the initializes attribute.
2246+
// Note that this function considers:
2247+
// 1. Unwind edge: use "initializes" attribute only if the callee has
2248+
// "nounwind" attribute, or the argument has "dead_on_unwind" attribute,
2249+
// or the argument is invisble to caller on unwind. That is, we don't
2250+
// perform incorrect DSE on unwind edges in the current function.
2251+
// 2. Argument alias: for aliasing arguments, the "initializes" attribute is
2252+
// the intersected range list of their "initializes" attributes.
2253+
SmallVector<MemoryLocation, 1> getInitializesArgMemLoc(const Instruction *I);
2254+
23152255
// Try to eliminate dead defs that access `KillingLocWrapper.MemLoc` and are
23162256
// killed by `KillingLocWrapper.MemDef`. Return whether
23172257
// any changes were made, and whether `KillingLocWrapper.DefInst` was deleted.
@@ -2323,6 +2263,75 @@ struct DSEState {
23232263
bool eliminateDeadDefs(const MemoryDefWrapper &KillingDefWrapper);
23242264
};
23252265

2266+
SmallVector<MemoryLocation, 1>
2267+
DSEState::getInitializesArgMemLoc(const Instruction *I) {
2268+
const CallBase *CB = dyn_cast<CallBase>(I);
2269+
if (!CB)
2270+
return {};
2271+
2272+
// Collect aliasing arguments and their initializes ranges.
2273+
SmallMapVector<Value *, SmallVector<ArgumentInitInfo, 2>, 2> Arguments;
2274+
for (unsigned Idx = 0, Count = CB->arg_size(); Idx < Count; ++Idx) {
2275+
ConstantRangeList Inits;
2276+
Attribute InitializesAttr = CB->getParamAttr(Idx, Attribute::Initializes);
2277+
if (InitializesAttr.isValid())
2278+
Inits = InitializesAttr.getValueAsConstantRangeList();
2279+
2280+
Value *CurArg = CB->getArgOperand(Idx);
2281+
// We don't perform incorrect DSE on unwind edges in the current function,
2282+
// and use the "initialize" attribute to kill dead stores if :
2283+
// - The call does not throw exceptions, "CB->doesNotThrow()".
2284+
// - Or the argument has "dead_on_unwind" attribute.
2285+
// - Or the argument is invisble to caller on unwind, and CB isa<CallInst>
2286+
// which means no unwind edges.
2287+
bool IsDeadOnUnwind =
2288+
CB->paramHasAttr(Idx, Attribute::DeadOnUnwind) ||
2289+
(isInvisibleToCallerOnUnwind(CurArg) && isa<CallInst>(CB));
2290+
ArgumentInitInfo InitInfo{Idx, IsDeadOnUnwind, Inits};
2291+
bool FoundAliasing = false;
2292+
for (auto &[Arg, AliasList] : Arguments) {
2293+
auto AAR = BatchAA.alias(MemoryLocation::getBeforeOrAfter(Arg),
2294+
MemoryLocation::getBeforeOrAfter(CurArg));
2295+
if (AAR == AliasResult::NoAlias) {
2296+
continue;
2297+
} else if (AAR == AliasResult::MustAlias) {
2298+
FoundAliasing = true;
2299+
AliasList.push_back(InitInfo);
2300+
} else {
2301+
// For PartialAlias and MayAlias, there is an offset or may be an
2302+
// unknown offset between the arguments and we insert an empty init
2303+
// range to discard the entire initializes info while intersecting.
2304+
FoundAliasing = true;
2305+
AliasList.push_back(
2306+
ArgumentInitInfo{Idx, IsDeadOnUnwind, ConstantRangeList()});
2307+
}
2308+
}
2309+
if (!FoundAliasing)
2310+
Arguments[CurArg] = {InitInfo};
2311+
}
2312+
2313+
SmallVector<MemoryLocation, 1> Locations;
2314+
for (const auto &[_, Args] : Arguments) {
2315+
auto IntersectedRanges =
2316+
getIntersectedInitRangeList(Args, CB->doesNotThrow());
2317+
if (IntersectedRanges.empty())
2318+
continue;
2319+
2320+
for (const auto &Arg : Args) {
2321+
for (const auto &Range : IntersectedRanges) {
2322+
int64_t Start = Range.getLower().getSExtValue();
2323+
int64_t End = Range.getUpper().getSExtValue();
2324+
// For now, we only handle locations starting at offset 0.
2325+
if (Start == 0)
2326+
Locations.push_back(MemoryLocation(CB->getArgOperand(Arg.Idx),
2327+
LocationSize::precise(End - Start),
2328+
CB->getAAMetadata()));
2329+
}
2330+
}
2331+
}
2332+
return Locations;
2333+
}
2334+
23262335
std::pair<bool, bool>
23272336
DSEState::eliminateDeadDefs(const MemoryLocationWrapper &KillingLocWrapper) {
23282337
bool Changed = false;

llvm/test/Transforms/DeadStoreElimination/inter-procedural.ll

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,13 @@ define i16 @p2_no_init_alias_caller() {
138138
ret i16 %l
139139
}
140140

141+
; Althrough the 2nd parameter of `p2_no_dead_on_unwind` doesn't have
142+
; the 'dead_on_unwind' attribute, it's invisble to caller on unwind.
143+
; DSE still uses the 'initializes' attribute and kill the dead store.
141144
; Function Attrs: mustprogress nounwind uwtable
142-
define i16 @p2_no_dead_on_unwind_alias_caller() {
143-
; CHECK-LABEL: @p2_no_dead_on_unwind_alias_caller(
145+
define i16 @p2_no_dead_on_unwind_but_invisble_to_caller_alias_caller() {
146+
; CHECK-LABEL: @p2_no_dead_on_unwind_but_invisble_to_caller_alias_caller(
144147
; CHECK-NEXT: [[PTR:%.*]] = alloca i16, align 2
145-
; CHECK-NEXT: store i16 0, ptr [[PTR]], align 2
146148
; CHECK-NEXT: call void @p2_no_dead_on_unwind(ptr [[PTR]], ptr [[PTR]])
147149
; CHECK-NEXT: [[L:%.*]] = load i16, ptr [[PTR]], align 2
148150
; CHECK-NEXT: ret i16 [[L]]
@@ -154,6 +156,20 @@ define i16 @p2_no_dead_on_unwind_alias_caller() {
154156
ret i16 %l
155157
}
156158

159+
; Function Attrs: mustprogress nounwind uwtable
160+
define i16 @p2_no_dead_on_unwind_alias_caller(ptr %ptr) {
161+
; CHECK-LABEL: @p2_no_dead_on_unwind_alias_caller(
162+
; CHECK-NEXT: store i16 0, ptr [[PTR:%.*]], align 2
163+
; CHECK-NEXT: call void @p2_no_dead_on_unwind(ptr [[PTR]], ptr [[PTR]])
164+
; CHECK-NEXT: [[L:%.*]] = load i16, ptr [[PTR]], align 2
165+
; CHECK-NEXT: ret i16 [[L]]
166+
;
167+
store i16 0, ptr %ptr
168+
call void @p2_no_dead_on_unwind(ptr %ptr, ptr %ptr)
169+
%l = load i16, ptr %ptr
170+
ret i16 %l
171+
}
172+
157173
; Function Attrs: mustprogress nounwind uwtable
158174
define i16 @p2_no_dead_on_unwind_but_nounwind_alias_caller() {
159175
; CHECK-LABEL: @p2_no_dead_on_unwind_but_nounwind_alias_caller(

0 commit comments

Comments
 (0)