1 //===- Attributor.cpp - Module-wide attribute deduction -------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file implements an inter procedural pass that deduces and/or propagating
10 // attributes. This is done in an abstract interpretation style fixpoint
11 // iteration. See the Attributor.h file comment and the class descriptions in
12 // that file for more information.
14 //===----------------------------------------------------------------------===//
16 #include "llvm/Transforms/IPO/Attributor.h"
18 #include "llvm/ADT/SetVector.h"
19 #include "llvm/ADT/SmallPtrSet.h"
20 #include "llvm/ADT/SmallVector.h"
21 #include "llvm/ADT/Statistic.h"
22 #include "llvm/Analysis/GlobalsModRef.h"
23 #include "llvm/IR/Argument.h"
24 #include "llvm/IR/Attributes.h"
25 #include "llvm/IR/InstIterator.h"
26 #include "llvm/Support/CommandLine.h"
27 #include "llvm/Support/Debug.h"
28 #include "llvm/Support/raw_ostream.h"
33 #define DEBUG_TYPE "attributor"
35 STATISTIC(NumFnWithExactDefinition,
36 "Number of function with exact definitions");
37 STATISTIC(NumFnWithoutExactDefinition,
38 "Number of function without exact definitions");
39 STATISTIC(NumAttributesTimedOut,
40 "Number of abstract attributes timed out before fixpoint");
41 STATISTIC(NumAttributesValidFixpoint,
42 "Number of abstract attributes in a valid fixpoint state");
43 STATISTIC(NumAttributesManifested,
44 "Number of abstract attributes manifested in IR");
46 // TODO: Determine a good default value.
48 // In the LLVM-TS and SPEC2006, 32 seems to not induce compile time overheads
49 // (when run with the first 5 abstract attributes). The results also indicate
50 // that we never reach 32 iterations but always find a fixpoint sooner.
52 // This will become more evolved once we perform two interleaved fixpoint
53 // iterations: bottom-up and top-down.
54 static cl::opt<unsigned>
55 MaxFixpointIterations("attributor-max-iterations", cl::Hidden,
56 cl::desc("Maximal number of fixpoint iterations."),
59 static cl::opt<bool> DisableAttributor(
60 "attributor-disable", cl::Hidden,
61 cl::desc("Disable the attributor inter-procedural deduction pass."),
64 static cl::opt<bool> VerifyAttributor(
65 "attributor-verify", cl::Hidden,
66 cl::desc("Verify the Attributor deduction and "
67 "manifestation of attributes -- may issue false-positive errors"),
70 /// Logic operators for the change status enum class.
73 ChangeStatus llvm::operator|(ChangeStatus l, ChangeStatus r) {
74 return l == ChangeStatus::CHANGED ? l : r;
76 ChangeStatus llvm::operator&(ChangeStatus l, ChangeStatus r) {
77 return l == ChangeStatus::UNCHANGED ? l : r;
81 /// Helper to adjust the statistics.
82 static void bookkeeping(AbstractAttribute::ManifestPosition MP,
83 const Attribute &Attr) {
84 if (!AreStatisticsEnabled())
87 if (!Attr.isEnumAttribute())
89 //switch (Attr.getKindAsEnum()) {
95 /// Helper to identify the correct offset into an attribute list.
96 static unsigned getAttrIndex(AbstractAttribute::ManifestPosition MP,
99 case AbstractAttribute::MP_ARGUMENT:
100 case AbstractAttribute::MP_CALL_SITE_ARGUMENT:
101 return ArgNo + AttributeList::FirstArgIndex;
102 case AbstractAttribute::MP_FUNCTION:
103 return AttributeList::FunctionIndex;
104 case AbstractAttribute::MP_RETURNED:
105 return AttributeList::ReturnIndex;
107 llvm_unreachable("Unknown manifest position!");
110 /// Return true if \p New is equal or worse than \p Old.
111 static bool isEqualOrWorse(const Attribute &New, const Attribute &Old) {
112 if (!Old.isIntAttribute())
115 return Old.getValueAsInt() >= New.getValueAsInt();
118 /// Return true if the information provided by \p Attr was added to the
119 /// attribute list \p Attrs. This is only the case if it was not already present
120 /// in \p Attrs at the position describe by \p MP and \p ArgNo.
121 static bool addIfNotExistent(LLVMContext &Ctx, const Attribute &Attr,
122 AttributeList &Attrs,
123 AbstractAttribute::ManifestPosition MP,
124 unsigned ArgNo = 0) {
125 unsigned AttrIdx = getAttrIndex(MP, ArgNo);
127 if (Attr.isEnumAttribute()) {
128 Attribute::AttrKind Kind = Attr.getKindAsEnum();
129 if (Attrs.hasAttribute(AttrIdx, Kind))
130 if (isEqualOrWorse(Attr, Attrs.getAttribute(AttrIdx, Kind)))
132 Attrs = Attrs.addAttribute(Ctx, AttrIdx, Attr);
135 if (Attr.isStringAttribute()) {
136 StringRef Kind = Attr.getKindAsString();
137 if (Attrs.hasAttribute(AttrIdx, Kind))
138 if (isEqualOrWorse(Attr, Attrs.getAttribute(AttrIdx, Kind)))
140 Attrs = Attrs.addAttribute(Ctx, AttrIdx, Attr);
144 llvm_unreachable("Expected enum or string attribute!");
147 ChangeStatus AbstractAttribute::update(Attributor &A) {
148 ChangeStatus HasChanged = ChangeStatus::UNCHANGED;
149 if (getState().isAtFixpoint())
152 LLVM_DEBUG(dbgs() << "[Attributor] Update: " << *this << "\n");
154 HasChanged = updateImpl(A);
156 LLVM_DEBUG(dbgs() << "[Attributor] Update " << HasChanged << " " << *this
162 ChangeStatus AbstractAttribute::manifest(Attributor &A) {
163 assert(getState().isValidState() &&
164 "Attempted to manifest an invalid state!");
165 assert(getAssociatedValue() &&
166 "Attempted to manifest an attribute without associated value!");
168 ChangeStatus HasChanged = ChangeStatus::UNCHANGED;
169 SmallVector<Attribute, 4> DeducedAttrs;
170 getDeducedAttributes(DeducedAttrs);
172 Function &ScopeFn = getAnchorScope();
173 LLVMContext &Ctx = ScopeFn.getContext();
174 ManifestPosition MP = getManifestPosition();
177 SmallVector<unsigned, 4> ArgNos;
179 // In the following some generic code that will manifest attributes in
180 // DeducedAttrs if they improve the current IR. Due to the different
181 // annotation positions we use the underlying AttributeList interface.
182 // Note that MP_CALL_SITE_ARGUMENT can annotate multiple locations.
186 ArgNos.push_back(cast<Argument>(getAssociatedValue())->getArgNo());
187 Attrs = ScopeFn.getAttributes();
192 Attrs = ScopeFn.getAttributes();
194 case MP_CALL_SITE_ARGUMENT: {
195 CallSite CS(&getAnchoredValue());
196 for (unsigned u = 0, e = CS.getNumArgOperands(); u != e; u++)
197 if (CS.getArgOperand(u) == getAssociatedValue())
199 Attrs = CS.getAttributes();
203 for (const Attribute &Attr : DeducedAttrs) {
204 for (unsigned ArgNo : ArgNos) {
205 if (!addIfNotExistent(Ctx, Attr, Attrs, MP, ArgNo))
208 HasChanged = ChangeStatus::CHANGED;
209 bookkeeping(MP, Attr);
213 if (HasChanged == ChangeStatus::UNCHANGED)
220 ScopeFn.setAttributes(Attrs);
222 case MP_CALL_SITE_ARGUMENT:
223 CallSite(&getAnchoredValue()).setAttributes(Attrs);
229 Function &AbstractAttribute::getAnchorScope() {
230 Value &V = getAnchoredValue();
231 if (isa<Function>(V))
232 return cast<Function>(V);
233 if (isa<Argument>(V))
234 return *cast<Argument>(V).getParent();
235 if (isa<Instruction>(V))
236 return *cast<Instruction>(V).getFunction();
237 llvm_unreachable("No scope for anchored value found!");
240 const Function &AbstractAttribute::getAnchorScope() const {
241 return const_cast<AbstractAttribute *>(this)->getAnchorScope();
244 /// ----------------------------------------------------------------------------
246 /// ----------------------------------------------------------------------------
248 ChangeStatus Attributor::run() {
249 // Initialize all abstract attributes.
250 for (AbstractAttribute *AA : AllAbstractAttributes)
251 AA->initialize(*this);
253 LLVM_DEBUG(dbgs() << "[Attributor] Identified and initialized "
254 << AllAbstractAttributes.size()
255 << " abstract attributes.\n");
257 // Now that all abstract attributes are collected and initialized we start the
258 // abstract analysis.
260 unsigned IterationCounter = 1;
262 SmallVector<AbstractAttribute *, 64> ChangedAAs;
263 SetVector<AbstractAttribute *> Worklist;
264 Worklist.insert(AllAbstractAttributes.begin(), AllAbstractAttributes.end());
267 LLVM_DEBUG(dbgs() << "\n\n[Attributor] #Iteration: " << IterationCounter
268 << ", Worklist size: " << Worklist.size() << "\n");
270 // Add all abstract attributes that are potentially dependent on one that
271 // changed to the work list.
272 for (AbstractAttribute *ChangedAA : ChangedAAs) {
273 auto &QuerriedAAs = QueryMap[ChangedAA];
274 Worklist.insert(QuerriedAAs.begin(), QuerriedAAs.end());
277 // Reset the changed set.
280 // Update all abstract attribute in the work list and record the ones that
282 for (AbstractAttribute *AA : Worklist)
283 if (AA->update(*this) == ChangeStatus::CHANGED)
284 ChangedAAs.push_back(AA);
286 // Reset the work list and repopulate with the changed abstract attributes.
287 // Note that dependent ones are added above.
289 Worklist.insert(ChangedAAs.begin(), ChangedAAs.end());
291 } while (!Worklist.empty() && ++IterationCounter < MaxFixpointIterations);
293 LLVM_DEBUG(dbgs() << "\n[Attributor] Fixpoint iteration done after: "
294 << IterationCounter << "/" << MaxFixpointIterations
297 bool FinishedAtFixpoint = Worklist.empty();
299 // Reset abstract arguments not settled in a sound fixpoint by now. This
300 // happens when we stopped the fixpoint iteration early. Note that only the
301 // ones marked as "changed" *and* the ones transitively depending on them
302 // need to be reverted to a pessimistic state. Others might not be in a
303 // fixpoint state but we can use the optimistic results for them anyway.
304 SmallPtrSet<AbstractAttribute *, 32> Visited;
305 for (unsigned u = 0; u < ChangedAAs.size(); u++) {
306 AbstractAttribute *ChangedAA = ChangedAAs[u];
307 if (!Visited.insert(ChangedAA).second)
310 AbstractState &State = ChangedAA->getState();
311 if (!State.isAtFixpoint()) {
312 State.indicatePessimisticFixpoint();
314 NumAttributesTimedOut++;
317 auto &QuerriedAAs = QueryMap[ChangedAA];
318 ChangedAAs.append(QuerriedAAs.begin(), QuerriedAAs.end());
322 if (!Visited.empty())
323 dbgs() << "\n[Attributor] Finalized " << Visited.size()
324 << " abstract attributes.\n";
327 unsigned NumManifested = 0;
328 unsigned NumAtFixpoint = 0;
329 ChangeStatus ManifestChange = ChangeStatus::UNCHANGED;
330 for (AbstractAttribute *AA : AllAbstractAttributes) {
331 AbstractState &State = AA->getState();
333 // If there is not already a fixpoint reached, we can now take the
334 // optimistic state. This is correct because we enforced a pessimistic one
335 // on abstract attributes that were transitively dependent on a changed one
337 if (!State.isAtFixpoint())
338 State.indicateOptimisticFixpoint();
340 // If the state is invalid, we do not try to manifest it.
341 if (!State.isValidState())
344 // Manifest the state and record if we changed the IR.
345 ChangeStatus LocalChange = AA->manifest(*this);
346 ManifestChange = ManifestChange | LocalChange;
349 NumManifested += (LocalChange == ChangeStatus::CHANGED);
354 LLVM_DEBUG(dbgs() << "\n[Attributor] Manifested " << NumManifested
355 << " arguments while " << NumAtFixpoint
356 << " were in a valid fixpoint state\n");
358 // If verification is requested, we finished this run at a fixpoint, and the
359 // IR was changed, we re-run the whole fixpoint analysis, starting at
360 // re-initialization of the arguments. This re-run should not result in an IR
361 // change. Though, the (virtual) state of attributes at the end of the re-run
362 // might be more optimistic than the known state or the IR state if the better
363 // state cannot be manifested.
364 if (VerifyAttributor && FinishedAtFixpoint &&
365 ManifestChange == ChangeStatus::CHANGED) {
366 VerifyAttributor = false;
367 ChangeStatus VerifyStatus = run();
368 if (VerifyStatus != ChangeStatus::UNCHANGED)
370 "Attributor verification failed, re-run did result in an IR change "
371 "even after a fixpoint was reached in the original run. (False "
372 "positives possible!)");
373 VerifyAttributor = true;
376 NumAttributesManifested += NumManifested;
377 NumAttributesValidFixpoint += NumAtFixpoint;
379 return ManifestChange;
382 void Attributor::identifyDefaultAbstractAttributes(
383 Function &F, InformationCache &InfoCache,
384 DenseSet</* Attribute::AttrKind */ unsigned> *Whitelist) {
386 // Walk all instructions to find more attribute opportunities and also
387 // interesting instructions that might be queried by abstract attributes
388 // during their initialization or update.
389 auto &ReadOrWriteInsts = InfoCache.FuncRWInstsMap[&F];
390 auto &InstOpcodeMap = InfoCache.FuncInstOpcodeMap[&F];
392 for (Instruction &I : instructions(&F)) {
393 bool IsInterestingOpcode = false;
395 // To allow easy access to all instructions in a function with a given
396 // opcode we store them in the InfoCache. As not all opcodes are interesting
397 // to concrete attributes we only cache the ones that are as identified in
398 // the following switch.
399 // Note: There are no concrete attributes now so this is initially empty.
400 //switch (I.getOpcode()) {
404 if (IsInterestingOpcode)
405 InstOpcodeMap[I.getOpcode()].push_back(&I);
406 if (I.mayReadOrWriteMemory())
407 ReadOrWriteInsts.push_back(&I);
411 /// Helpers to ease debugging through output streams and print calls.
414 raw_ostream &llvm::operator<<(raw_ostream &OS, ChangeStatus S) {
415 return OS << (S == ChangeStatus::CHANGED ? "changed" : "unchanged");
418 raw_ostream &llvm::operator<<(raw_ostream &OS,
419 AbstractAttribute::ManifestPosition AP) {
421 case AbstractAttribute::MP_ARGUMENT:
423 case AbstractAttribute::MP_CALL_SITE_ARGUMENT:
424 return OS << "cs_arg";
425 case AbstractAttribute::MP_FUNCTION:
427 case AbstractAttribute::MP_RETURNED:
428 return OS << "fn_ret";
430 llvm_unreachable("Unknown attribute position!");
433 raw_ostream &llvm::operator<<(raw_ostream &OS, const AbstractState &S) {
434 return OS << (!S.isValidState() ? "top" : (S.isAtFixpoint() ? "fix" : ""));
437 raw_ostream &llvm::operator<<(raw_ostream &OS, const AbstractAttribute &AA) {
442 void AbstractAttribute::print(raw_ostream &OS) const {
443 OS << "[" << getManifestPosition() << "][" << getAsStr() << "]["
444 << AnchoredVal.getName() << "]";
448 /// ----------------------------------------------------------------------------
449 /// Pass (Manager) Boilerplate
450 /// ----------------------------------------------------------------------------
452 static bool runAttributorOnModule(Module &M) {
453 if (DisableAttributor)
456 LLVM_DEBUG(dbgs() << "[Attributor] Run on module with " << M.size()
459 // Create an Attributor and initially empty information cache that is filled
460 // while we identify default attribute opportunities.
462 InformationCache InfoCache;
464 for (Function &F : M) {
465 // TODO: Not all attributes require an exact definition. Find a way to
466 // enable deduction for some but not all attributes in case the
467 // definition might be changed at runtime, see also
468 // http://lists.llvm.org/pipermail/llvm-dev/2018-February/121275.html.
469 // TODO: We could always determine abstract attributes and if sufficient
470 // information was found we could duplicate the functions that do not
471 // have an exact definition.
472 if (!F.hasExactDefinition()) {
473 NumFnWithoutExactDefinition++;
477 // For now we ignore naked and optnone functions.
478 if (F.hasFnAttribute(Attribute::Naked) ||
479 F.hasFnAttribute(Attribute::OptimizeNone))
482 NumFnWithExactDefinition++;
484 // Populate the Attributor with abstract attribute opportunities in the
485 // function and the information cache with IR information.
486 A.identifyDefaultAbstractAttributes(F, InfoCache);
489 return A.run() == ChangeStatus::CHANGED;
492 PreservedAnalyses AttributorPass::run(Module &M, ModuleAnalysisManager &AM) {
493 if (runAttributorOnModule(M)) {
494 // FIXME: Think about passes we will preserve and add them here.
495 return PreservedAnalyses::none();
497 return PreservedAnalyses::all();
502 struct AttributorLegacyPass : public ModulePass {
505 AttributorLegacyPass() : ModulePass(ID) {
506 initializeAttributorLegacyPassPass(*PassRegistry::getPassRegistry());
509 bool runOnModule(Module &M) override {
512 return runAttributorOnModule(M);
515 void getAnalysisUsage(AnalysisUsage &AU) const override {
516 // FIXME: Think about passes we will preserve and add them here.
517 AU.setPreservesCFG();
521 } // end anonymous namespace
523 Pass *llvm::createAttributorLegacyPass() { return new AttributorLegacyPass(); }
525 char AttributorLegacyPass::ID = 0;
526 INITIALIZE_PASS_BEGIN(AttributorLegacyPass, "attributor",
527 "Deduce and propagate attributes", false, false)
528 INITIALIZE_PASS_END(AttributorLegacyPass, "attributor",
529 "Deduce and propagate attributes", false, false)