[llvm] [DSE] Apply initializes attribute to DSE (PR #107282)
Arthur Eubanks via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 30 15:20:50 PDT 2024
================
@@ -820,20 +828,130 @@ struct MemoryLocationWrapper {
const Value *UnderlyingObject;
MemoryDef *MemDef;
Instruction *DefInst;
+ bool DefByInitializesAttr = false;
};
// A memory def wrapper that represents a MemoryDef and the MemoryLocation(s)
// defined by this MemoryDef.
struct MemoryDefWrapper {
- MemoryDefWrapper(MemoryDef *MemDef, std::optional<MemoryLocation> MemLoc) {
+ MemoryDefWrapper(MemoryDef *MemDef,
+ ArrayRef<std::pair<MemoryLocation, bool>> MemLocations) {
DefInst = MemDef->getMemoryInst();
- if (MemLoc.has_value())
- DefinedLocation = MemoryLocationWrapper(*MemLoc, MemDef);
+ for (auto &[MemLoc, DefByInitializesAttr] : MemLocations)
+ DefinedLocations.push_back(
+ MemoryLocationWrapper(MemLoc, MemDef, DefByInitializesAttr));
}
Instruction *DefInst;
- std::optional<MemoryLocationWrapper> DefinedLocation = std::nullopt;
+ SmallVector<MemoryLocationWrapper, 1> DefinedLocations;
+};
+
+bool hasInitializesAttr(Instruction *I) {
+ CallBase *CB = dyn_cast<CallBase>(I);
+ return CB != nullptr &&
+ CB->getArgOperandWithAttribute(Attribute::Initializes) != nullptr;
+}
+
+struct ArgumentInitInfo {
+ unsigned Idx;
+ bool HasDeadOnUnwindAttr;
+ ConstantRangeList Inits;
};
+// Return the intersected range list of the initializes attributes of "Args".
+// "Args" are call arguments that alias to each other.
+// If any argument in "Args" doesn't have dead_on_unwind attr and
+// "CallHasNoUnwindAttr" is false, return empty.
+ConstantRangeList getIntersectedInitRangeList(ArrayRef<ArgumentInitInfo> Args,
+ bool CallHasNoUnwindAttr) {
+ if (Args.empty())
+ return {};
+
+ // To address unwind, the function should have nounwind attribute or the
+ // arguments have dead_on_unwind attribute. Otherwise, return empty.
+ for (const auto &Arg : Args) {
+ if (!CallHasNoUnwindAttr && !Arg.HasDeadOnUnwindAttr)
+ return {};
+ if (Arg.Inits.empty())
+ return {};
+ }
+
+ if (Args.size() == 1)
+ return Args[0].Inits;
+
+ ConstantRangeList IntersectedIntervals = Args.front().Inits;
+ for (auto &Arg : Args.drop_front())
+ IntersectedIntervals = IntersectedIntervals.intersectWith(Arg.Inits);
+
+ return IntersectedIntervals;
+}
+
+// Return the locations written by the initializes attribute.
+// Note that this function considers:
+// 1. Unwind edge: apply "initializes" attribute only if the callee has
+// "nounwind" attribute or the argument has "dead_on_unwind" attribute.
+// 2. Argument alias: for aliasing arguments, the "initializes" attribute is
+// the intersected range list of their "initializes" attributes.
+SmallVector<MemoryLocation, 1>
+getInitializesArgMemLoc(const Instruction *I, BatchAAResults &BatchAA) {
+ const CallBase *CB = dyn_cast<CallBase>(I);
+ if (!CB)
+ return {};
+
+ // Collect aliasing arguments and their initializes ranges.
+ SmallMapVector<Value *, SmallVector<ArgumentInitInfo, 2>, 2> Arguments;
+ for (unsigned Idx = 0, Count = CB->arg_size(); Idx < Count; ++Idx) {
+ ConstantRangeList Inits;
+ Attribute InitializesAttr = CB->getParamAttr(Idx, Attribute::Initializes);
+ if (InitializesAttr.isValid())
+ Inits = InitializesAttr.getValueAsConstantRangeList();
+
+ bool HasDeadOnUnwindAttr = CB->paramHasAttr(Idx, Attribute::DeadOnUnwind);
----------------
aeubanks wrote:
@haopliu can you change this to be `bool IsDeadOnUnwind = CB->paramHasAttr(Idx, Attribute::DeadOnUnwind) || (isInvisibleToCallerOnUnwind(CurArg) && isa<CallInst>(CB));` with an explanation about how we need to make sure that we don't perform incorrect DSE on unwind edges in the current function, and that `isa<CallInst>` means no unwind edges (maybe there's a better way to detect no unwind edges?)?
https://github.com/llvm/llvm-project/pull/107282
More information about the llvm-commits
mailing list