| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 1 | //===- Attributor.cpp - Module-wide attribute deduction -------------------===// |
| 2 | // |
| 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 |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 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. |
| 13 | // |
| 14 | //===----------------------------------------------------------------------===// |
| 15 | |
| 16 | #include "llvm/Transforms/IPO/Attributor.h" |
| 17 | |
| 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" |
| 29 | #include <cassert> |
| 30 | |
| 31 | using namespace llvm; |
| 32 | |
| 33 | #define DEBUG_TYPE "attributor" |
| 34 | |
| 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"); |
| 45 | |
| 46 | // TODO: Determine a good default value. |
| 47 | // |
| 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. |
| 51 | // |
| 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."), |
| 57 | cl::init(32)); |
| 58 | |
| 59 | static cl::opt<bool> DisableAttributor( |
| 60 | "attributor-disable", cl::Hidden, |
| 61 | cl::desc("Disable the attributor inter-procedural deduction pass."), |
| 62 | cl::init(false)); |
| 63 | |
| 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"), |
| 68 | cl::init(false)); |
| 69 | |
| 70 | /// Logic operators for the change status enum class. |
| 71 | /// |
| 72 | ///{ |
| 73 | ChangeStatus llvm::operator|(ChangeStatus l, ChangeStatus r) { |
| 74 | return l == ChangeStatus::CHANGED ? l : r; |
| 75 | } |
| 76 | ChangeStatus llvm::operator&(ChangeStatus l, ChangeStatus r) { |
| 77 | return l == ChangeStatus::UNCHANGED ? l : r; |
| 78 | } |
| 79 | ///} |
| 80 | |
| 81 | /// Helper to adjust the statistics. |
| 82 | static void bookkeeping(AbstractAttribute::ManifestPosition MP, |
| 83 | const Attribute &Attr) { |
| 84 | if (!AreStatisticsEnabled()) |
| 85 | return; |
| 86 | |
| 87 | if (!Attr.isEnumAttribute()) |
| 88 | return; |
| Simon Pilgrim | db134aa | 2019-06-05 10:04:05 +0000 | [diff] [blame] | 89 | //switch (Attr.getKindAsEnum()) { |
| 90 | //default: |
| 91 | // return; |
| 92 | //} |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 93 | } |
| 94 | |
| 95 | /// Helper to identify the correct offset into an attribute list. |
| 96 | static unsigned getAttrIndex(AbstractAttribute::ManifestPosition MP, |
| 97 | unsigned ArgNo = 0) { |
| 98 | switch (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; |
| 106 | } |
| Michael Liao | fa449a9 | 2019-06-05 04:18:12 +0000 | [diff] [blame] | 107 | llvm_unreachable("Unknown manifest position!"); |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 108 | } |
| 109 | |
| 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()) |
| 113 | return true; |
| 114 | |
| 115 | return Old.getValueAsInt() >= New.getValueAsInt(); |
| 116 | } |
| 117 | |
| 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); |
| 126 | |
| 127 | if (Attr.isEnumAttribute()) { |
| 128 | Attribute::AttrKind Kind = Attr.getKindAsEnum(); |
| 129 | if (Attrs.hasAttribute(AttrIdx, Kind)) |
| 130 | if (isEqualOrWorse(Attr, Attrs.getAttribute(AttrIdx, Kind))) |
| 131 | return false; |
| 132 | Attrs = Attrs.addAttribute(Ctx, AttrIdx, Attr); |
| 133 | return true; |
| 134 | } |
| 135 | if (Attr.isStringAttribute()) { |
| 136 | StringRef Kind = Attr.getKindAsString(); |
| 137 | if (Attrs.hasAttribute(AttrIdx, Kind)) |
| 138 | if (isEqualOrWorse(Attr, Attrs.getAttribute(AttrIdx, Kind))) |
| 139 | return false; |
| 140 | Attrs = Attrs.addAttribute(Ctx, AttrIdx, Attr); |
| 141 | return true; |
| 142 | } |
| 143 | |
| 144 | llvm_unreachable("Expected enum or string attribute!"); |
| 145 | } |
| 146 | |
| 147 | ChangeStatus AbstractAttribute::update(Attributor &A) { |
| 148 | ChangeStatus HasChanged = ChangeStatus::UNCHANGED; |
| 149 | if (getState().isAtFixpoint()) |
| 150 | return HasChanged; |
| 151 | |
| 152 | LLVM_DEBUG(dbgs() << "[Attributor] Update: " << *this << "\n"); |
| 153 | |
| 154 | HasChanged = updateImpl(A); |
| 155 | |
| 156 | LLVM_DEBUG(dbgs() << "[Attributor] Update " << HasChanged << " " << *this |
| 157 | << "\n"); |
| 158 | |
| 159 | return HasChanged; |
| 160 | } |
| 161 | |
| 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!"); |
| 167 | |
| 168 | ChangeStatus HasChanged = ChangeStatus::UNCHANGED; |
| 169 | SmallVector<Attribute, 4> DeducedAttrs; |
| 170 | getDeducedAttributes(DeducedAttrs); |
| 171 | |
| 172 | Function &ScopeFn = getAnchorScope(); |
| 173 | LLVMContext &Ctx = ScopeFn.getContext(); |
| 174 | ManifestPosition MP = getManifestPosition(); |
| 175 | |
| 176 | AttributeList Attrs; |
| 177 | SmallVector<unsigned, 4> ArgNos; |
| 178 | |
| 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. |
| 183 | |
| 184 | switch (MP) { |
| 185 | case MP_ARGUMENT: |
| 186 | ArgNos.push_back(cast<Argument>(getAssociatedValue())->getArgNo()); |
| 187 | Attrs = ScopeFn.getAttributes(); |
| 188 | break; |
| 189 | case MP_FUNCTION: |
| 190 | case MP_RETURNED: |
| 191 | ArgNos.push_back(0); |
| 192 | Attrs = ScopeFn.getAttributes(); |
| 193 | break; |
| 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()) |
| 198 | ArgNos.push_back(u); |
| 199 | Attrs = CS.getAttributes(); |
| 200 | } |
| 201 | } |
| 202 | |
| 203 | for (const Attribute &Attr : DeducedAttrs) { |
| 204 | for (unsigned ArgNo : ArgNos) { |
| 205 | if (!addIfNotExistent(Ctx, Attr, Attrs, MP, ArgNo)) |
| 206 | continue; |
| 207 | |
| 208 | HasChanged = ChangeStatus::CHANGED; |
| 209 | bookkeeping(MP, Attr); |
| 210 | } |
| 211 | } |
| 212 | |
| 213 | if (HasChanged == ChangeStatus::UNCHANGED) |
| 214 | return HasChanged; |
| 215 | |
| 216 | switch (MP) { |
| 217 | case MP_ARGUMENT: |
| 218 | case MP_FUNCTION: |
| 219 | case MP_RETURNED: |
| 220 | ScopeFn.setAttributes(Attrs); |
| 221 | break; |
| 222 | case MP_CALL_SITE_ARGUMENT: |
| 223 | CallSite(&getAnchoredValue()).setAttributes(Attrs); |
| 224 | } |
| 225 | |
| 226 | return HasChanged; |
| 227 | } |
| 228 | |
| 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!"); |
| 238 | } |
| 239 | |
| 240 | const Function &AbstractAttribute::getAnchorScope() const { |
| 241 | return const_cast<AbstractAttribute *>(this)->getAnchorScope(); |
| 242 | } |
| 243 | |
| 244 | /// ---------------------------------------------------------------------------- |
| 245 | /// Attributor |
| 246 | /// ---------------------------------------------------------------------------- |
| 247 | |
| 248 | ChangeStatus Attributor::run() { |
| 249 | // Initialize all abstract attributes. |
| 250 | for (AbstractAttribute *AA : AllAbstractAttributes) |
| 251 | AA->initialize(*this); |
| 252 | |
| 253 | LLVM_DEBUG(dbgs() << "[Attributor] Identified and initialized " |
| 254 | << AllAbstractAttributes.size() |
| 255 | << " abstract attributes.\n"); |
| 256 | |
| 257 | // Now that all abstract attributes are collected and initialized we start the |
| 258 | // abstract analysis. |
| 259 | |
| 260 | unsigned IterationCounter = 1; |
| 261 | |
| 262 | SmallVector<AbstractAttribute *, 64> ChangedAAs; |
| 263 | SetVector<AbstractAttribute *> Worklist; |
| 264 | Worklist.insert(AllAbstractAttributes.begin(), AllAbstractAttributes.end()); |
| 265 | |
| 266 | do { |
| 267 | LLVM_DEBUG(dbgs() << "\n\n[Attributor] #Iteration: " << IterationCounter |
| 268 | << ", Worklist size: " << Worklist.size() << "\n"); |
| 269 | |
| 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()); |
| 275 | } |
| 276 | |
| 277 | // Reset the changed set. |
| 278 | ChangedAAs.clear(); |
| 279 | |
| 280 | // Update all abstract attribute in the work list and record the ones that |
| 281 | // changed. |
| 282 | for (AbstractAttribute *AA : Worklist) |
| 283 | if (AA->update(*this) == ChangeStatus::CHANGED) |
| 284 | ChangedAAs.push_back(AA); |
| 285 | |
| 286 | // Reset the work list and repopulate with the changed abstract attributes. |
| 287 | // Note that dependent ones are added above. |
| 288 | Worklist.clear(); |
| 289 | Worklist.insert(ChangedAAs.begin(), ChangedAAs.end()); |
| 290 | |
| 291 | } while (!Worklist.empty() && ++IterationCounter < MaxFixpointIterations); |
| 292 | |
| 293 | LLVM_DEBUG(dbgs() << "\n[Attributor] Fixpoint iteration done after: " |
| 294 | << IterationCounter << "/" << MaxFixpointIterations |
| 295 | << " iterations\n"); |
| 296 | |
| 297 | bool FinishedAtFixpoint = Worklist.empty(); |
| 298 | |
| 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) |
| 308 | continue; |
| 309 | |
| 310 | AbstractState &State = ChangedAA->getState(); |
| 311 | if (!State.isAtFixpoint()) { |
| 312 | State.indicatePessimisticFixpoint(); |
| 313 | |
| 314 | NumAttributesTimedOut++; |
| 315 | } |
| 316 | |
| 317 | auto &QuerriedAAs = QueryMap[ChangedAA]; |
| 318 | ChangedAAs.append(QuerriedAAs.begin(), QuerriedAAs.end()); |
| 319 | } |
| 320 | |
| 321 | LLVM_DEBUG({ |
| 322 | if (!Visited.empty()) |
| 323 | dbgs() << "\n[Attributor] Finalized " << Visited.size() |
| 324 | << " abstract attributes.\n"; |
| 325 | }); |
| 326 | |
| 327 | unsigned NumManifested = 0; |
| 328 | unsigned NumAtFixpoint = 0; |
| 329 | ChangeStatus ManifestChange = ChangeStatus::UNCHANGED; |
| 330 | for (AbstractAttribute *AA : AllAbstractAttributes) { |
| 331 | AbstractState &State = AA->getState(); |
| 332 | |
| 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 |
| 336 | // already above. |
| 337 | if (!State.isAtFixpoint()) |
| 338 | State.indicateOptimisticFixpoint(); |
| 339 | |
| 340 | // If the state is invalid, we do not try to manifest it. |
| 341 | if (!State.isValidState()) |
| 342 | continue; |
| 343 | |
| 344 | // Manifest the state and record if we changed the IR. |
| 345 | ChangeStatus LocalChange = AA->manifest(*this); |
| 346 | ManifestChange = ManifestChange | LocalChange; |
| 347 | |
| 348 | NumAtFixpoint++; |
| 349 | NumManifested += (LocalChange == ChangeStatus::CHANGED); |
| 350 | } |
| 351 | |
| 352 | (void)NumManifested; |
| 353 | (void)NumAtFixpoint; |
| 354 | LLVM_DEBUG(dbgs() << "\n[Attributor] Manifested " << NumManifested |
| 355 | << " arguments while " << NumAtFixpoint |
| 356 | << " were in a valid fixpoint state\n"); |
| 357 | |
| 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) |
| 369 | llvm_unreachable( |
| 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; |
| 374 | } |
| 375 | |
| 376 | NumAttributesManifested += NumManifested; |
| 377 | NumAttributesValidFixpoint += NumAtFixpoint; |
| 378 | |
| 379 | return ManifestChange; |
| 380 | } |
| 381 | |
| 382 | void Attributor::identifyDefaultAbstractAttributes( |
| 383 | Function &F, InformationCache &InfoCache, |
| 384 | DenseSet</* Attribute::AttrKind */ unsigned> *Whitelist) { |
| 385 | |
| 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]; |
| 391 | |
| 392 | for (Instruction &I : instructions(&F)) { |
| 393 | bool IsInterestingOpcode = false; |
| 394 | |
| 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. |
| Simon Pilgrim | db134aa | 2019-06-05 10:04:05 +0000 | [diff] [blame] | 400 | //switch (I.getOpcode()) { |
| 401 | //default: |
| 402 | // break; |
| 403 | //} |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 404 | if (IsInterestingOpcode) |
| 405 | InstOpcodeMap[I.getOpcode()].push_back(&I); |
| 406 | if (I.mayReadOrWriteMemory()) |
| 407 | ReadOrWriteInsts.push_back(&I); |
| 408 | } |
| 409 | } |
| 410 | |
| 411 | /// Helpers to ease debugging through output streams and print calls. |
| 412 | /// |
| 413 | ///{ |
| 414 | raw_ostream &llvm::operator<<(raw_ostream &OS, ChangeStatus S) { |
| 415 | return OS << (S == ChangeStatus::CHANGED ? "changed" : "unchanged"); |
| 416 | } |
| 417 | |
| 418 | raw_ostream &llvm::operator<<(raw_ostream &OS, |
| 419 | AbstractAttribute::ManifestPosition AP) { |
| 420 | switch (AP) { |
| 421 | case AbstractAttribute::MP_ARGUMENT: |
| 422 | return OS << "arg"; |
| 423 | case AbstractAttribute::MP_CALL_SITE_ARGUMENT: |
| 424 | return OS << "cs_arg"; |
| 425 | case AbstractAttribute::MP_FUNCTION: |
| 426 | return OS << "fn"; |
| 427 | case AbstractAttribute::MP_RETURNED: |
| 428 | return OS << "fn_ret"; |
| 429 | } |
| 430 | llvm_unreachable("Unknown attribute position!"); |
| 431 | } |
| 432 | |
| 433 | raw_ostream &llvm::operator<<(raw_ostream &OS, const AbstractState &S) { |
| 434 | return OS << (!S.isValidState() ? "top" : (S.isAtFixpoint() ? "fix" : "")); |
| 435 | } |
| 436 | |
| 437 | raw_ostream &llvm::operator<<(raw_ostream &OS, const AbstractAttribute &AA) { |
| 438 | AA.print(OS); |
| 439 | return OS; |
| 440 | } |
| 441 | |
| 442 | void AbstractAttribute::print(raw_ostream &OS) const { |
| 443 | OS << "[" << getManifestPosition() << "][" << getAsStr() << "][" |
| 444 | << AnchoredVal.getName() << "]"; |
| 445 | } |
| 446 | ///} |
| 447 | |
| 448 | /// ---------------------------------------------------------------------------- |
| 449 | /// Pass (Manager) Boilerplate |
| 450 | /// ---------------------------------------------------------------------------- |
| 451 | |
| 452 | static bool runAttributorOnModule(Module &M) { |
| 453 | if (DisableAttributor) |
| 454 | return false; |
| 455 | |
| 456 | LLVM_DEBUG(dbgs() << "[Attributor] Run on module with " << M.size() |
| 457 | << " functions.\n"); |
| 458 | |
| 459 | // Create an Attributor and initially empty information cache that is filled |
| 460 | // while we identify default attribute opportunities. |
| 461 | Attributor A; |
| 462 | InformationCache InfoCache; |
| 463 | |
| 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++; |
| 474 | continue; |
| 475 | } |
| 476 | |
| 477 | // For now we ignore naked and optnone functions. |
| 478 | if (F.hasFnAttribute(Attribute::Naked) || |
| 479 | F.hasFnAttribute(Attribute::OptimizeNone)) |
| 480 | continue; |
| 481 | |
| 482 | NumFnWithExactDefinition++; |
| 483 | |
| 484 | // Populate the Attributor with abstract attribute opportunities in the |
| 485 | // function and the information cache with IR information. |
| 486 | A.identifyDefaultAbstractAttributes(F, InfoCache); |
| 487 | } |
| 488 | |
| 489 | return A.run() == ChangeStatus::CHANGED; |
| 490 | } |
| 491 | |
| 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(); |
| 496 | } |
| 497 | return PreservedAnalyses::all(); |
| 498 | } |
| 499 | |
| 500 | namespace { |
| 501 | |
| 502 | struct AttributorLegacyPass : public ModulePass { |
| 503 | static char ID; |
| 504 | |
| 505 | AttributorLegacyPass() : ModulePass(ID) { |
| 506 | initializeAttributorLegacyPassPass(*PassRegistry::getPassRegistry()); |
| 507 | } |
| 508 | |
| 509 | bool runOnModule(Module &M) override { |
| 510 | if (skipModule(M)) |
| 511 | return false; |
| 512 | return runAttributorOnModule(M); |
| 513 | } |
| 514 | |
| 515 | void getAnalysisUsage(AnalysisUsage &AU) const override { |
| 516 | // FIXME: Think about passes we will preserve and add them here. |
| 517 | AU.setPreservesCFG(); |
| 518 | } |
| 519 | }; |
| 520 | |
| 521 | } // end anonymous namespace |
| 522 | |
| 523 | Pass *llvm::createAttributorLegacyPass() { return new AttributorLegacyPass(); } |
| 524 | |
| 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) |