| 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 | // |
| Uday Bondhugula | 06066c4 | 2020-03-28 12:21:49 +0530 | [diff] [blame] | 9 | // This file implements an interprocedural pass that deduces and/or propagates |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 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 | |
| Johannes Doerfert | 368f7ee | 2019-12-30 16:12:36 -0600 | [diff] [blame] | 16 | #include "llvm/Transforms/IPO/Attributor.h" |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 17 | |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 18 | #include "llvm/ADT/Statistic.h" |
| Hideto Ueno | 188f9a3 | 2020-01-15 15:25:52 +0900 | [diff] [blame] | 19 | #include "llvm/Analysis/LazyValueInfo.h" |
| omarahmed1111 | b285b33 | 2020-03-13 10:30:36 -0500 | [diff] [blame] | 20 | #include "llvm/Analysis/MustExecute.h" |
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 21 | #include "llvm/Analysis/ValueTracking.h" |
| Johannes Doerfert | 89c2e73 | 2019-10-30 17:20:20 -0500 | [diff] [blame] | 22 | #include "llvm/IR/IRBuilder.h" |
| omarahmed1111 | b285b33 | 2020-03-13 10:30:36 -0500 | [diff] [blame] | 23 | #include "llvm/IR/NoFolder.h" |
| Johannes Doerfert | a4088c7 | 2020-01-07 16:01:57 -0600 | [diff] [blame] | 24 | #include "llvm/IR/Verifier.h" |
| Reid Kleckner | 05da2fe | 2019-11-13 13:15:01 -0800 | [diff] [blame] | 25 | #include "llvm/InitializePasses.h" |
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 26 | #include "llvm/Transforms/Utils/BasicBlockUtils.h" |
| 27 | #include "llvm/Transforms/Utils/Local.h" |
| 28 | |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 29 | #include <cassert> |
| 30 | |
| 31 | using namespace llvm; |
| 32 | |
| 33 | #define DEBUG_TYPE "attributor" |
| 34 | |
| Johannes Doerfert | 0985554 | 2020-04-08 17:24:24 -0500 | [diff] [blame] | 35 | STATISTIC(NumFnDeleted, |
| 36 | "Number of function deleted"); |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 37 | STATISTIC(NumFnWithExactDefinition, |
| Uday Bondhugula | 06066c4 | 2020-03-28 12:21:49 +0530 | [diff] [blame] | 38 | "Number of functions with exact definitions"); |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 39 | STATISTIC(NumFnWithoutExactDefinition, |
| Uday Bondhugula | 06066c4 | 2020-03-28 12:21:49 +0530 | [diff] [blame] | 40 | "Number of functions without exact definitions"); |
| Luofan Chen | eec6d87 | 2020-04-04 11:32:36 -0500 | [diff] [blame] | 41 | STATISTIC(NumFnShallowWrapperCreated, "Number of shallow wrappers created"); |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 42 | STATISTIC(NumAttributesTimedOut, |
| 43 | "Number of abstract attributes timed out before fixpoint"); |
| 44 | STATISTIC(NumAttributesValidFixpoint, |
| 45 | "Number of abstract attributes in a valid fixpoint state"); |
| 46 | STATISTIC(NumAttributesManifested, |
| 47 | "Number of abstract attributes manifested in IR"); |
| Johannes Doerfert | 680f638 | 2019-11-02 02:48:05 -0500 | [diff] [blame] | 48 | STATISTIC(NumAttributesFixedDueToRequiredDependences, |
| 49 | "Number of abstract attributes fixed due to required dependences"); |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 50 | |
| 51 | // TODO: Determine a good default value. |
| 52 | // |
| 53 | // In the LLVM-TS and SPEC2006, 32 seems to not induce compile time overheads |
| 54 | // (when run with the first 5 abstract attributes). The results also indicate |
| 55 | // that we never reach 32 iterations but always find a fixpoint sooner. |
| 56 | // |
| 57 | // This will become more evolved once we perform two interleaved fixpoint |
| 58 | // iterations: bottom-up and top-down. |
| 59 | static cl::opt<unsigned> |
| 60 | MaxFixpointIterations("attributor-max-iterations", cl::Hidden, |
| 61 | cl::desc("Maximal number of fixpoint iterations."), |
| 62 | cl::init(32)); |
| Johannes Doerfert | b504eb8 | 2019-08-26 18:55:47 +0000 | [diff] [blame] | 63 | static cl::opt<bool> VerifyMaxFixpointIterations( |
| 64 | "attributor-max-iterations-verify", cl::Hidden, |
| 65 | cl::desc("Verify that max-iterations is a tight bound for a fixpoint"), |
| 66 | cl::init(false)); |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 67 | |
| Johannes Doerfert | c36e2eb | 2019-10-31 20:15:02 -0500 | [diff] [blame] | 68 | static cl::opt<bool> AnnotateDeclarationCallSites( |
| 69 | "attributor-annotate-decl-cs", cl::Hidden, |
| James Henderson | d68904f | 2020-01-06 10:15:44 +0000 | [diff] [blame] | 70 | cl::desc("Annotate call sites of function declarations."), cl::init(false)); |
| Johannes Doerfert | c36e2eb | 2019-10-31 20:15:02 -0500 | [diff] [blame] | 71 | |
| Johannes Doerfert | f7ca0fe | 2019-08-28 16:58:52 +0000 | [diff] [blame] | 72 | static cl::opt<unsigned> DepRecInterval( |
| 73 | "attributor-dependence-recompute-interval", cl::Hidden, |
| 74 | cl::desc("Number of iterations until dependences are recomputed."), |
| 75 | cl::init(4)); |
| 76 | |
| Stefan Stipanovic | 431141c | 2019-09-15 21:47:41 +0000 | [diff] [blame] | 77 | static cl::opt<bool> EnableHeapToStack("enable-heap-to-stack-conversion", |
| 78 | cl::init(true), cl::Hidden); |
| 79 | |
| Luofan Chen | eec6d87 | 2020-04-04 11:32:36 -0500 | [diff] [blame] | 80 | static cl::opt<bool> |
| 81 | AllowShallowWrappers("attributor-allow-shallow-wrappers", cl::Hidden, |
| 82 | cl::desc("Allow the Attributor to create shallow " |
| 83 | "wrappers for non-exact definitions."), |
| 84 | cl::init(false)); |
| 85 | |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 86 | /// Logic operators for the change status enum class. |
| 87 | /// |
| 88 | ///{ |
| 89 | ChangeStatus llvm::operator|(ChangeStatus l, ChangeStatus r) { |
| 90 | return l == ChangeStatus::CHANGED ? l : r; |
| 91 | } |
| 92 | ChangeStatus llvm::operator&(ChangeStatus l, ChangeStatus r) { |
| 93 | return l == ChangeStatus::UNCHANGED ? l : r; |
| 94 | } |
| 95 | ///} |
| 96 | |
| Johannes Doerfert | 0985554 | 2020-04-08 17:24:24 -0500 | [diff] [blame] | 97 | /// Return true if \p New is equal or worse than \p Old. |
| 98 | static bool isEqualOrWorse(const Attribute &New, const Attribute &Old) { |
| 99 | if (!Old.isIntAttribute()) |
| 100 | return true; |
| 101 | |
| 102 | return Old.getValueAsInt() >= New.getValueAsInt(); |
| 103 | } |
| 104 | |
| 105 | /// Return true if the information provided by \p Attr was added to the |
| 106 | /// attribute list \p Attrs. This is only the case if it was not already present |
| 107 | /// in \p Attrs at the position describe by \p PK and \p AttrIdx. |
| 108 | static bool addIfNotExistent(LLVMContext &Ctx, const Attribute &Attr, |
| 109 | AttributeList &Attrs, int AttrIdx) { |
| 110 | |
| 111 | if (Attr.isEnumAttribute()) { |
| 112 | Attribute::AttrKind Kind = Attr.getKindAsEnum(); |
| 113 | if (Attrs.hasAttribute(AttrIdx, Kind)) |
| 114 | if (isEqualOrWorse(Attr, Attrs.getAttribute(AttrIdx, Kind))) |
| 115 | return false; |
| 116 | Attrs = Attrs.addAttribute(Ctx, AttrIdx, Attr); |
| 117 | return true; |
| 118 | } |
| 119 | if (Attr.isStringAttribute()) { |
| 120 | StringRef Kind = Attr.getKindAsString(); |
| 121 | if (Attrs.hasAttribute(AttrIdx, Kind)) |
| 122 | if (isEqualOrWorse(Attr, Attrs.getAttribute(AttrIdx, Kind))) |
| 123 | return false; |
| 124 | Attrs = Attrs.addAttribute(Ctx, AttrIdx, Attr); |
| 125 | return true; |
| 126 | } |
| 127 | if (Attr.isIntAttribute()) { |
| 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.removeAttribute(Ctx, AttrIdx, Kind); |
| 133 | Attrs = Attrs.addAttribute(Ctx, AttrIdx, Attr); |
| 134 | return true; |
| 135 | } |
| 136 | |
| 137 | llvm_unreachable("Expected enum or string attribute!"); |
| 138 | } |
| 139 | |
| 140 | |
| Johannes Doerfert | b1b441d | 2019-10-10 01:19:57 -0500 | [diff] [blame] | 141 | Argument *IRPosition::getAssociatedArgument() const { |
| 142 | if (getPositionKind() == IRP_ARGUMENT) |
| 143 | return cast<Argument>(&getAnchorValue()); |
| 144 | |
| 145 | // Not an Argument and no argument number means this is not a call site |
| 146 | // argument, thus we cannot find a callback argument to return. |
| 147 | int ArgNo = getArgNo(); |
| 148 | if (ArgNo < 0) |
| 149 | return nullptr; |
| 150 | |
| 151 | // Use abstract call sites to make the connection between the call site |
| 152 | // values and the ones in callbacks. If a callback was found that makes use |
| 153 | // of the underlying call site operand, we want the corresponding callback |
| 154 | // callee argument and not the direct callee argument. |
| 155 | Optional<Argument *> CBCandidateArg; |
| 156 | SmallVector<const Use *, 4> CBUses; |
| 157 | ImmutableCallSite ICS(&getAnchorValue()); |
| 158 | AbstractCallSite::getCallbackUses(ICS, CBUses); |
| 159 | for (const Use *U : CBUses) { |
| 160 | AbstractCallSite ACS(U); |
| 161 | assert(ACS && ACS.isCallbackCall()); |
| 162 | if (!ACS.getCalledFunction()) |
| 163 | continue; |
| 164 | |
| 165 | for (unsigned u = 0, e = ACS.getNumArgOperands(); u < e; u++) { |
| 166 | |
| 167 | // Test if the underlying call site operand is argument number u of the |
| 168 | // callback callee. |
| 169 | if (ACS.getCallArgOperandNo(u) != ArgNo) |
| 170 | continue; |
| 171 | |
| 172 | assert(ACS.getCalledFunction()->arg_size() > u && |
| 173 | "ACS mapped into var-args arguments!"); |
| 174 | if (CBCandidateArg.hasValue()) { |
| 175 | CBCandidateArg = nullptr; |
| 176 | break; |
| 177 | } |
| 178 | CBCandidateArg = ACS.getCalledFunction()->getArg(u); |
| 179 | } |
| 180 | } |
| 181 | |
| 182 | // If we found a unique callback candidate argument, return it. |
| 183 | if (CBCandidateArg.hasValue() && CBCandidateArg.getValue()) |
| 184 | return CBCandidateArg.getValue(); |
| 185 | |
| 186 | // If no callbacks were found, or none used the underlying call site operand |
| 187 | // exclusively, use the direct callee argument if available. |
| 188 | const Function *Callee = ICS.getCalledFunction(); |
| 189 | if (Callee && Callee->arg_size() > unsigned(ArgNo)) |
| 190 | return Callee->getArg(ArgNo); |
| 191 | |
| 192 | return nullptr; |
| 193 | } |
| 194 | |
| Johannes Doerfert | ece8190 | 2019-08-12 22:05:53 +0000 | [diff] [blame] | 195 | ChangeStatus AbstractAttribute::update(Attributor &A) { |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 196 | ChangeStatus HasChanged = ChangeStatus::UNCHANGED; |
| 197 | if (getState().isAtFixpoint()) |
| 198 | return HasChanged; |
| 199 | |
| 200 | LLVM_DEBUG(dbgs() << "[Attributor] Update: " << *this << "\n"); |
| 201 | |
| Johannes Doerfert | ece8190 | 2019-08-12 22:05:53 +0000 | [diff] [blame] | 202 | HasChanged = updateImpl(A); |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 203 | |
| 204 | LLVM_DEBUG(dbgs() << "[Attributor] Update " << HasChanged << " " << *this |
| 205 | << "\n"); |
| 206 | |
| 207 | return HasChanged; |
| 208 | } |
| 209 | |
| Johannes Doerfert | d1b79e0 | 2019-08-07 22:46:11 +0000 | [diff] [blame] | 210 | ChangeStatus |
| Johannes Doerfert | b2083c5 | 2019-10-20 22:46:48 -0500 | [diff] [blame] | 211 | IRAttributeManifest::manifestAttrs(Attributor &A, const IRPosition &IRP, |
| Johannes Doerfert | d1b79e0 | 2019-08-07 22:46:11 +0000 | [diff] [blame] | 212 | const ArrayRef<Attribute> &DeducedAttrs) { |
| Stefanos Baziotis | a650d55 | 2020-03-23 22:44:10 +0200 | [diff] [blame] | 213 | Function *ScopeFn = IRP.getAnchorScope(); |
| Kristina Brooks | 26e60f0 | 2019-08-06 19:53:19 +0000 | [diff] [blame] | 214 | IRPosition::Kind PK = IRP.getPositionKind(); |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 215 | |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 216 | // In the following some generic code that will manifest attributes in |
| 217 | // DeducedAttrs if they improve the current IR. Due to the different |
| 218 | // annotation positions we use the underlying AttributeList interface. |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 219 | |
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 220 | AttributeList Attrs; |
| 221 | switch (PK) { |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 222 | case IRPosition::IRP_INVALID: |
| 223 | case IRPosition::IRP_FLOAT: |
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 224 | return ChangeStatus::UNCHANGED; |
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 225 | case IRPosition::IRP_ARGUMENT: |
| 226 | case IRPosition::IRP_FUNCTION: |
| 227 | case IRPosition::IRP_RETURNED: |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 228 | Attrs = ScopeFn->getAttributes(); |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 229 | break; |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 230 | case IRPosition::IRP_CALL_SITE: |
| 231 | case IRPosition::IRP_CALL_SITE_RETURNED: |
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 232 | case IRPosition::IRP_CALL_SITE_ARGUMENT: |
| Kristina Brooks | 26e60f0 | 2019-08-06 19:53:19 +0000 | [diff] [blame] | 233 | Attrs = ImmutableCallSite(&IRP.getAnchorValue()).getAttributes(); |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 234 | break; |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 235 | } |
| 236 | |
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 237 | ChangeStatus HasChanged = ChangeStatus::UNCHANGED; |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 238 | LLVMContext &Ctx = IRP.getAnchorValue().getContext(); |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 239 | for (const Attribute &Attr : DeducedAttrs) { |
| Kristina Brooks | 26e60f0 | 2019-08-06 19:53:19 +0000 | [diff] [blame] | 240 | if (!addIfNotExistent(Ctx, Attr, Attrs, IRP.getAttrIdx())) |
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 241 | continue; |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 242 | |
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 243 | HasChanged = ChangeStatus::CHANGED; |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 244 | } |
| 245 | |
| 246 | if (HasChanged == ChangeStatus::UNCHANGED) |
| 247 | return HasChanged; |
| 248 | |
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 249 | switch (PK) { |
| 250 | case IRPosition::IRP_ARGUMENT: |
| 251 | case IRPosition::IRP_FUNCTION: |
| 252 | case IRPosition::IRP_RETURNED: |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 253 | ScopeFn->setAttributes(Attrs); |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 254 | break; |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 255 | case IRPosition::IRP_CALL_SITE: |
| 256 | case IRPosition::IRP_CALL_SITE_RETURNED: |
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 257 | case IRPosition::IRP_CALL_SITE_ARGUMENT: |
| Kristina Brooks | 26e60f0 | 2019-08-06 19:53:19 +0000 | [diff] [blame] | 258 | CallSite(&IRP.getAnchorValue()).setAttributes(Attrs); |
| Johannes Doerfert | 4395b31 | 2019-08-14 21:46:28 +0000 | [diff] [blame] | 259 | break; |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 260 | case IRPosition::IRP_INVALID: |
| Johannes Doerfert | 4395b31 | 2019-08-14 21:46:28 +0000 | [diff] [blame] | 261 | case IRPosition::IRP_FLOAT: |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 262 | break; |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 263 | } |
| 264 | |
| 265 | return HasChanged; |
| 266 | } |
| 267 | |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 268 | const IRPosition IRPosition::EmptyKey(255); |
| 269 | const IRPosition IRPosition::TombstoneKey(256); |
| 270 | |
| 271 | SubsumingPositionIterator::SubsumingPositionIterator(const IRPosition &IRP) { |
| 272 | IRPositions.emplace_back(IRP); |
| 273 | |
| 274 | ImmutableCallSite ICS(&IRP.getAnchorValue()); |
| 275 | switch (IRP.getPositionKind()) { |
| 276 | case IRPosition::IRP_INVALID: |
| 277 | case IRPosition::IRP_FLOAT: |
| 278 | case IRPosition::IRP_FUNCTION: |
| 279 | return; |
| 280 | case IRPosition::IRP_ARGUMENT: |
| 281 | case IRPosition::IRP_RETURNED: |
| Stefanos Baziotis | a650d55 | 2020-03-23 22:44:10 +0200 | [diff] [blame] | 282 | IRPositions.emplace_back(IRPosition::function(*IRP.getAnchorScope())); |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 283 | return; |
| 284 | case IRPosition::IRP_CALL_SITE: |
| 285 | assert(ICS && "Expected call site!"); |
| 286 | // TODO: We need to look at the operand bundles similar to the redirection |
| 287 | // in CallBase. |
| 288 | if (!ICS.hasOperandBundles()) |
| 289 | if (const Function *Callee = ICS.getCalledFunction()) |
| 290 | IRPositions.emplace_back(IRPosition::function(*Callee)); |
| 291 | return; |
| 292 | case IRPosition::IRP_CALL_SITE_RETURNED: |
| 293 | assert(ICS && "Expected call site!"); |
| 294 | // TODO: We need to look at the operand bundles similar to the redirection |
| 295 | // in CallBase. |
| 296 | if (!ICS.hasOperandBundles()) { |
| 297 | if (const Function *Callee = ICS.getCalledFunction()) { |
| 298 | IRPositions.emplace_back(IRPosition::returned(*Callee)); |
| 299 | IRPositions.emplace_back(IRPosition::function(*Callee)); |
| Johannes Doerfert | f8ad735 | 2020-02-19 23:39:57 -0600 | [diff] [blame] | 300 | for (const Argument &Arg : Callee->args()) |
| 301 | if (Arg.hasReturnedAttr()) { |
| 302 | IRPositions.emplace_back( |
| 303 | IRPosition::callsite_argument(ICS, Arg.getArgNo())); |
| 304 | IRPositions.emplace_back( |
| 305 | IRPosition::value(*ICS.getArgOperand(Arg.getArgNo()))); |
| 306 | IRPositions.emplace_back(IRPosition::argument(Arg)); |
| 307 | } |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 308 | } |
| 309 | } |
| 310 | IRPositions.emplace_back( |
| 311 | IRPosition::callsite_function(cast<CallBase>(*ICS.getInstruction()))); |
| 312 | return; |
| 313 | case IRPosition::IRP_CALL_SITE_ARGUMENT: { |
| 314 | int ArgNo = IRP.getArgNo(); |
| 315 | assert(ICS && ArgNo >= 0 && "Expected call site!"); |
| 316 | // TODO: We need to look at the operand bundles similar to the redirection |
| 317 | // in CallBase. |
| 318 | if (!ICS.hasOperandBundles()) { |
| 319 | const Function *Callee = ICS.getCalledFunction(); |
| 320 | if (Callee && Callee->arg_size() > unsigned(ArgNo)) |
| 321 | IRPositions.emplace_back(IRPosition::argument(*Callee->getArg(ArgNo))); |
| 322 | if (Callee) |
| 323 | IRPositions.emplace_back(IRPosition::function(*Callee)); |
| 324 | } |
| 325 | IRPositions.emplace_back(IRPosition::value(IRP.getAssociatedValue())); |
| 326 | return; |
| 327 | } |
| 328 | } |
| 329 | } |
| 330 | |
| Johannes Doerfert | 1097fab | 2019-10-07 21:07:57 +0000 | [diff] [blame] | 331 | bool IRPosition::hasAttr(ArrayRef<Attribute::AttrKind> AKs, |
| Johannes Doerfert | 5699d08 | 2020-02-20 02:06:48 -0600 | [diff] [blame] | 332 | bool IgnoreSubsumingPositions, Attributor *A) const { |
| Johannes Doerfert | 6185fb1 | 2020-02-20 02:02:57 -0600 | [diff] [blame] | 333 | SmallVector<Attribute, 4> Attrs; |
| Johannes Doerfert | 1097fab | 2019-10-07 21:07:57 +0000 | [diff] [blame] | 334 | for (const IRPosition &EquivIRP : SubsumingPositionIterator(*this)) { |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 335 | for (Attribute::AttrKind AK : AKs) |
| Johannes Doerfert | 6185fb1 | 2020-02-20 02:02:57 -0600 | [diff] [blame] | 336 | if (EquivIRP.getAttrsFromIRAttr(AK, Attrs)) |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 337 | return true; |
| Johannes Doerfert | 1097fab | 2019-10-07 21:07:57 +0000 | [diff] [blame] | 338 | // The first position returned by the SubsumingPositionIterator is |
| 339 | // always the position itself. If we ignore subsuming positions we |
| 340 | // are done after the first iteration. |
| 341 | if (IgnoreSubsumingPositions) |
| 342 | break; |
| 343 | } |
| Johannes Doerfert | 5699d08 | 2020-02-20 02:06:48 -0600 | [diff] [blame] | 344 | if (A) |
| 345 | for (Attribute::AttrKind AK : AKs) |
| 346 | if (getAttrsFromAssumes(AK, Attrs, *A)) |
| 347 | return true; |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 348 | return false; |
| 349 | } |
| 350 | |
| 351 | void IRPosition::getAttrs(ArrayRef<Attribute::AttrKind> AKs, |
| Johannes Doerfert | 6abd01e | 2019-12-12 15:02:36 -0600 | [diff] [blame] | 352 | SmallVectorImpl<Attribute> &Attrs, |
| Johannes Doerfert | 5699d08 | 2020-02-20 02:06:48 -0600 | [diff] [blame] | 353 | bool IgnoreSubsumingPositions, Attributor *A) const { |
| Johannes Doerfert | 6abd01e | 2019-12-12 15:02:36 -0600 | [diff] [blame] | 354 | for (const IRPosition &EquivIRP : SubsumingPositionIterator(*this)) { |
| Johannes Doerfert | 6185fb1 | 2020-02-20 02:02:57 -0600 | [diff] [blame] | 355 | for (Attribute::AttrKind AK : AKs) |
| 356 | EquivIRP.getAttrsFromIRAttr(AK, Attrs); |
| Johannes Doerfert | 6abd01e | 2019-12-12 15:02:36 -0600 | [diff] [blame] | 357 | // The first position returned by the SubsumingPositionIterator is |
| 358 | // always the position itself. If we ignore subsuming positions we |
| 359 | // are done after the first iteration. |
| 360 | if (IgnoreSubsumingPositions) |
| 361 | break; |
| 362 | } |
| Johannes Doerfert | 5699d08 | 2020-02-20 02:06:48 -0600 | [diff] [blame] | 363 | if (A) |
| 364 | for (Attribute::AttrKind AK : AKs) |
| Johannes Doerfert | bcd8009 | 2020-04-01 22:05:24 -0500 | [diff] [blame] | 365 | getAttrsFromAssumes(AK, Attrs, *A); |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 366 | } |
| 367 | |
| Johannes Doerfert | 6185fb1 | 2020-02-20 02:02:57 -0600 | [diff] [blame] | 368 | bool IRPosition::getAttrsFromIRAttr(Attribute::AttrKind AK, |
| 369 | SmallVectorImpl<Attribute> &Attrs) const { |
| 370 | if (getPositionKind() == IRP_INVALID || getPositionKind() == IRP_FLOAT) |
| 371 | return false; |
| 372 | |
| 373 | AttributeList AttrList; |
| 374 | if (ImmutableCallSite ICS = ImmutableCallSite(&getAnchorValue())) |
| 375 | AttrList = ICS.getAttributes(); |
| 376 | else |
| 377 | AttrList = getAssociatedFunction()->getAttributes(); |
| 378 | |
| 379 | bool HasAttr = AttrList.hasAttribute(getAttrIdx(), AK); |
| 380 | if (HasAttr) |
| 381 | Attrs.push_back(AttrList.getAttribute(getAttrIdx(), AK)); |
| 382 | return HasAttr; |
| 383 | } |
| 384 | |
| Johannes Doerfert | 5699d08 | 2020-02-20 02:06:48 -0600 | [diff] [blame] | 385 | bool IRPosition::getAttrsFromAssumes(Attribute::AttrKind AK, |
| 386 | SmallVectorImpl<Attribute> &Attrs, |
| 387 | Attributor &A) const { |
| 388 | assert(getPositionKind() != IRP_INVALID && "Did expect a valid position!"); |
| 389 | Value &AssociatedValue = getAssociatedValue(); |
| 390 | |
| 391 | const Assume2KnowledgeMap &A2K = |
| 392 | A.getInfoCache().getKnowledgeMap().lookup({&AssociatedValue, AK}); |
| 393 | |
| 394 | // Check if we found any potential assume use, if not we don't need to create |
| 395 | // explorer iterators. |
| 396 | if (A2K.empty()) |
| 397 | return false; |
| 398 | |
| 399 | LLVMContext &Ctx = AssociatedValue.getContext(); |
| 400 | unsigned AttrsSize = Attrs.size(); |
| 401 | MustBeExecutedContextExplorer &Explorer = |
| 402 | A.getInfoCache().getMustBeExecutedContextExplorer(); |
| 403 | auto EIt = Explorer.begin(getCtxI()), EEnd = Explorer.end(getCtxI()); |
| 404 | for (auto &It : A2K) |
| 405 | if (Explorer.findInContextOf(It.first, EIt, EEnd)) |
| 406 | Attrs.push_back(Attribute::get(Ctx, AK, It.second.Max)); |
| 407 | return AttrsSize != Attrs.size(); |
| 408 | } |
| 409 | |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 410 | void IRPosition::verify() { |
| 411 | switch (KindOrArgNo) { |
| 412 | default: |
| 413 | assert(KindOrArgNo >= 0 && "Expected argument or call site argument!"); |
| 414 | assert((isa<CallBase>(AnchorVal) || isa<Argument>(AnchorVal)) && |
| 415 | "Expected call base or argument for positive attribute index!"); |
| Simon Pilgrim | 920b040 | 2019-08-29 10:08:45 +0000 | [diff] [blame] | 416 | if (isa<Argument>(AnchorVal)) { |
| 417 | assert(cast<Argument>(AnchorVal)->getArgNo() == unsigned(getArgNo()) && |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 418 | "Argument number mismatch!"); |
| Simon Pilgrim | 920b040 | 2019-08-29 10:08:45 +0000 | [diff] [blame] | 419 | assert(cast<Argument>(AnchorVal) == &getAssociatedValue() && |
| 420 | "Associated value mismatch!"); |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 421 | } else { |
| Simon Pilgrim | 920b040 | 2019-08-29 10:08:45 +0000 | [diff] [blame] | 422 | assert(cast<CallBase>(*AnchorVal).arg_size() > unsigned(getArgNo()) && |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 423 | "Call site argument number mismatch!"); |
| Simon Pilgrim | 920b040 | 2019-08-29 10:08:45 +0000 | [diff] [blame] | 424 | assert(cast<CallBase>(*AnchorVal).getArgOperand(getArgNo()) == |
| 425 | &getAssociatedValue() && |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 426 | "Associated value mismatch!"); |
| 427 | } |
| 428 | break; |
| 429 | case IRP_INVALID: |
| 430 | assert(!AnchorVal && "Expected no value for an invalid position!"); |
| 431 | break; |
| 432 | case IRP_FLOAT: |
| 433 | assert((!isa<CallBase>(&getAssociatedValue()) && |
| 434 | !isa<Argument>(&getAssociatedValue())) && |
| 435 | "Expected specialized kind for call base and argument values!"); |
| 436 | break; |
| 437 | case IRP_RETURNED: |
| 438 | assert(isa<Function>(AnchorVal) && |
| 439 | "Expected function for a 'returned' position!"); |
| 440 | assert(AnchorVal == &getAssociatedValue() && "Associated value mismatch!"); |
| 441 | break; |
| 442 | case IRP_CALL_SITE_RETURNED: |
| 443 | assert((isa<CallBase>(AnchorVal)) && |
| 444 | "Expected call base for 'call site returned' position!"); |
| 445 | assert(AnchorVal == &getAssociatedValue() && "Associated value mismatch!"); |
| 446 | break; |
| 447 | case IRP_CALL_SITE: |
| 448 | assert((isa<CallBase>(AnchorVal)) && |
| 449 | "Expected call base for 'call site function' position!"); |
| 450 | assert(AnchorVal == &getAssociatedValue() && "Associated value mismatch!"); |
| 451 | break; |
| 452 | case IRP_FUNCTION: |
| 453 | assert(isa<Function>(AnchorVal) && |
| 454 | "Expected function for a 'function' position!"); |
| 455 | assert(AnchorVal == &getAssociatedValue() && "Associated value mismatch!"); |
| 456 | break; |
| 457 | } |
| 458 | } |
| 459 | |
| Johannes Doerfert | 0985554 | 2020-04-08 17:24:24 -0500 | [diff] [blame] | 460 | Optional<Constant *> |
| 461 | Attributor::getAssumedConstant(const Value &V, const AbstractAttribute &AA, |
| 462 | bool &UsedAssumedInformation) { |
| 463 | const auto &ValueSimplifyAA = getAAFor<AAValueSimplify>( |
| 464 | AA, IRPosition::value(V), /* TrackDependence */ false); |
| 465 | Optional<Value *> SimplifiedV = |
| 466 | ValueSimplifyAA.getAssumedSimplifiedValue(*this); |
| 467 | bool IsKnown = ValueSimplifyAA.isKnown(); |
| 468 | UsedAssumedInformation |= !IsKnown; |
| 469 | if (!SimplifiedV.hasValue()) { |
| 470 | recordDependence(ValueSimplifyAA, AA, DepClassTy::OPTIONAL); |
| 471 | return llvm::None; |
| Johannes Doerfert | d95cb56 | 2020-02-20 02:03:32 -0600 | [diff] [blame] | 472 | } |
| Johannes Doerfert | 0985554 | 2020-04-08 17:24:24 -0500 | [diff] [blame] | 473 | if (isa_and_nonnull<UndefValue>(SimplifiedV.getValue())) { |
| 474 | recordDependence(ValueSimplifyAA, AA, DepClassTy::OPTIONAL); |
| 475 | return llvm::None; |
| Hideto Ueno | 08daf8c | 2019-10-08 15:20:19 +0000 | [diff] [blame] | 476 | } |
| Johannes Doerfert | 0985554 | 2020-04-08 17:24:24 -0500 | [diff] [blame] | 477 | Constant *CI = dyn_cast_or_null<Constant>(SimplifiedV.getValue()); |
| 478 | if (CI && CI->getType() != V.getType()) { |
| 479 | // TODO: Check for a save conversion. |
| Johannes Doerfert | 89c2e73 | 2019-10-30 17:20:20 -0500 | [diff] [blame] | 480 | return nullptr; |
| 481 | } |
| Johannes Doerfert | 0985554 | 2020-04-08 17:24:24 -0500 | [diff] [blame] | 482 | if (CI) |
| 483 | recordDependence(ValueSimplifyAA, AA, DepClassTy::OPTIONAL); |
| 484 | return CI; |
| Johannes Doerfert | 1097fab | 2019-10-07 21:07:57 +0000 | [diff] [blame] | 485 | } |
| 486 | |
| Johannes Doerfert | 41f2a57 | 2020-04-01 20:41:35 -0500 | [diff] [blame] | 487 | Attributor::~Attributor() { |
| 488 | // The abstract attributes are allocated via the BumpPtrAllocator Allocator, |
| 489 | // thus we cannot delete them. We can, and want to, destruct them though. |
| 490 | for (AbstractAttribute *AA : AllAbstractAttributes) |
| 491 | AA->~AbstractAttribute(); |
| 492 | |
| 493 | for (auto &It : ArgumentReplacementMap) |
| 494 | DeleteContainerPointers(It.second); |
| 495 | } |
| 496 | |
| Johannes Doerfert | 9a1a1f9 | 2019-08-14 21:25:08 +0000 | [diff] [blame] | 497 | bool Attributor::isAssumedDead(const AbstractAttribute &AA, |
| Johannes Doerfert | 23f41f1 | 2020-01-12 01:09:22 -0600 | [diff] [blame] | 498 | const AAIsDead *FnLivenessAA, |
| 499 | bool CheckBBLivenessOnly, DepClassTy DepClass) { |
| 500 | const IRPosition &IRP = AA.getIRPosition(); |
| 501 | if (!Functions.count(IRP.getAnchorScope())) |
| 502 | return false; |
| 503 | return isAssumedDead(IRP, &AA, FnLivenessAA, CheckBBLivenessOnly, DepClass); |
| 504 | } |
| 505 | |
| 506 | bool Attributor::isAssumedDead(const Use &U, |
| 507 | const AbstractAttribute *QueryingAA, |
| 508 | const AAIsDead *FnLivenessAA, |
| 509 | bool CheckBBLivenessOnly, DepClassTy DepClass) { |
| 510 | Instruction *UserI = dyn_cast<Instruction>(U.getUser()); |
| 511 | if (!UserI) |
| 512 | return isAssumedDead(IRPosition::value(*U.get()), QueryingAA, FnLivenessAA, |
| 513 | CheckBBLivenessOnly, DepClass); |
| 514 | |
| 515 | if (CallSite CS = CallSite(UserI)) { |
| 516 | // For call site argument uses we can check if the argument is |
| 517 | // unused/dead. |
| 518 | if (CS.isArgOperand(&U)) { |
| 519 | const IRPosition &CSArgPos = |
| 520 | IRPosition::callsite_argument(CS, CS.getArgumentNo(&U)); |
| 521 | return isAssumedDead(CSArgPos, QueryingAA, FnLivenessAA, |
| 522 | CheckBBLivenessOnly, DepClass); |
| 523 | } |
| 524 | } else if (ReturnInst *RI = dyn_cast<ReturnInst>(UserI)) { |
| 525 | const IRPosition &RetPos = IRPosition::returned(*RI->getFunction()); |
| 526 | return isAssumedDead(RetPos, QueryingAA, FnLivenessAA, CheckBBLivenessOnly, |
| 527 | DepClass); |
| 528 | } else if (PHINode *PHI = dyn_cast<PHINode>(UserI)) { |
| 529 | BasicBlock *IncomingBB = PHI->getIncomingBlock(U); |
| 530 | return isAssumedDead(*IncomingBB->getTerminator(), QueryingAA, FnLivenessAA, |
| 531 | CheckBBLivenessOnly, DepClass); |
| 532 | } |
| 533 | |
| 534 | return isAssumedDead(IRPosition::value(*UserI), QueryingAA, FnLivenessAA, |
| 535 | CheckBBLivenessOnly, DepClass); |
| 536 | } |
| 537 | |
| 538 | bool Attributor::isAssumedDead(const Instruction &I, |
| 539 | const AbstractAttribute *QueryingAA, |
| 540 | const AAIsDead *FnLivenessAA, |
| 541 | bool CheckBBLivenessOnly, DepClassTy DepClass) { |
| 542 | if (!FnLivenessAA) |
| 543 | FnLivenessAA = lookupAAFor<AAIsDead>(IRPosition::function(*I.getFunction()), |
| 544 | QueryingAA, |
| 545 | /* TrackDependence */ false); |
| 546 | |
| 547 | // If we have a context instruction and a liveness AA we use it. |
| 548 | if (FnLivenessAA && |
| 549 | FnLivenessAA->getIRPosition().getAnchorScope() == I.getFunction() && |
| 550 | FnLivenessAA->isAssumedDead(&I)) { |
| 551 | if (QueryingAA) |
| 552 | recordDependence(*FnLivenessAA, *QueryingAA, DepClass); |
| 553 | return true; |
| 554 | } |
| 555 | |
| 556 | if (CheckBBLivenessOnly) |
| Johannes Doerfert | 9a1a1f9 | 2019-08-14 21:25:08 +0000 | [diff] [blame] | 557 | return false; |
| 558 | |
| Johannes Doerfert | 23f41f1 | 2020-01-12 01:09:22 -0600 | [diff] [blame] | 559 | const AAIsDead &IsDeadAA = getOrCreateAAFor<AAIsDead>( |
| 560 | IRPosition::value(I), QueryingAA, /* TrackDependence */ false); |
| Stefan Stipanovic | 26121ae | 2019-08-20 23:16:57 +0000 | [diff] [blame] | 561 | // Don't check liveness for AAIsDead. |
| Johannes Doerfert | 23f41f1 | 2020-01-12 01:09:22 -0600 | [diff] [blame] | 562 | if (QueryingAA == &IsDeadAA) |
| Stefan Stipanovic | 26121ae | 2019-08-20 23:16:57 +0000 | [diff] [blame] | 563 | return false; |
| 564 | |
| Johannes Doerfert | 23f41f1 | 2020-01-12 01:09:22 -0600 | [diff] [blame] | 565 | if (IsDeadAA.isAssumedDead()) { |
| 566 | if (QueryingAA) |
| 567 | recordDependence(IsDeadAA, *QueryingAA, DepClass); |
| 568 | return true; |
| 569 | } |
| 570 | |
| 571 | return false; |
| 572 | } |
| 573 | |
| 574 | bool Attributor::isAssumedDead(const IRPosition &IRP, |
| 575 | const AbstractAttribute *QueryingAA, |
| 576 | const AAIsDead *FnLivenessAA, |
| 577 | bool CheckBBLivenessOnly, DepClassTy DepClass) { |
| 578 | Instruction *CtxI = IRP.getCtxI(); |
| 579 | if (CtxI && |
| 580 | isAssumedDead(*CtxI, QueryingAA, FnLivenessAA, |
| 581 | /* CheckBBLivenessOnly */ true, |
| 582 | CheckBBLivenessOnly ? DepClass : DepClassTy::OPTIONAL)) |
| 583 | return true; |
| 584 | |
| 585 | if (CheckBBLivenessOnly) |
| Johannes Doerfert | 9a1a1f9 | 2019-08-14 21:25:08 +0000 | [diff] [blame] | 586 | return false; |
| 587 | |
| Johannes Doerfert | 23f41f1 | 2020-01-12 01:09:22 -0600 | [diff] [blame] | 588 | // If we haven't succeeded we query the specific liveness info for the IRP. |
| 589 | const AAIsDead *IsDeadAA; |
| 590 | if (IRP.getPositionKind() == IRPosition::IRP_CALL_SITE) |
| 591 | IsDeadAA = &getOrCreateAAFor<AAIsDead>( |
| 592 | IRPosition::callsite_returned(cast<CallBase>(IRP.getAssociatedValue())), |
| 593 | QueryingAA, /* TrackDependence */ false); |
| 594 | else |
| 595 | IsDeadAA = &getOrCreateAAFor<AAIsDead>(IRP, QueryingAA, |
| 596 | /* TrackDependence */ false); |
| 597 | // Don't check liveness for AAIsDead. |
| 598 | if (QueryingAA == IsDeadAA) |
| 599 | return false; |
| Johannes Doerfert | 19b0043 | 2019-08-26 17:48:05 +0000 | [diff] [blame] | 600 | |
| Johannes Doerfert | 23f41f1 | 2020-01-12 01:09:22 -0600 | [diff] [blame] | 601 | if (IsDeadAA->isAssumedDead()) { |
| 602 | if (QueryingAA) |
| 603 | recordDependence(*IsDeadAA, *QueryingAA, DepClass); |
| 604 | return true; |
| 605 | } |
| 606 | |
| 607 | return false; |
| Johannes Doerfert | 9a1a1f9 | 2019-08-14 21:25:08 +0000 | [diff] [blame] | 608 | } |
| 609 | |
| Johannes Doerfert | c57689b | 2020-03-23 02:02:09 -0500 | [diff] [blame] | 610 | bool Attributor::checkForAllUses(function_ref<bool(const Use &, bool &)> Pred, |
| 611 | const AbstractAttribute &QueryingAA, |
| 612 | const Value &V, DepClassTy LivenessDepClass) { |
| Johannes Doerfert | b2c7600 | 2020-01-23 17:12:56 -0600 | [diff] [blame] | 613 | |
| 614 | // Check the trivial case first as it catches void values. |
| 615 | if (V.use_empty()) |
| 616 | return true; |
| 617 | |
| 618 | // If the value is replaced by another one, for now a constant, we do not have |
| 619 | // uses. Note that this requires users of `checkForAllUses` to not recurse but |
| 620 | // instead use the `follow` callback argument to look at transitive users, |
| 621 | // however, that should be clear from the presence of the argument. |
| 622 | bool UsedAssumedInformation = false; |
| Johannes Doerfert | e1eed6c | 2020-02-16 16:45:28 -0600 | [diff] [blame] | 623 | Optional<Constant *> C = |
| Johannes Doerfert | 0985554 | 2020-04-08 17:24:24 -0500 | [diff] [blame] | 624 | getAssumedConstant(V, QueryingAA, UsedAssumedInformation); |
| Johannes Doerfert | e1eed6c | 2020-02-16 16:45:28 -0600 | [diff] [blame] | 625 | if (C.hasValue() && C.getValue()) { |
| Johannes Doerfert | b2c7600 | 2020-01-23 17:12:56 -0600 | [diff] [blame] | 626 | LLVM_DEBUG(dbgs() << "[Attributor] Value is simplified, uses skipped: " << V |
| Johannes Doerfert | e1eed6c | 2020-02-16 16:45:28 -0600 | [diff] [blame] | 627 | << " -> " << *C.getValue() << "\n"); |
| Johannes Doerfert | b2c7600 | 2020-01-23 17:12:56 -0600 | [diff] [blame] | 628 | return true; |
| 629 | } |
| 630 | |
| Johannes Doerfert | cd4aab4 | 2019-10-13 03:08:18 -0500 | [diff] [blame] | 631 | const IRPosition &IRP = QueryingAA.getIRPosition(); |
| 632 | SmallVector<const Use *, 16> Worklist; |
| 633 | SmallPtrSet<const Use *, 16> Visited; |
| 634 | |
| 635 | for (const Use &U : V.uses()) |
| 636 | Worklist.push_back(&U); |
| 637 | |
| 638 | LLVM_DEBUG(dbgs() << "[Attributor] Got " << Worklist.size() |
| 639 | << " initial uses to check\n"); |
| 640 | |
| Johannes Doerfert | cd4aab4 | 2019-10-13 03:08:18 -0500 | [diff] [blame] | 641 | const Function *ScopeFn = IRP.getAnchorScope(); |
| 642 | const auto *LivenessAA = |
| 643 | ScopeFn ? &getAAFor<AAIsDead>(QueryingAA, IRPosition::function(*ScopeFn), |
| 644 | /* TrackDependence */ false) |
| 645 | : nullptr; |
| 646 | |
| 647 | while (!Worklist.empty()) { |
| 648 | const Use *U = Worklist.pop_back_val(); |
| 649 | if (!Visited.insert(U).second) |
| 650 | continue; |
| Johannes Doerfert | 23f41f1 | 2020-01-12 01:09:22 -0600 | [diff] [blame] | 651 | LLVM_DEBUG(dbgs() << "[Attributor] Check use: " << **U << " in " |
| 652 | << *U->getUser() << "\n"); |
| 653 | if (isAssumedDead(*U, &QueryingAA, LivenessAA, |
| 654 | /* CheckBBLivenessOnly */ false, LivenessDepClass)) { |
| 655 | LLVM_DEBUG(dbgs() << "[Attributor] Dead use, skip!\n"); |
| 656 | continue; |
| Johannes Doerfert | 8e62968 | 2020-02-11 00:10:35 -0600 | [diff] [blame] | 657 | } |
| Johannes Doerfert | 5699d08 | 2020-02-20 02:06:48 -0600 | [diff] [blame] | 658 | if (U->getUser()->isDroppable()) { |
| 659 | LLVM_DEBUG(dbgs() << "[Attributor] Droppable user, skip!\n"); |
| 660 | continue; |
| 661 | } |
| Johannes Doerfert | cd4aab4 | 2019-10-13 03:08:18 -0500 | [diff] [blame] | 662 | |
| 663 | bool Follow = false; |
| 664 | if (!Pred(*U, Follow)) |
| 665 | return false; |
| 666 | if (!Follow) |
| 667 | continue; |
| 668 | for (const Use &UU : U->getUser()->uses()) |
| 669 | Worklist.push_back(&UU); |
| 670 | } |
| 671 | |
| Johannes Doerfert | cd4aab4 | 2019-10-13 03:08:18 -0500 | [diff] [blame] | 672 | return true; |
| 673 | } |
| 674 | |
| Johannes Doerfert | c57689b | 2020-03-23 02:02:09 -0500 | [diff] [blame] | 675 | bool Attributor::checkForAllCallSites(function_ref<bool(AbstractCallSite)> Pred, |
| 676 | const AbstractAttribute &QueryingAA, |
| 677 | bool RequireAllCallSites, |
| 678 | bool &AllCallSitesKnown) { |
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 679 | // We can try to determine information from |
| 680 | // the call sites. However, this is only possible all call sites are known, |
| 681 | // hence the function has internal linkage. |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 682 | const IRPosition &IRP = QueryingAA.getIRPosition(); |
| 683 | const Function *AssociatedFunction = IRP.getAssociatedFunction(); |
| Johannes Doerfert | 748538e | 2019-10-07 23:30:04 +0000 | [diff] [blame] | 684 | if (!AssociatedFunction) { |
| 685 | LLVM_DEBUG(dbgs() << "[Attributor] No function associated with " << IRP |
| 686 | << "\n"); |
| Johannes Doerfert | 368f7ee | 2019-12-30 16:12:36 -0600 | [diff] [blame] | 687 | AllCallSitesKnown = false; |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 688 | return false; |
| Johannes Doerfert | 748538e | 2019-10-07 23:30:04 +0000 | [diff] [blame] | 689 | } |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 690 | |
| Johannes Doerfert | 3753aa7 | 2019-10-13 04:16:02 +0000 | [diff] [blame] | 691 | return checkForAllCallSites(Pred, *AssociatedFunction, RequireAllCallSites, |
| Johannes Doerfert | 368f7ee | 2019-12-30 16:12:36 -0600 | [diff] [blame] | 692 | &QueryingAA, AllCallSitesKnown); |
| Johannes Doerfert | 3753aa7 | 2019-10-13 04:16:02 +0000 | [diff] [blame] | 693 | } |
| 694 | |
| Johannes Doerfert | c57689b | 2020-03-23 02:02:09 -0500 | [diff] [blame] | 695 | bool Attributor::checkForAllCallSites(function_ref<bool(AbstractCallSite)> Pred, |
| 696 | const Function &Fn, |
| 697 | bool RequireAllCallSites, |
| 698 | const AbstractAttribute *QueryingAA, |
| 699 | bool &AllCallSitesKnown) { |
| Johannes Doerfert | 3753aa7 | 2019-10-13 04:16:02 +0000 | [diff] [blame] | 700 | if (RequireAllCallSites && !Fn.hasLocalLinkage()) { |
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 701 | LLVM_DEBUG( |
| 702 | dbgs() |
| Johannes Doerfert | 3753aa7 | 2019-10-13 04:16:02 +0000 | [diff] [blame] | 703 | << "[Attributor] Function " << Fn.getName() |
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 704 | << " has no internal linkage, hence not all call sites are known\n"); |
| Johannes Doerfert | 368f7ee | 2019-12-30 16:12:36 -0600 | [diff] [blame] | 705 | AllCallSitesKnown = false; |
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 706 | return false; |
| 707 | } |
| 708 | |
| Johannes Doerfert | 368f7ee | 2019-12-30 16:12:36 -0600 | [diff] [blame] | 709 | // If we do not require all call sites we might not see all. |
| 710 | AllCallSitesKnown = RequireAllCallSites; |
| 711 | |
| Johannes Doerfert | c6ac717 | 2020-01-25 20:24:38 -0600 | [diff] [blame] | 712 | SmallVector<const Use *, 8> Uses(make_pointer_range(Fn.uses())); |
| 713 | for (unsigned u = 0; u < Uses.size(); ++u) { |
| 714 | const Use &U = *Uses[u]; |
| Johannes Doerfert | 23f41f1 | 2020-01-12 01:09:22 -0600 | [diff] [blame] | 715 | LLVM_DEBUG(dbgs() << "[Attributor] Check use: " << *U << " in " |
| 716 | << *U.getUser() << "\n"); |
| 717 | if (isAssumedDead(U, QueryingAA, nullptr, /* CheckBBLivenessOnly */ true)) { |
| 718 | LLVM_DEBUG(dbgs() << "[Attributor] Dead use, skip!\n"); |
| 719 | continue; |
| 720 | } |
| Johannes Doerfert | c6ac717 | 2020-01-25 20:24:38 -0600 | [diff] [blame] | 721 | if (ConstantExpr *CE = dyn_cast<ConstantExpr>(U.getUser())) { |
| 722 | if (CE->isCast() && CE->getType()->isPointerTy() && |
| 723 | CE->getType()->getPointerElementType()->isFunctionTy()) { |
| 724 | for (const Use &CEU : CE->uses()) |
| 725 | Uses.push_back(&CEU); |
| 726 | continue; |
| 727 | } |
| 728 | } |
| Johannes Doerfert | 23f41f1 | 2020-01-12 01:09:22 -0600 | [diff] [blame] | 729 | |
| Johannes Doerfert | 661db04 | 2019-10-07 23:14:58 +0000 | [diff] [blame] | 730 | AbstractCallSite ACS(&U); |
| 731 | if (!ACS) { |
| Stefan Stipanovic | f35740d | 2019-11-02 16:35:38 +0100 | [diff] [blame] | 732 | LLVM_DEBUG(dbgs() << "[Attributor] Function " << Fn.getName() |
| Johannes Doerfert | 661db04 | 2019-10-07 23:14:58 +0000 | [diff] [blame] | 733 | << " has non call site use " << *U.get() << " in " |
| 734 | << *U.getUser() << "\n"); |
| Johannes Doerfert | 2d77b0c | 2019-11-01 22:35:18 -0500 | [diff] [blame] | 735 | // BlockAddress users are allowed. |
| 736 | if (isa<BlockAddress>(U.getUser())) |
| 737 | continue; |
| Johannes Doerfert | d98f975 | 2019-08-21 21:48:56 +0000 | [diff] [blame] | 738 | return false; |
| Johannes Doerfert | 661db04 | 2019-10-07 23:14:58 +0000 | [diff] [blame] | 739 | } |
| Johannes Doerfert | d98f975 | 2019-08-21 21:48:56 +0000 | [diff] [blame] | 740 | |
| Johannes Doerfert | 661db04 | 2019-10-07 23:14:58 +0000 | [diff] [blame] | 741 | const Use *EffectiveUse = |
| 742 | ACS.isCallbackCall() ? &ACS.getCalleeUseForCallback() : &U; |
| 743 | if (!ACS.isCallee(EffectiveUse)) { |
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 744 | if (!RequireAllCallSites) |
| 745 | continue; |
| Johannes Doerfert | 661db04 | 2019-10-07 23:14:58 +0000 | [diff] [blame] | 746 | LLVM_DEBUG(dbgs() << "[Attributor] User " << EffectiveUse->getUser() |
| Stefan Stipanovic | f35740d | 2019-11-02 16:35:38 +0100 | [diff] [blame] | 747 | << " is an invalid use of " << Fn.getName() << "\n"); |
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 748 | return false; |
| 749 | } |
| 750 | |
| Johannes Doerfert | 1e99fc9 | 2020-02-16 16:42:47 -0600 | [diff] [blame] | 751 | // Make sure the arguments that can be matched between the call site and the |
| 752 | // callee argee on their type. It is unlikely they do not and it doesn't |
| 753 | // make sense for all attributes to know/care about this. |
| 754 | assert(&Fn == ACS.getCalledFunction() && "Expected known callee"); |
| 755 | unsigned MinArgsParams = |
| 756 | std::min(size_t(ACS.getNumArgOperands()), Fn.arg_size()); |
| 757 | for (unsigned u = 0; u < MinArgsParams; ++u) { |
| 758 | Value *CSArgOp = ACS.getCallArgOperand(u); |
| 759 | if (CSArgOp && Fn.getArg(u)->getType() != CSArgOp->getType()) { |
| 760 | LLVM_DEBUG( |
| 761 | dbgs() << "[Attributor] Call site / callee argument type mismatch [" |
| 762 | << u << "@" << Fn.getName() << ": " |
| 763 | << *Fn.getArg(u)->getType() << " vs. " |
| 764 | << *ACS.getCallArgOperand(u)->getType() << "\n"); |
| 765 | return false; |
| 766 | } |
| 767 | } |
| 768 | |
| Johannes Doerfert | 661db04 | 2019-10-07 23:14:58 +0000 | [diff] [blame] | 769 | if (Pred(ACS)) |
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 770 | continue; |
| 771 | |
| Johannes Doerfert | 5304b72 | 2019-08-14 22:04:28 +0000 | [diff] [blame] | 772 | LLVM_DEBUG(dbgs() << "[Attributor] Call site callback failed for " |
| Johannes Doerfert | 661db04 | 2019-10-07 23:14:58 +0000 | [diff] [blame] | 773 | << *ACS.getInstruction() << "\n"); |
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 774 | return false; |
| 775 | } |
| 776 | |
| 777 | return true; |
| 778 | } |
| 779 | |
| Johannes Doerfert | 14a0493 | 2019-08-07 22:27:24 +0000 | [diff] [blame] | 780 | bool Attributor::checkForAllReturnedValuesAndReturnInsts( |
| Johannes Doerfert | c57689b | 2020-03-23 02:02:09 -0500 | [diff] [blame] | 781 | function_ref<bool(Value &, const SmallSetVector<ReturnInst *, 4> &)> Pred, |
| Johannes Doerfert | 14a0493 | 2019-08-07 22:27:24 +0000 | [diff] [blame] | 782 | const AbstractAttribute &QueryingAA) { |
| 783 | |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 784 | const IRPosition &IRP = QueryingAA.getIRPosition(); |
| 785 | // Since we need to provide return instructions we have to have an exact |
| 786 | // definition. |
| 787 | const Function *AssociatedFunction = IRP.getAssociatedFunction(); |
| Johannes Doerfert | b0412e4 | 2019-09-04 16:16:13 +0000 | [diff] [blame] | 788 | if (!AssociatedFunction) |
| Johannes Doerfert | 14a0493 | 2019-08-07 22:27:24 +0000 | [diff] [blame] | 789 | return false; |
| 790 | |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 791 | // If this is a call site query we use the call site specific return values |
| 792 | // and liveness information. |
| Johannes Doerfert | 07a5c12 | 2019-08-28 14:09:14 +0000 | [diff] [blame] | 793 | // TODO: use the function scope once we have call site AAReturnedValues. |
| 794 | const IRPosition &QueryIRP = IRPosition::function(*AssociatedFunction); |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 795 | const auto &AARetVal = getAAFor<AAReturnedValues>(QueryingAA, QueryIRP); |
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 796 | if (!AARetVal.getState().isValidState()) |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 797 | return false; |
| 798 | |
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 799 | return AARetVal.checkForAllReturnedValuesAndReturnInsts(Pred); |
| Johannes Doerfert | 14a0493 | 2019-08-07 22:27:24 +0000 | [diff] [blame] | 800 | } |
| 801 | |
| 802 | bool Attributor::checkForAllReturnedValues( |
| Johannes Doerfert | c57689b | 2020-03-23 02:02:09 -0500 | [diff] [blame] | 803 | function_ref<bool(Value &)> Pred, const AbstractAttribute &QueryingAA) { |
| Johannes Doerfert | 14a0493 | 2019-08-07 22:27:24 +0000 | [diff] [blame] | 804 | |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 805 | const IRPosition &IRP = QueryingAA.getIRPosition(); |
| 806 | const Function *AssociatedFunction = IRP.getAssociatedFunction(); |
| Johannes Doerfert | b0412e4 | 2019-09-04 16:16:13 +0000 | [diff] [blame] | 807 | if (!AssociatedFunction) |
| Johannes Doerfert | 14a0493 | 2019-08-07 22:27:24 +0000 | [diff] [blame] | 808 | return false; |
| 809 | |
| Johannes Doerfert | 07a5c12 | 2019-08-28 14:09:14 +0000 | [diff] [blame] | 810 | // TODO: use the function scope once we have call site AAReturnedValues. |
| 811 | const IRPosition &QueryIRP = IRPosition::function(*AssociatedFunction); |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 812 | const auto &AARetVal = getAAFor<AAReturnedValues>(QueryingAA, QueryIRP); |
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 813 | if (!AARetVal.getState().isValidState()) |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 814 | return false; |
| 815 | |
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 816 | return AARetVal.checkForAllReturnedValuesAndReturnInsts( |
| Johannes Doerfert | 695089e | 2019-08-23 15:23:49 +0000 | [diff] [blame] | 817 | [&](Value &RV, const SmallSetVector<ReturnInst *, 4> &) { |
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 818 | return Pred(RV); |
| 819 | }); |
| Johannes Doerfert | 14a0493 | 2019-08-07 22:27:24 +0000 | [diff] [blame] | 820 | } |
| 821 | |
| Johannes Doerfert | 23f41f1 | 2020-01-12 01:09:22 -0600 | [diff] [blame] | 822 | static bool checkForAllInstructionsImpl( |
| 823 | Attributor *A, InformationCache::OpcodeInstMapTy &OpcodeInstMap, |
| Johannes Doerfert | c57689b | 2020-03-23 02:02:09 -0500 | [diff] [blame] | 824 | function_ref<bool(Instruction &)> Pred, const AbstractAttribute *QueryingAA, |
| 825 | const AAIsDead *LivenessAA, const ArrayRef<unsigned> &Opcodes, |
| 826 | bool CheckBBLivenessOnly = false) { |
| Johannes Doerfert | 3ab9e8b | 2019-09-17 10:52:41 +0000 | [diff] [blame] | 827 | for (unsigned Opcode : Opcodes) { |
| 828 | for (Instruction *I : OpcodeInstMap[Opcode]) { |
| 829 | // Skip dead instructions. |
| Johannes Doerfert | 23f41f1 | 2020-01-12 01:09:22 -0600 | [diff] [blame] | 830 | if (A && A->isAssumedDead(IRPosition::value(*I), QueryingAA, LivenessAA, |
| 831 | CheckBBLivenessOnly)) |
| Johannes Doerfert | 3ab9e8b | 2019-09-17 10:52:41 +0000 | [diff] [blame] | 832 | continue; |
| Johannes Doerfert | 3ab9e8b | 2019-09-17 10:52:41 +0000 | [diff] [blame] | 833 | |
| 834 | if (!Pred(*I)) |
| 835 | return false; |
| 836 | } |
| 837 | } |
| 838 | return true; |
| 839 | } |
| 840 | |
| Johannes Doerfert | c57689b | 2020-03-23 02:02:09 -0500 | [diff] [blame] | 841 | bool Attributor::checkForAllInstructions(function_ref<bool(Instruction &)> Pred, |
| 842 | const AbstractAttribute &QueryingAA, |
| 843 | const ArrayRef<unsigned> &Opcodes, |
| 844 | bool CheckBBLivenessOnly) { |
| Johannes Doerfert | d0f6400 | 2019-08-06 00:32:43 +0000 | [diff] [blame] | 845 | |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 846 | const IRPosition &IRP = QueryingAA.getIRPosition(); |
| 847 | // Since we need to provide instructions we have to have an exact definition. |
| 848 | const Function *AssociatedFunction = IRP.getAssociatedFunction(); |
| Johannes Doerfert | b0412e4 | 2019-09-04 16:16:13 +0000 | [diff] [blame] | 849 | if (!AssociatedFunction) |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 850 | return false; |
| Johannes Doerfert | d0f6400 | 2019-08-06 00:32:43 +0000 | [diff] [blame] | 851 | |
| Johannes Doerfert | 07a5c12 | 2019-08-28 14:09:14 +0000 | [diff] [blame] | 852 | // TODO: use the function scope once we have call site AAReturnedValues. |
| 853 | const IRPosition &QueryIRP = IRPosition::function(*AssociatedFunction); |
| Johannes Doerfert | 19b0043 | 2019-08-26 17:48:05 +0000 | [diff] [blame] | 854 | const auto &LivenessAA = |
| 855 | getAAFor<AAIsDead>(QueryingAA, QueryIRP, /* TrackDependence */ false); |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 856 | |
| 857 | auto &OpcodeInstMap = |
| 858 | InfoCache.getOpcodeInstMapForFunction(*AssociatedFunction); |
| Johannes Doerfert | 23f41f1 | 2020-01-12 01:09:22 -0600 | [diff] [blame] | 859 | if (!checkForAllInstructionsImpl(this, OpcodeInstMap, Pred, &QueryingAA, |
| 860 | &LivenessAA, Opcodes, CheckBBLivenessOnly)) |
| Johannes Doerfert | 3ab9e8b | 2019-09-17 10:52:41 +0000 | [diff] [blame] | 861 | return false; |
| Johannes Doerfert | d0f6400 | 2019-08-06 00:32:43 +0000 | [diff] [blame] | 862 | |
| 863 | return true; |
| 864 | } |
| 865 | |
| Stefan Stipanovic | aaa5270 | 2019-08-07 18:26:02 +0000 | [diff] [blame] | 866 | bool Attributor::checkForAllReadWriteInstructions( |
| Johannes Doerfert | c57689b | 2020-03-23 02:02:09 -0500 | [diff] [blame] | 867 | function_ref<bool(Instruction &)> Pred, AbstractAttribute &QueryingAA) { |
| Stefan Stipanovic | aaa5270 | 2019-08-07 18:26:02 +0000 | [diff] [blame] | 868 | |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 869 | const Function *AssociatedFunction = |
| 870 | QueryingAA.getIRPosition().getAssociatedFunction(); |
| 871 | if (!AssociatedFunction) |
| 872 | return false; |
| Stefan Stipanovic | aaa5270 | 2019-08-07 18:26:02 +0000 | [diff] [blame] | 873 | |
| Johannes Doerfert | 07a5c12 | 2019-08-28 14:09:14 +0000 | [diff] [blame] | 874 | // TODO: use the function scope once we have call site AAReturnedValues. |
| 875 | const IRPosition &QueryIRP = IRPosition::function(*AssociatedFunction); |
| 876 | const auto &LivenessAA = |
| 877 | getAAFor<AAIsDead>(QueryingAA, QueryIRP, /* TrackDependence */ false); |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 878 | |
| 879 | for (Instruction *I : |
| 880 | InfoCache.getReadOrWriteInstsForFunction(*AssociatedFunction)) { |
| Stefan Stipanovic | aaa5270 | 2019-08-07 18:26:02 +0000 | [diff] [blame] | 881 | // Skip dead instructions. |
| Johannes Doerfert | 23f41f1 | 2020-01-12 01:09:22 -0600 | [diff] [blame] | 882 | if (isAssumedDead(IRPosition::value(*I), &QueryingAA, &LivenessAA)) |
| Stefan Stipanovic | aaa5270 | 2019-08-07 18:26:02 +0000 | [diff] [blame] | 883 | continue; |
| 884 | |
| 885 | if (!Pred(*I)) |
| 886 | return false; |
| 887 | } |
| 888 | |
| 889 | return true; |
| 890 | } |
| 891 | |
| Johannes Doerfert | b0c77c3 | 2019-11-27 00:30:12 -0600 | [diff] [blame] | 892 | ChangeStatus Attributor::run() { |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 893 | LLVM_DEBUG(dbgs() << "[Attributor] Identified and initialized " |
| 894 | << AllAbstractAttributes.size() |
| 895 | << " abstract attributes.\n"); |
| 896 | |
| Stefan Stipanovic | 5360589 | 2019-06-27 11:27:54 +0000 | [diff] [blame] | 897 | // Now that all abstract attributes are collected and initialized we start |
| 898 | // the abstract analysis. |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 899 | |
| 900 | unsigned IterationCounter = 1; |
| 901 | |
| Stefanos Baziotis | a650d55 | 2020-03-23 22:44:10 +0200 | [diff] [blame] | 902 | SmallVector<AbstractAttribute *, 32> ChangedAAs; |
| Johannes Doerfert | 680f638 | 2019-11-02 02:48:05 -0500 | [diff] [blame] | 903 | SetVector<AbstractAttribute *> Worklist, InvalidAAs; |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 904 | Worklist.insert(AllAbstractAttributes.begin(), AllAbstractAttributes.end()); |
| 905 | |
| Johannes Doerfert | f7ca0fe | 2019-08-28 16:58:52 +0000 | [diff] [blame] | 906 | bool RecomputeDependences = false; |
| 907 | |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 908 | do { |
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 909 | // Remember the size to determine new attributes. |
| 910 | size_t NumAAs = AllAbstractAttributes.size(); |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 911 | LLVM_DEBUG(dbgs() << "\n\n[Attributor] #Iteration: " << IterationCounter |
| 912 | << ", Worklist size: " << Worklist.size() << "\n"); |
| 913 | |
| Johannes Doerfert | 680f638 | 2019-11-02 02:48:05 -0500 | [diff] [blame] | 914 | // For invalid AAs we can fix dependent AAs that have a required dependence, |
| 915 | // thereby folding long dependence chains in a single step without the need |
| 916 | // to run updates. |
| 917 | for (unsigned u = 0; u < InvalidAAs.size(); ++u) { |
| 918 | AbstractAttribute *InvalidAA = InvalidAAs[u]; |
| 919 | auto &QuerriedAAs = QueryMap[InvalidAA]; |
| 920 | LLVM_DEBUG(dbgs() << "[Attributor] InvalidAA: " << *InvalidAA << " has " |
| 921 | << QuerriedAAs.RequiredAAs.size() << "/" |
| 922 | << QuerriedAAs.OptionalAAs.size() |
| 923 | << " required/optional dependences\n"); |
| 924 | for (AbstractAttribute *DepOnInvalidAA : QuerriedAAs.RequiredAAs) { |
| 925 | AbstractState &DOIAAState = DepOnInvalidAA->getState(); |
| 926 | DOIAAState.indicatePessimisticFixpoint(); |
| 927 | ++NumAttributesFixedDueToRequiredDependences; |
| 928 | assert(DOIAAState.isAtFixpoint() && "Expected fixpoint state!"); |
| 929 | if (!DOIAAState.isValidState()) |
| 930 | InvalidAAs.insert(DepOnInvalidAA); |
| Johannes Doerfert | 2240854 | 2020-01-28 09:38:07 -0600 | [diff] [blame] | 931 | else |
| 932 | ChangedAAs.push_back(DepOnInvalidAA); |
| Johannes Doerfert | 680f638 | 2019-11-02 02:48:05 -0500 | [diff] [blame] | 933 | } |
| 934 | if (!RecomputeDependences) |
| 935 | Worklist.insert(QuerriedAAs.OptionalAAs.begin(), |
| 936 | QuerriedAAs.OptionalAAs.end()); |
| 937 | } |
| 938 | |
| Johannes Doerfert | f7ca0fe | 2019-08-28 16:58:52 +0000 | [diff] [blame] | 939 | // If dependences (=QueryMap) are recomputed we have to look at all abstract |
| 940 | // attributes again, regardless of what changed in the last iteration. |
| 941 | if (RecomputeDependences) { |
| 942 | LLVM_DEBUG( |
| 943 | dbgs() << "[Attributor] Run all AAs to recompute dependences\n"); |
| 944 | QueryMap.clear(); |
| 945 | ChangedAAs.clear(); |
| 946 | Worklist.insert(AllAbstractAttributes.begin(), |
| 947 | AllAbstractAttributes.end()); |
| 948 | } |
| 949 | |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 950 | // Add all abstract attributes that are potentially dependent on one that |
| 951 | // changed to the work list. |
| 952 | for (AbstractAttribute *ChangedAA : ChangedAAs) { |
| 953 | auto &QuerriedAAs = QueryMap[ChangedAA]; |
| Johannes Doerfert | 680f638 | 2019-11-02 02:48:05 -0500 | [diff] [blame] | 954 | Worklist.insert(QuerriedAAs.OptionalAAs.begin(), |
| 955 | QuerriedAAs.OptionalAAs.end()); |
| 956 | Worklist.insert(QuerriedAAs.RequiredAAs.begin(), |
| 957 | QuerriedAAs.RequiredAAs.end()); |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 958 | } |
| 959 | |
| Johannes Doerfert | b504eb8 | 2019-08-26 18:55:47 +0000 | [diff] [blame] | 960 | LLVM_DEBUG(dbgs() << "[Attributor] #Iteration: " << IterationCounter |
| 961 | << ", Worklist+Dependent size: " << Worklist.size() |
| 962 | << "\n"); |
| 963 | |
| Johannes Doerfert | 680f638 | 2019-11-02 02:48:05 -0500 | [diff] [blame] | 964 | // Reset the changed and invalid set. |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 965 | ChangedAAs.clear(); |
| Johannes Doerfert | 680f638 | 2019-11-02 02:48:05 -0500 | [diff] [blame] | 966 | InvalidAAs.clear(); |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 967 | |
| 968 | // Update all abstract attribute in the work list and record the ones that |
| 969 | // changed. |
| 970 | for (AbstractAttribute *AA : Worklist) |
| Johannes Doerfert | 23f41f1 | 2020-01-12 01:09:22 -0600 | [diff] [blame] | 971 | if (!AA->getState().isAtFixpoint() && |
| 972 | !isAssumedDead(*AA, nullptr, /* CheckBBLivenessOnly */ true)) { |
| Johannes Doerfert | 2dad729 | 2019-10-13 21:10:31 -0500 | [diff] [blame] | 973 | QueriedNonFixAA = false; |
| 974 | if (AA->update(*this) == ChangeStatus::CHANGED) { |
| Johannes Doerfert | 9a1a1f9 | 2019-08-14 21:25:08 +0000 | [diff] [blame] | 975 | ChangedAAs.push_back(AA); |
| Johannes Doerfert | 680f638 | 2019-11-02 02:48:05 -0500 | [diff] [blame] | 976 | if (!AA->getState().isValidState()) |
| 977 | InvalidAAs.insert(AA); |
| Johannes Doerfert | 2dad729 | 2019-10-13 21:10:31 -0500 | [diff] [blame] | 978 | } else if (!QueriedNonFixAA) { |
| 979 | // If the attribute did not query any non-fix information, the state |
| 980 | // will not change and we can indicate that right away. |
| 981 | AA->getState().indicateOptimisticFixpoint(); |
| 982 | } |
| 983 | } |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 984 | |
| Johannes Doerfert | f7ca0fe | 2019-08-28 16:58:52 +0000 | [diff] [blame] | 985 | // Check if we recompute the dependences in the next iteration. |
| 986 | RecomputeDependences = (DepRecomputeInterval > 0 && |
| 987 | IterationCounter % DepRecomputeInterval == 0); |
| 988 | |
| Johannes Doerfert | 9543f14 | 2019-08-23 15:24:57 +0000 | [diff] [blame] | 989 | // Add attributes to the changed set if they have been created in the last |
| 990 | // iteration. |
| 991 | ChangedAAs.append(AllAbstractAttributes.begin() + NumAAs, |
| 992 | AllAbstractAttributes.end()); |
| 993 | |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 994 | // Reset the work list and repopulate with the changed abstract attributes. |
| 995 | // Note that dependent ones are added above. |
| 996 | Worklist.clear(); |
| 997 | Worklist.insert(ChangedAAs.begin(), ChangedAAs.end()); |
| 998 | |
| Johannes Doerfert | bf11213 | 2019-08-29 01:29:44 +0000 | [diff] [blame] | 999 | } while (!Worklist.empty() && (IterationCounter++ < MaxFixpointIterations || |
| 1000 | VerifyMaxFixpointIterations)); |
| Johannes Doerfert | f7ca0fe | 2019-08-28 16:58:52 +0000 | [diff] [blame] | 1001 | |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 1002 | LLVM_DEBUG(dbgs() << "\n[Attributor] Fixpoint iteration done after: " |
| 1003 | << IterationCounter << "/" << MaxFixpointIterations |
| 1004 | << " iterations\n"); |
| 1005 | |
| Johannes Doerfert | bf11213 | 2019-08-29 01:29:44 +0000 | [diff] [blame] | 1006 | size_t NumFinalAAs = AllAbstractAttributes.size(); |
| Johannes Doerfert | b504eb8 | 2019-08-26 18:55:47 +0000 | [diff] [blame] | 1007 | |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 1008 | // Reset abstract arguments not settled in a sound fixpoint by now. This |
| 1009 | // happens when we stopped the fixpoint iteration early. Note that only the |
| 1010 | // ones marked as "changed" *and* the ones transitively depending on them |
| 1011 | // need to be reverted to a pessimistic state. Others might not be in a |
| 1012 | // fixpoint state but we can use the optimistic results for them anyway. |
| 1013 | SmallPtrSet<AbstractAttribute *, 32> Visited; |
| 1014 | for (unsigned u = 0; u < ChangedAAs.size(); u++) { |
| 1015 | AbstractAttribute *ChangedAA = ChangedAAs[u]; |
| 1016 | if (!Visited.insert(ChangedAA).second) |
| 1017 | continue; |
| 1018 | |
| 1019 | AbstractState &State = ChangedAA->getState(); |
| 1020 | if (!State.isAtFixpoint()) { |
| 1021 | State.indicatePessimisticFixpoint(); |
| 1022 | |
| 1023 | NumAttributesTimedOut++; |
| 1024 | } |
| 1025 | |
| 1026 | auto &QuerriedAAs = QueryMap[ChangedAA]; |
| Johannes Doerfert | 680f638 | 2019-11-02 02:48:05 -0500 | [diff] [blame] | 1027 | ChangedAAs.append(QuerriedAAs.OptionalAAs.begin(), |
| 1028 | QuerriedAAs.OptionalAAs.end()); |
| 1029 | ChangedAAs.append(QuerriedAAs.RequiredAAs.begin(), |
| 1030 | QuerriedAAs.RequiredAAs.end()); |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 1031 | } |
| 1032 | |
| 1033 | LLVM_DEBUG({ |
| 1034 | if (!Visited.empty()) |
| 1035 | dbgs() << "\n[Attributor] Finalized " << Visited.size() |
| 1036 | << " abstract attributes.\n"; |
| 1037 | }); |
| 1038 | |
| 1039 | unsigned NumManifested = 0; |
| 1040 | unsigned NumAtFixpoint = 0; |
| 1041 | ChangeStatus ManifestChange = ChangeStatus::UNCHANGED; |
| 1042 | for (AbstractAttribute *AA : AllAbstractAttributes) { |
| 1043 | AbstractState &State = AA->getState(); |
| 1044 | |
| 1045 | // If there is not already a fixpoint reached, we can now take the |
| 1046 | // optimistic state. This is correct because we enforced a pessimistic one |
| 1047 | // on abstract attributes that were transitively dependent on a changed one |
| 1048 | // already above. |
| 1049 | if (!State.isAtFixpoint()) |
| 1050 | State.indicateOptimisticFixpoint(); |
| 1051 | |
| 1052 | // If the state is invalid, we do not try to manifest it. |
| 1053 | if (!State.isValidState()) |
| 1054 | continue; |
| 1055 | |
| Johannes Doerfert | 9a1a1f9 | 2019-08-14 21:25:08 +0000 | [diff] [blame] | 1056 | // Skip dead code. |
| Johannes Doerfert | 23f41f1 | 2020-01-12 01:09:22 -0600 | [diff] [blame] | 1057 | if (isAssumedDead(*AA, nullptr, /* CheckBBLivenessOnly */ true)) |
| Johannes Doerfert | 9a1a1f9 | 2019-08-14 21:25:08 +0000 | [diff] [blame] | 1058 | continue; |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 1059 | // Manifest the state and record if we changed the IR. |
| 1060 | ChangeStatus LocalChange = AA->manifest(*this); |
| Johannes Doerfert | d1b79e0 | 2019-08-07 22:46:11 +0000 | [diff] [blame] | 1061 | if (LocalChange == ChangeStatus::CHANGED && AreStatisticsEnabled()) |
| 1062 | AA->trackStatistics(); |
| Johannes Doerfert | 8e76fec | 2020-02-16 17:37:50 -0600 | [diff] [blame] | 1063 | LLVM_DEBUG(dbgs() << "[Attributor] Manifest " << LocalChange << " : " << *AA |
| 1064 | << "\n"); |
| Johannes Doerfert | d1b79e0 | 2019-08-07 22:46:11 +0000 | [diff] [blame] | 1065 | |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 1066 | ManifestChange = ManifestChange | LocalChange; |
| 1067 | |
| 1068 | NumAtFixpoint++; |
| 1069 | NumManifested += (LocalChange == ChangeStatus::CHANGED); |
| 1070 | } |
| 1071 | |
| 1072 | (void)NumManifested; |
| 1073 | (void)NumAtFixpoint; |
| 1074 | LLVM_DEBUG(dbgs() << "\n[Attributor] Manifested " << NumManifested |
| 1075 | << " arguments while " << NumAtFixpoint |
| 1076 | << " were in a valid fixpoint state\n"); |
| 1077 | |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 1078 | NumAttributesManifested += NumManifested; |
| 1079 | NumAttributesValidFixpoint += NumAtFixpoint; |
| 1080 | |
| Fangrui Song | f182617 | 2019-08-20 07:21:43 +0000 | [diff] [blame] | 1081 | (void)NumFinalAAs; |
| Johannes Doerfert | b70297a | 2020-02-14 10:34:31 -0600 | [diff] [blame] | 1082 | if (NumFinalAAs != AllAbstractAttributes.size()) { |
| 1083 | for (unsigned u = NumFinalAAs; u < AllAbstractAttributes.size(); ++u) |
| 1084 | errs() << "Unexpected abstract attribute: " << *AllAbstractAttributes[u] |
| 1085 | << " :: " |
| 1086 | << AllAbstractAttributes[u]->getIRPosition().getAssociatedValue() |
| 1087 | << "\n"; |
| 1088 | llvm_unreachable("Expected the final number of abstract attributes to " |
| 1089 | "remain unchanged!"); |
| 1090 | } |
| Johannes Doerfert | 39681e7 | 2019-08-27 04:57:54 +0000 | [diff] [blame] | 1091 | |
| 1092 | // Delete stuff at the end to avoid invalid references and a nice order. |
| Johannes Doerfert | 2f62206 | 2019-09-04 16:35:20 +0000 | [diff] [blame] | 1093 | { |
| 1094 | LLVM_DEBUG(dbgs() << "\n[Attributor] Delete at least " |
| 1095 | << ToBeDeletedFunctions.size() << " functions and " |
| 1096 | << ToBeDeletedBlocks.size() << " blocks and " |
| Johannes Doerfert | cd4aab4 | 2019-10-13 03:08:18 -0500 | [diff] [blame] | 1097 | << ToBeDeletedInsts.size() << " instructions and " |
| 1098 | << ToBeChangedUses.size() << " uses\n"); |
| 1099 | |
| Alina Sbirlea | 9e66c4e | 2020-01-23 14:21:08 -0800 | [diff] [blame] | 1100 | SmallVector<WeakTrackingVH, 32> DeadInsts; |
| Johannes Doerfert | cd4aab4 | 2019-10-13 03:08:18 -0500 | [diff] [blame] | 1101 | SmallVector<Instruction *, 32> TerminatorsToFold; |
| Johannes Doerfert | cd4aab4 | 2019-10-13 03:08:18 -0500 | [diff] [blame] | 1102 | |
| 1103 | for (auto &It : ToBeChangedUses) { |
| 1104 | Use *U = It.first; |
| 1105 | Value *NewV = It.second; |
| 1106 | Value *OldV = U->get(); |
| Johannes Doerfert | 54ec9b5 | 2020-03-16 20:23:27 -0500 | [diff] [blame] | 1107 | |
| 1108 | // Do not replace uses in returns if the value is a must-tail call we will |
| 1109 | // not delete. |
| 1110 | if (isa<ReturnInst>(U->getUser())) |
| 1111 | if (auto *CI = dyn_cast<CallInst>(OldV->stripPointerCasts())) |
| 1112 | if (CI->isMustTailCall() && !ToBeDeletedInsts.count(CI)) |
| 1113 | continue; |
| 1114 | |
| Johannes Doerfert | cd4aab4 | 2019-10-13 03:08:18 -0500 | [diff] [blame] | 1115 | LLVM_DEBUG(dbgs() << "Use " << *NewV << " in " << *U->getUser() |
| 1116 | << " instead of " << *OldV << "\n"); |
| 1117 | U->set(NewV); |
| Johannes Doerfert | 137c99a | 2020-02-14 20:06:34 -0600 | [diff] [blame] | 1118 | // Do not modify call instructions outside the SCC. |
| 1119 | if (auto *CB = dyn_cast<CallBase>(OldV)) |
| 1120 | if (!Functions.count(CB->getCaller())) |
| 1121 | continue; |
| Johannes Doerfert | b0c77c3 | 2019-11-27 00:30:12 -0600 | [diff] [blame] | 1122 | if (Instruction *I = dyn_cast<Instruction>(OldV)) { |
| 1123 | CGModifiedFunctions.insert(I->getFunction()); |
| Stefan Stipanovic | f35740d | 2019-11-02 16:35:38 +0100 | [diff] [blame] | 1124 | if (!isa<PHINode>(I) && !ToBeDeletedInsts.count(I) && |
| Johannes Doerfert | b0c77c3 | 2019-11-27 00:30:12 -0600 | [diff] [blame] | 1125 | isInstructionTriviallyDead(I)) |
| Johannes Doerfert | cd4aab4 | 2019-10-13 03:08:18 -0500 | [diff] [blame] | 1126 | DeadInsts.push_back(I); |
| Johannes Doerfert | b0c77c3 | 2019-11-27 00:30:12 -0600 | [diff] [blame] | 1127 | } |
| Johannes Doerfert | cd4aab4 | 2019-10-13 03:08:18 -0500 | [diff] [blame] | 1128 | if (isa<Constant>(NewV) && isa<BranchInst>(U->getUser())) { |
| 1129 | Instruction *UserI = cast<Instruction>(U->getUser()); |
| 1130 | if (isa<UndefValue>(NewV)) { |
| Hideto Ueno | cb5eb13 | 2019-12-27 02:39:37 +0900 | [diff] [blame] | 1131 | ToBeChangedToUnreachableInsts.insert(UserI); |
| Johannes Doerfert | cd4aab4 | 2019-10-13 03:08:18 -0500 | [diff] [blame] | 1132 | } else { |
| 1133 | TerminatorsToFold.push_back(UserI); |
| 1134 | } |
| 1135 | } |
| Johannes Doerfert | 2f62206 | 2019-09-04 16:35:20 +0000 | [diff] [blame] | 1136 | } |
| Johannes Doerfert | a4088c7 | 2020-01-07 16:01:57 -0600 | [diff] [blame] | 1137 | for (auto &V : InvokeWithDeadSuccessor) |
| 1138 | if (InvokeInst *II = dyn_cast_or_null<InvokeInst>(V)) { |
| 1139 | bool UnwindBBIsDead = II->hasFnAttr(Attribute::NoUnwind); |
| 1140 | bool NormalBBIsDead = II->hasFnAttr(Attribute::NoReturn); |
| 1141 | bool Invoke2CallAllowed = |
| Johannes Doerfert | 0985554 | 2020-04-08 17:24:24 -0500 | [diff] [blame] | 1142 | !AAIsDead::mayCatchAsynchronousExceptions(*II->getFunction()); |
| Johannes Doerfert | a4088c7 | 2020-01-07 16:01:57 -0600 | [diff] [blame] | 1143 | assert((UnwindBBIsDead || NormalBBIsDead) && |
| 1144 | "Invoke does not have dead successors!"); |
| 1145 | BasicBlock *BB = II->getParent(); |
| 1146 | BasicBlock *NormalDestBB = II->getNormalDest(); |
| 1147 | if (UnwindBBIsDead) { |
| 1148 | Instruction *NormalNextIP = &NormalDestBB->front(); |
| 1149 | if (Invoke2CallAllowed) { |
| 1150 | changeToCall(II); |
| 1151 | NormalNextIP = BB->getTerminator(); |
| 1152 | } |
| 1153 | if (NormalBBIsDead) |
| 1154 | ToBeChangedToUnreachableInsts.insert(NormalNextIP); |
| 1155 | } else { |
| 1156 | assert(NormalBBIsDead && "Broken invariant!"); |
| 1157 | if (!NormalDestBB->getUniquePredecessor()) |
| 1158 | NormalDestBB = SplitBlockPredecessors(NormalDestBB, {BB}, ".dead"); |
| 1159 | ToBeChangedToUnreachableInsts.insert(&NormalDestBB->front()); |
| 1160 | } |
| 1161 | } |
| Stefanos Baziotis | 01c48d7d | 2020-03-07 12:38:44 +0200 | [diff] [blame] | 1162 | for (Instruction *I : TerminatorsToFold) { |
| 1163 | CGModifiedFunctions.insert(I->getFunction()); |
| 1164 | ConstantFoldTerminator(I->getParent()); |
| 1165 | } |
| Johannes Doerfert | 1e46eb7 | 2020-01-07 15:10:30 -0600 | [diff] [blame] | 1166 | for (auto &V : ToBeChangedToUnreachableInsts) |
| Johannes Doerfert | b0c77c3 | 2019-11-27 00:30:12 -0600 | [diff] [blame] | 1167 | if (Instruction *I = dyn_cast_or_null<Instruction>(V)) { |
| 1168 | CGModifiedFunctions.insert(I->getFunction()); |
| Johannes Doerfert | 1e46eb7 | 2020-01-07 15:10:30 -0600 | [diff] [blame] | 1169 | changeToUnreachable(I, /* UseLLVMTrap */ false); |
| Johannes Doerfert | b0c77c3 | 2019-11-27 00:30:12 -0600 | [diff] [blame] | 1170 | } |
| Johannes Doerfert | cd4aab4 | 2019-10-13 03:08:18 -0500 | [diff] [blame] | 1171 | |
| Johannes Doerfert | 5429c82 | 2020-01-11 23:30:36 -0600 | [diff] [blame] | 1172 | for (auto &V : ToBeDeletedInsts) { |
| 1173 | if (Instruction *I = dyn_cast_or_null<Instruction>(V)) { |
| Johannes Doerfert | b0c77c3 | 2019-11-27 00:30:12 -0600 | [diff] [blame] | 1174 | CGModifiedFunctions.insert(I->getFunction()); |
| Johannes Doerfert | b4352e4 | 2020-02-13 20:10:59 -0600 | [diff] [blame] | 1175 | if (!I->getType()->isVoidTy()) |
| 1176 | I->replaceAllUsesWith(UndefValue::get(I->getType())); |
| Johannes Doerfert | 5429c82 | 2020-01-11 23:30:36 -0600 | [diff] [blame] | 1177 | if (!isa<PHINode>(I) && isInstructionTriviallyDead(I)) |
| 1178 | DeadInsts.push_back(I); |
| 1179 | else |
| 1180 | I->eraseFromParent(); |
| 1181 | } |
| Johannes Doerfert | cd4aab4 | 2019-10-13 03:08:18 -0500 | [diff] [blame] | 1182 | } |
| 1183 | |
| 1184 | RecursivelyDeleteTriviallyDeadInstructions(DeadInsts); |
| Johannes Doerfert | b19cd27 | 2019-09-03 20:42:16 +0000 | [diff] [blame] | 1185 | |
| Johannes Doerfert | 2f62206 | 2019-09-04 16:35:20 +0000 | [diff] [blame] | 1186 | if (unsigned NumDeadBlocks = ToBeDeletedBlocks.size()) { |
| 1187 | SmallVector<BasicBlock *, 8> ToBeDeletedBBs; |
| 1188 | ToBeDeletedBBs.reserve(NumDeadBlocks); |
| Johannes Doerfert | b0c77c3 | 2019-11-27 00:30:12 -0600 | [diff] [blame] | 1189 | for (BasicBlock *BB : ToBeDeletedBlocks) { |
| 1190 | CGModifiedFunctions.insert(BB->getParent()); |
| 1191 | ToBeDeletedBBs.push_back(BB); |
| 1192 | } |
| Johannes Doerfert | 5e442a5 | 2019-10-30 17:34:59 -0500 | [diff] [blame] | 1193 | // Actually we do not delete the blocks but squash them into a single |
| 1194 | // unreachable but untangling branches that jump here is something we need |
| 1195 | // to do in a more generic way. |
| 1196 | DetatchDeadBlocks(ToBeDeletedBBs, nullptr); |
| Johannes Doerfert | 2f62206 | 2019-09-04 16:35:20 +0000 | [diff] [blame] | 1197 | } |
| Johannes Doerfert | b19cd27 | 2019-09-03 20:42:16 +0000 | [diff] [blame] | 1198 | |
| Johannes Doerfert | 2f62206 | 2019-09-04 16:35:20 +0000 | [diff] [blame] | 1199 | // Identify dead internal functions and delete them. This happens outside |
| 1200 | // the other fixpoint analysis as we might treat potentially dead functions |
| 1201 | // as live to lower the number of iterations. If they happen to be dead, the |
| 1202 | // below fixpoint loop will identify and eliminate them. |
| 1203 | SmallVector<Function *, 8> InternalFns; |
| Johannes Doerfert | b0c77c3 | 2019-11-27 00:30:12 -0600 | [diff] [blame] | 1204 | for (Function *F : Functions) |
| 1205 | if (F->hasLocalLinkage()) |
| 1206 | InternalFns.push_back(F); |
| Johannes Doerfert | 2f62206 | 2019-09-04 16:35:20 +0000 | [diff] [blame] | 1207 | |
| 1208 | bool FoundDeadFn = true; |
| 1209 | while (FoundDeadFn) { |
| 1210 | FoundDeadFn = false; |
| 1211 | for (unsigned u = 0, e = InternalFns.size(); u < e; ++u) { |
| 1212 | Function *F = InternalFns[u]; |
| 1213 | if (!F) |
| 1214 | continue; |
| 1215 | |
| Johannes Doerfert | 368f7ee | 2019-12-30 16:12:36 -0600 | [diff] [blame] | 1216 | bool AllCallSitesKnown; |
| Johannes Doerfert | 6b9ee2d | 2020-01-02 16:53:37 -0600 | [diff] [blame] | 1217 | if (!checkForAllCallSites( |
| 1218 | [this](AbstractCallSite ACS) { |
| 1219 | return ToBeDeletedFunctions.count( |
| 1220 | ACS.getInstruction()->getFunction()); |
| 1221 | }, |
| Johannes Doerfert | 368f7ee | 2019-12-30 16:12:36 -0600 | [diff] [blame] | 1222 | *F, true, nullptr, AllCallSitesKnown)) |
| Johannes Doerfert | 2f62206 | 2019-09-04 16:35:20 +0000 | [diff] [blame] | 1223 | continue; |
| 1224 | |
| Johannes Doerfert | cd4aab4 | 2019-10-13 03:08:18 -0500 | [diff] [blame] | 1225 | ToBeDeletedFunctions.insert(F); |
| Johannes Doerfert | 2f62206 | 2019-09-04 16:35:20 +0000 | [diff] [blame] | 1226 | InternalFns[u] = nullptr; |
| 1227 | FoundDeadFn = true; |
| 1228 | } |
| 1229 | } |
| Johannes Doerfert | 39681e7 | 2019-08-27 04:57:54 +0000 | [diff] [blame] | 1230 | } |
| 1231 | |
| Johannes Doerfert | b0c77c3 | 2019-11-27 00:30:12 -0600 | [diff] [blame] | 1232 | // Rewrite the functions as requested during manifest. |
| 1233 | ManifestChange = |
| 1234 | ManifestChange | rewriteFunctionSignatures(CGModifiedFunctions); |
| 1235 | |
| 1236 | for (Function *Fn : CGModifiedFunctions) |
| 1237 | CGUpdater.reanalyzeFunction(*Fn); |
| 1238 | |
| Johannes Doerfert | b0c77c3 | 2019-11-27 00:30:12 -0600 | [diff] [blame] | 1239 | for (Function *Fn : ToBeDeletedFunctions) |
| 1240 | CGUpdater.removeFunction(*Fn); |
| Johannes Doerfert | 6b9ee2d | 2020-01-02 16:53:37 -0600 | [diff] [blame] | 1241 | |
| Johannes Doerfert | 0985554 | 2020-04-08 17:24:24 -0500 | [diff] [blame] | 1242 | NumFnDeleted += ToBeDeletedFunctions.size(); |
| 1243 | |
| Johannes Doerfert | bf11213 | 2019-08-29 01:29:44 +0000 | [diff] [blame] | 1244 | if (VerifyMaxFixpointIterations && |
| 1245 | IterationCounter != MaxFixpointIterations) { |
| 1246 | errs() << "\n[Attributor] Fixpoint iteration done after: " |
| 1247 | << IterationCounter << "/" << MaxFixpointIterations |
| 1248 | << " iterations\n"; |
| 1249 | llvm_unreachable("The fixpoint was not reached with exactly the number of " |
| 1250 | "specified iterations!"); |
| 1251 | } |
| 1252 | |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 1253 | return ManifestChange; |
| 1254 | } |
| 1255 | |
| Luofan Chen | eec6d87 | 2020-04-04 11:32:36 -0500 | [diff] [blame] | 1256 | /// Create a shallow wrapper for \p F such that \p F has internal linkage |
| 1257 | /// afterwards. It also sets the original \p F 's name to anonymous |
| 1258 | /// |
| 1259 | /// A wrapper is a function with the same type (and attributes) as \p F |
| 1260 | /// that will only call \p F and return the result, if any. |
| 1261 | /// |
| 1262 | /// Assuming the declaration of looks like: |
| 1263 | /// rty F(aty0 arg0, ..., atyN argN); |
| 1264 | /// |
| 1265 | /// The wrapper will then look as follows: |
| 1266 | /// rty wrapper(aty0 arg0, ..., atyN argN) { |
| 1267 | /// return F(arg0, ..., argN); |
| 1268 | /// } |
| 1269 | /// |
| 1270 | static void createShallowWrapper(Function &F) { |
| 1271 | assert(AllowShallowWrappers && |
| 1272 | "Cannot create a wrapper if it is not allowed!"); |
| 1273 | assert(!F.isDeclaration() && "Cannot create a wrapper around a declaration!"); |
| 1274 | |
| 1275 | Module &M = *F.getParent(); |
| 1276 | LLVMContext &Ctx = M.getContext(); |
| 1277 | FunctionType *FnTy = F.getFunctionType(); |
| 1278 | |
| 1279 | Function *Wrapper = |
| 1280 | Function::Create(FnTy, F.getLinkage(), F.getAddressSpace(), F.getName()); |
| 1281 | F.setName(""); // set the inside function anonymous |
| 1282 | M.getFunctionList().insert(F.getIterator(), Wrapper); |
| 1283 | |
| 1284 | F.setLinkage(GlobalValue::InternalLinkage); |
| 1285 | |
| 1286 | F.replaceAllUsesWith(Wrapper); |
| 1287 | assert(F.getNumUses() == 0 && "Uses remained after wrapper was created!"); |
| 1288 | |
| 1289 | // Move the COMDAT section to the wrapper. |
| 1290 | // TODO: Check if we need to keep it for F as well. |
| 1291 | Wrapper->setComdat(F.getComdat()); |
| 1292 | F.setComdat(nullptr); |
| 1293 | |
| 1294 | // Copy all metadata and attributes but keep them on F as well. |
| 1295 | SmallVector<std::pair<unsigned, MDNode *>, 1> MDs; |
| 1296 | F.getAllMetadata(MDs); |
| 1297 | for (auto MDIt : MDs) |
| 1298 | Wrapper->addMetadata(MDIt.first, *MDIt.second); |
| 1299 | Wrapper->setAttributes(F.getAttributes()); |
| 1300 | |
| 1301 | // Create the call in the wrapper. |
| 1302 | BasicBlock *EntryBB = BasicBlock::Create(Ctx, "entry", Wrapper); |
| 1303 | |
| 1304 | SmallVector<Value *, 8> Args; |
| 1305 | auto FArgIt = F.arg_begin(); |
| 1306 | for (Argument &Arg : Wrapper->args()) { |
| 1307 | Args.push_back(&Arg); |
| 1308 | Arg.setName((FArgIt++)->getName()); |
| 1309 | } |
| 1310 | |
| 1311 | CallInst *CI = CallInst::Create(&F, Args, "", EntryBB); |
| 1312 | CI->setTailCall(true); |
| 1313 | CI->addAttribute(AttributeList::FunctionIndex, Attribute::NoInline); |
| 1314 | ReturnInst::Create(Ctx, CI->getType()->isVoidTy() ? nullptr : CI, EntryBB); |
| 1315 | |
| 1316 | NumFnShallowWrapperCreated++; |
| 1317 | } |
| 1318 | |
| Johannes Doerfert | 89c2e73 | 2019-10-30 17:20:20 -0500 | [diff] [blame] | 1319 | bool Attributor::isValidFunctionSignatureRewrite( |
| 1320 | Argument &Arg, ArrayRef<Type *> ReplacementTypes) { |
| Johannes Doerfert | 7513363 | 2019-10-10 01:39:16 -0500 | [diff] [blame] | 1321 | |
| 1322 | auto CallSiteCanBeChanged = [](AbstractCallSite ACS) { |
| 1323 | // Forbid must-tail calls for now. |
| 1324 | return !ACS.isCallbackCall() && !ACS.getCallSite().isMustTailCall(); |
| 1325 | }; |
| 1326 | |
| 1327 | Function *Fn = Arg.getParent(); |
| 1328 | // Avoid var-arg functions for now. |
| 1329 | if (Fn->isVarArg()) { |
| 1330 | LLVM_DEBUG(dbgs() << "[Attributor] Cannot rewrite var-args functions\n"); |
| 1331 | return false; |
| 1332 | } |
| 1333 | |
| 1334 | // Avoid functions with complicated argument passing semantics. |
| 1335 | AttributeList FnAttributeList = Fn->getAttributes(); |
| 1336 | if (FnAttributeList.hasAttrSomewhere(Attribute::Nest) || |
| 1337 | FnAttributeList.hasAttrSomewhere(Attribute::StructRet) || |
| 1338 | FnAttributeList.hasAttrSomewhere(Attribute::InAlloca)) { |
| 1339 | LLVM_DEBUG( |
| 1340 | dbgs() << "[Attributor] Cannot rewrite due to complex attribute\n"); |
| 1341 | return false; |
| 1342 | } |
| 1343 | |
| 1344 | // Avoid callbacks for now. |
| Johannes Doerfert | 368f7ee | 2019-12-30 16:12:36 -0600 | [diff] [blame] | 1345 | bool AllCallSitesKnown; |
| 1346 | if (!checkForAllCallSites(CallSiteCanBeChanged, *Fn, true, nullptr, |
| 1347 | AllCallSitesKnown)) { |
| Johannes Doerfert | 7513363 | 2019-10-10 01:39:16 -0500 | [diff] [blame] | 1348 | LLVM_DEBUG(dbgs() << "[Attributor] Cannot rewrite all call sites\n"); |
| 1349 | return false; |
| 1350 | } |
| 1351 | |
| 1352 | auto InstPred = [](Instruction &I) { |
| 1353 | if (auto *CI = dyn_cast<CallInst>(&I)) |
| 1354 | return !CI->isMustTailCall(); |
| 1355 | return true; |
| 1356 | }; |
| 1357 | |
| 1358 | // Forbid must-tail calls for now. |
| 1359 | // TODO: |
| Johannes Doerfert | 7513363 | 2019-10-10 01:39:16 -0500 | [diff] [blame] | 1360 | auto &OpcodeInstMap = InfoCache.getOpcodeInstMapForFunction(*Fn); |
| Johannes Doerfert | 23f41f1 | 2020-01-12 01:09:22 -0600 | [diff] [blame] | 1361 | if (!checkForAllInstructionsImpl(nullptr, OpcodeInstMap, InstPred, nullptr, |
| 1362 | nullptr, {Instruction::Call})) { |
| Johannes Doerfert | 7513363 | 2019-10-10 01:39:16 -0500 | [diff] [blame] | 1363 | LLVM_DEBUG(dbgs() << "[Attributor] Cannot rewrite due to instructions\n"); |
| 1364 | return false; |
| 1365 | } |
| 1366 | |
| Johannes Doerfert | 89c2e73 | 2019-10-30 17:20:20 -0500 | [diff] [blame] | 1367 | return true; |
| 1368 | } |
| 1369 | |
| 1370 | bool Attributor::registerFunctionSignatureRewrite( |
| 1371 | Argument &Arg, ArrayRef<Type *> ReplacementTypes, |
| 1372 | ArgumentReplacementInfo::CalleeRepairCBTy &&CalleeRepairCB, |
| 1373 | ArgumentReplacementInfo::ACSRepairCBTy &&ACSRepairCB) { |
| 1374 | LLVM_DEBUG(dbgs() << "[Attributor] Register new rewrite of " << Arg << " in " |
| 1375 | << Arg.getParent()->getName() << " with " |
| 1376 | << ReplacementTypes.size() << " replacements\n"); |
| 1377 | assert(isValidFunctionSignatureRewrite(Arg, ReplacementTypes) && |
| 1378 | "Cannot register an invalid rewrite"); |
| 1379 | |
| 1380 | Function *Fn = Arg.getParent(); |
| Johannes Doerfert | 7513363 | 2019-10-10 01:39:16 -0500 | [diff] [blame] | 1381 | SmallVectorImpl<ArgumentReplacementInfo *> &ARIs = ArgumentReplacementMap[Fn]; |
| Johannes Doerfert | 89c2e73 | 2019-10-30 17:20:20 -0500 | [diff] [blame] | 1382 | if (ARIs.empty()) |
| Johannes Doerfert | 7513363 | 2019-10-10 01:39:16 -0500 | [diff] [blame] | 1383 | ARIs.resize(Fn->arg_size()); |
| 1384 | |
| 1385 | // If we have a replacement already with less than or equal new arguments, |
| 1386 | // ignore this request. |
| 1387 | ArgumentReplacementInfo *&ARI = ARIs[Arg.getArgNo()]; |
| 1388 | if (ARI && ARI->getNumReplacementArgs() <= ReplacementTypes.size()) { |
| 1389 | LLVM_DEBUG(dbgs() << "[Attributor] Existing rewrite is preferred\n"); |
| 1390 | return false; |
| 1391 | } |
| 1392 | |
| 1393 | // If we have a replacement already but we like the new one better, delete |
| 1394 | // the old. |
| 1395 | if (ARI) |
| 1396 | delete ARI; |
| 1397 | |
| Johannes Doerfert | 89c2e73 | 2019-10-30 17:20:20 -0500 | [diff] [blame] | 1398 | LLVM_DEBUG(dbgs() << "[Attributor] Register new rewrite of " << Arg << " in " |
| 1399 | << Arg.getParent()->getName() << " with " |
| 1400 | << ReplacementTypes.size() << " replacements\n"); |
| 1401 | |
| Johannes Doerfert | 7513363 | 2019-10-10 01:39:16 -0500 | [diff] [blame] | 1402 | // Remember the replacement. |
| 1403 | ARI = new ArgumentReplacementInfo(*this, Arg, ReplacementTypes, |
| 1404 | std::move(CalleeRepairCB), |
| 1405 | std::move(ACSRepairCB)); |
| 1406 | |
| 1407 | return true; |
| 1408 | } |
| 1409 | |
| Johannes Doerfert | b0c77c3 | 2019-11-27 00:30:12 -0600 | [diff] [blame] | 1410 | ChangeStatus Attributor::rewriteFunctionSignatures( |
| 1411 | SmallPtrSetImpl<Function *> &ModifiedFns) { |
| Johannes Doerfert | 7513363 | 2019-10-10 01:39:16 -0500 | [diff] [blame] | 1412 | ChangeStatus Changed = ChangeStatus::UNCHANGED; |
| 1413 | |
| 1414 | for (auto &It : ArgumentReplacementMap) { |
| 1415 | Function *OldFn = It.getFirst(); |
| 1416 | |
| 1417 | // Deleted functions do not require rewrites. |
| 1418 | if (ToBeDeletedFunctions.count(OldFn)) |
| 1419 | continue; |
| 1420 | |
| 1421 | const SmallVectorImpl<ArgumentReplacementInfo *> &ARIs = It.getSecond(); |
| 1422 | assert(ARIs.size() == OldFn->arg_size() && "Inconsistent state!"); |
| 1423 | |
| 1424 | SmallVector<Type *, 16> NewArgumentTypes; |
| 1425 | SmallVector<AttributeSet, 16> NewArgumentAttributes; |
| 1426 | |
| 1427 | // Collect replacement argument types and copy over existing attributes. |
| 1428 | AttributeList OldFnAttributeList = OldFn->getAttributes(); |
| 1429 | for (Argument &Arg : OldFn->args()) { |
| 1430 | if (ArgumentReplacementInfo *ARI = ARIs[Arg.getArgNo()]) { |
| 1431 | NewArgumentTypes.append(ARI->ReplacementTypes.begin(), |
| 1432 | ARI->ReplacementTypes.end()); |
| 1433 | NewArgumentAttributes.append(ARI->getNumReplacementArgs(), |
| 1434 | AttributeSet()); |
| 1435 | } else { |
| 1436 | NewArgumentTypes.push_back(Arg.getType()); |
| 1437 | NewArgumentAttributes.push_back( |
| 1438 | OldFnAttributeList.getParamAttributes(Arg.getArgNo())); |
| 1439 | } |
| 1440 | } |
| 1441 | |
| 1442 | FunctionType *OldFnTy = OldFn->getFunctionType(); |
| 1443 | Type *RetTy = OldFnTy->getReturnType(); |
| 1444 | |
| 1445 | // Construct the new function type using the new arguments types. |
| 1446 | FunctionType *NewFnTy = |
| 1447 | FunctionType::get(RetTy, NewArgumentTypes, OldFnTy->isVarArg()); |
| 1448 | |
| 1449 | LLVM_DEBUG(dbgs() << "[Attributor] Function rewrite '" << OldFn->getName() |
| 1450 | << "' from " << *OldFn->getFunctionType() << " to " |
| 1451 | << *NewFnTy << "\n"); |
| 1452 | |
| 1453 | // Create the new function body and insert it into the module. |
| 1454 | Function *NewFn = Function::Create(NewFnTy, OldFn->getLinkage(), |
| 1455 | OldFn->getAddressSpace(), ""); |
| 1456 | OldFn->getParent()->getFunctionList().insert(OldFn->getIterator(), NewFn); |
| 1457 | NewFn->takeName(OldFn); |
| 1458 | NewFn->copyAttributesFrom(OldFn); |
| 1459 | |
| 1460 | // Patch the pointer to LLVM function in debug info descriptor. |
| 1461 | NewFn->setSubprogram(OldFn->getSubprogram()); |
| 1462 | OldFn->setSubprogram(nullptr); |
| 1463 | |
| 1464 | // Recompute the parameter attributes list based on the new arguments for |
| 1465 | // the function. |
| 1466 | LLVMContext &Ctx = OldFn->getContext(); |
| 1467 | NewFn->setAttributes(AttributeList::get( |
| 1468 | Ctx, OldFnAttributeList.getFnAttributes(), |
| 1469 | OldFnAttributeList.getRetAttributes(), NewArgumentAttributes)); |
| 1470 | |
| 1471 | // Since we have now created the new function, splice the body of the old |
| 1472 | // function right into the new function, leaving the old rotting hulk of the |
| 1473 | // function empty. |
| 1474 | NewFn->getBasicBlockList().splice(NewFn->begin(), |
| 1475 | OldFn->getBasicBlockList()); |
| 1476 | |
| Johannes Doerfert | d2d2fb1 | 2020-01-02 17:20:47 -0600 | [diff] [blame] | 1477 | // Set of all "call-like" instructions that invoke the old function mapped |
| 1478 | // to their new replacements. |
| 1479 | SmallVector<std::pair<CallBase *, CallBase *>, 8> CallSitePairs; |
| Johannes Doerfert | 7513363 | 2019-10-10 01:39:16 -0500 | [diff] [blame] | 1480 | |
| 1481 | // Callback to create a new "call-like" instruction for a given one. |
| 1482 | auto CallSiteReplacementCreator = [&](AbstractCallSite ACS) { |
| 1483 | CallBase *OldCB = cast<CallBase>(ACS.getInstruction()); |
| 1484 | const AttributeList &OldCallAttributeList = OldCB->getAttributes(); |
| 1485 | |
| 1486 | // Collect the new argument operands for the replacement call site. |
| 1487 | SmallVector<Value *, 16> NewArgOperands; |
| 1488 | SmallVector<AttributeSet, 16> NewArgOperandAttributes; |
| 1489 | for (unsigned OldArgNum = 0; OldArgNum < ARIs.size(); ++OldArgNum) { |
| 1490 | unsigned NewFirstArgNum = NewArgOperands.size(); |
| Ilya Biryukov | 4f82af8 | 2019-12-31 10:21:52 +0100 | [diff] [blame] | 1491 | (void)NewFirstArgNum; // only used inside assert. |
| Johannes Doerfert | 7513363 | 2019-10-10 01:39:16 -0500 | [diff] [blame] | 1492 | if (ArgumentReplacementInfo *ARI = ARIs[OldArgNum]) { |
| 1493 | if (ARI->ACSRepairCB) |
| 1494 | ARI->ACSRepairCB(*ARI, ACS, NewArgOperands); |
| 1495 | assert(ARI->getNumReplacementArgs() + NewFirstArgNum == |
| 1496 | NewArgOperands.size() && |
| 1497 | "ACS repair callback did not provide as many operand as new " |
| 1498 | "types were registered!"); |
| 1499 | // TODO: Exose the attribute set to the ACS repair callback |
| 1500 | NewArgOperandAttributes.append(ARI->ReplacementTypes.size(), |
| 1501 | AttributeSet()); |
| 1502 | } else { |
| 1503 | NewArgOperands.push_back(ACS.getCallArgOperand(OldArgNum)); |
| 1504 | NewArgOperandAttributes.push_back( |
| 1505 | OldCallAttributeList.getParamAttributes(OldArgNum)); |
| 1506 | } |
| 1507 | } |
| 1508 | |
| 1509 | assert(NewArgOperands.size() == NewArgOperandAttributes.size() && |
| 1510 | "Mismatch # argument operands vs. # argument operand attributes!"); |
| 1511 | assert(NewArgOperands.size() == NewFn->arg_size() && |
| 1512 | "Mismatch # argument operands vs. # function arguments!"); |
| 1513 | |
| 1514 | SmallVector<OperandBundleDef, 4> OperandBundleDefs; |
| 1515 | OldCB->getOperandBundlesAsDefs(OperandBundleDefs); |
| 1516 | |
| 1517 | // Create a new call or invoke instruction to replace the old one. |
| 1518 | CallBase *NewCB; |
| 1519 | if (InvokeInst *II = dyn_cast<InvokeInst>(OldCB)) { |
| 1520 | NewCB = |
| 1521 | InvokeInst::Create(NewFn, II->getNormalDest(), II->getUnwindDest(), |
| 1522 | NewArgOperands, OperandBundleDefs, "", OldCB); |
| 1523 | } else { |
| 1524 | auto *NewCI = CallInst::Create(NewFn, NewArgOperands, OperandBundleDefs, |
| 1525 | "", OldCB); |
| 1526 | NewCI->setTailCallKind(cast<CallInst>(OldCB)->getTailCallKind()); |
| 1527 | NewCB = NewCI; |
| 1528 | } |
| 1529 | |
| 1530 | // Copy over various properties and the new attributes. |
| Johannes Doerfert | 7513363 | 2019-10-10 01:39:16 -0500 | [diff] [blame] | 1531 | uint64_t W; |
| 1532 | if (OldCB->extractProfTotalWeight(W)) |
| 1533 | NewCB->setProfWeight(W); |
| 1534 | NewCB->setCallingConv(OldCB->getCallingConv()); |
| 1535 | NewCB->setDebugLoc(OldCB->getDebugLoc()); |
| 1536 | NewCB->takeName(OldCB); |
| 1537 | NewCB->setAttributes(AttributeList::get( |
| 1538 | Ctx, OldCallAttributeList.getFnAttributes(), |
| 1539 | OldCallAttributeList.getRetAttributes(), NewArgOperandAttributes)); |
| 1540 | |
| Johannes Doerfert | d2d2fb1 | 2020-01-02 17:20:47 -0600 | [diff] [blame] | 1541 | CallSitePairs.push_back({OldCB, NewCB}); |
| Johannes Doerfert | 7513363 | 2019-10-10 01:39:16 -0500 | [diff] [blame] | 1542 | return true; |
| 1543 | }; |
| 1544 | |
| 1545 | // Use the CallSiteReplacementCreator to create replacement call sites. |
| Johannes Doerfert | 368f7ee | 2019-12-30 16:12:36 -0600 | [diff] [blame] | 1546 | bool AllCallSitesKnown; |
| 1547 | bool Success = checkForAllCallSites(CallSiteReplacementCreator, *OldFn, |
| 1548 | true, nullptr, AllCallSitesKnown); |
| Ilya Biryukov | 4f82af8 | 2019-12-31 10:21:52 +0100 | [diff] [blame] | 1549 | (void)Success; |
| Johannes Doerfert | 7513363 | 2019-10-10 01:39:16 -0500 | [diff] [blame] | 1550 | assert(Success && "Assumed call site replacement to succeed!"); |
| 1551 | |
| 1552 | // Rewire the arguments. |
| 1553 | auto OldFnArgIt = OldFn->arg_begin(); |
| 1554 | auto NewFnArgIt = NewFn->arg_begin(); |
| 1555 | for (unsigned OldArgNum = 0; OldArgNum < ARIs.size(); |
| 1556 | ++OldArgNum, ++OldFnArgIt) { |
| 1557 | if (ArgumentReplacementInfo *ARI = ARIs[OldArgNum]) { |
| 1558 | if (ARI->CalleeRepairCB) |
| 1559 | ARI->CalleeRepairCB(*ARI, *NewFn, NewFnArgIt); |
| 1560 | NewFnArgIt += ARI->ReplacementTypes.size(); |
| 1561 | } else { |
| 1562 | NewFnArgIt->takeName(&*OldFnArgIt); |
| 1563 | OldFnArgIt->replaceAllUsesWith(&*NewFnArgIt); |
| 1564 | ++NewFnArgIt; |
| 1565 | } |
| 1566 | } |
| 1567 | |
| 1568 | // Eliminate the instructions *after* we visited all of them. |
| Johannes Doerfert | d2d2fb1 | 2020-01-02 17:20:47 -0600 | [diff] [blame] | 1569 | for (auto &CallSitePair : CallSitePairs) { |
| 1570 | CallBase &OldCB = *CallSitePair.first; |
| 1571 | CallBase &NewCB = *CallSitePair.second; |
| Johannes Doerfert | b0c77c3 | 2019-11-27 00:30:12 -0600 | [diff] [blame] | 1572 | // We do not modify the call graph here but simply reanalyze the old |
| 1573 | // function. This should be revisited once the old PM is gone. |
| 1574 | ModifiedFns.insert(OldCB.getFunction()); |
| Johannes Doerfert | d2d2fb1 | 2020-01-02 17:20:47 -0600 | [diff] [blame] | 1575 | OldCB.replaceAllUsesWith(&NewCB); |
| 1576 | OldCB.eraseFromParent(); |
| 1577 | } |
| Johannes Doerfert | 7513363 | 2019-10-10 01:39:16 -0500 | [diff] [blame] | 1578 | |
| Johannes Doerfert | b0c77c3 | 2019-11-27 00:30:12 -0600 | [diff] [blame] | 1579 | // Replace the function in the call graph (if any). |
| 1580 | CGUpdater.replaceFunctionWith(*OldFn, *NewFn); |
| 1581 | |
| 1582 | // If the old function was modified and needed to be reanalyzed, the new one |
| 1583 | // does now. |
| 1584 | if (ModifiedFns.erase(OldFn)) |
| 1585 | ModifiedFns.insert(NewFn); |
| Johannes Doerfert | d2d2fb1 | 2020-01-02 17:20:47 -0600 | [diff] [blame] | 1586 | |
| Johannes Doerfert | 7513363 | 2019-10-10 01:39:16 -0500 | [diff] [blame] | 1587 | Changed = ChangeStatus::CHANGED; |
| 1588 | } |
| 1589 | |
| 1590 | return Changed; |
| 1591 | } |
| 1592 | |
| Johannes Doerfert | 3ab9e8b | 2019-09-17 10:52:41 +0000 | [diff] [blame] | 1593 | void Attributor::initializeInformationCache(Function &F) { |
| 1594 | |
| 1595 | // Walk all instructions to find interesting instructions that might be |
| 1596 | // queried by abstract attributes during their initialization or update. |
| 1597 | // This has to happen before we create attributes. |
| 1598 | auto &ReadOrWriteInsts = InfoCache.FuncRWInstsMap[&F]; |
| 1599 | auto &InstOpcodeMap = InfoCache.FuncInstOpcodeMap[&F]; |
| 1600 | |
| 1601 | for (Instruction &I : instructions(&F)) { |
| 1602 | bool IsInterestingOpcode = false; |
| 1603 | |
| 1604 | // To allow easy access to all instructions in a function with a given |
| 1605 | // opcode we store them in the InfoCache. As not all opcodes are interesting |
| 1606 | // to concrete attributes we only cache the ones that are as identified in |
| 1607 | // the following switch. |
| 1608 | // Note: There are no concrete attributes now so this is initially empty. |
| 1609 | switch (I.getOpcode()) { |
| 1610 | default: |
| 1611 | assert((!ImmutableCallSite(&I)) && (!isa<CallBase>(&I)) && |
| Stefanos Baziotis | a650d55 | 2020-03-23 22:44:10 +0200 | [diff] [blame] | 1612 | "New call site/base instruction type needs to be known in the " |
| Johannes Doerfert | 3ab9e8b | 2019-09-17 10:52:41 +0000 | [diff] [blame] | 1613 | "Attributor."); |
| 1614 | break; |
| Johannes Doerfert | 5699d08 | 2020-02-20 02:06:48 -0600 | [diff] [blame] | 1615 | case Instruction::Call: |
| Johannes Doerfert | b1c788d | 2020-04-01 21:07:41 -0500 | [diff] [blame] | 1616 | // Calls are interesting on their own, additionally: |
| 1617 | // For `llvm.assume` calls we also fill the KnowledgeMap as we find them. |
| 1618 | // For `must-tail` calls we remember the caller and callee. |
| Johannes Doerfert | 5699d08 | 2020-02-20 02:06:48 -0600 | [diff] [blame] | 1619 | if (IntrinsicInst *Assume = dyn_cast<IntrinsicInst>(&I)) { |
| 1620 | if (Assume->getIntrinsicID() == Intrinsic::assume) |
| 1621 | fillMapFromAssume(*Assume, InfoCache.KnowledgeMap); |
| Johannes Doerfert | b1c788d | 2020-04-01 21:07:41 -0500 | [diff] [blame] | 1622 | } else if (cast<CallInst>(I).isMustTailCall()) { |
| 1623 | InfoCache.FunctionsWithMustTailCall.insert(&F); |
| 1624 | InfoCache.FunctionsCalledViaMustTail.insert( |
| 1625 | cast<CallInst>(I).getCalledFunction()); |
| Johannes Doerfert | 5699d08 | 2020-02-20 02:06:48 -0600 | [diff] [blame] | 1626 | } |
| 1627 | LLVM_FALLTHROUGH; |
| Johannes Doerfert | 3ab9e8b | 2019-09-17 10:52:41 +0000 | [diff] [blame] | 1628 | case Instruction::CallBr: |
| 1629 | case Instruction::Invoke: |
| 1630 | case Instruction::CleanupRet: |
| 1631 | case Instruction::CatchSwitch: |
| Johannes Doerfert | 5732f56 | 2019-12-24 19:25:08 -0600 | [diff] [blame] | 1632 | case Instruction::AtomicRMW: |
| 1633 | case Instruction::AtomicCmpXchg: |
| Hideto Ueno | ef4febd | 2019-12-29 17:34:08 +0900 | [diff] [blame] | 1634 | case Instruction::Br: |
| Johannes Doerfert | 3ab9e8b | 2019-09-17 10:52:41 +0000 | [diff] [blame] | 1635 | case Instruction::Resume: |
| 1636 | case Instruction::Ret: |
| Johannes Doerfert | b1c788d | 2020-04-01 21:07:41 -0500 | [diff] [blame] | 1637 | case Instruction::Load: |
| 1638 | // The alignment of a pointer is interesting for loads. |
| 1639 | case Instruction::Store: |
| 1640 | // The alignment of a pointer is interesting for stores. |
| Johannes Doerfert | 3ab9e8b | 2019-09-17 10:52:41 +0000 | [diff] [blame] | 1641 | IsInterestingOpcode = true; |
| 1642 | } |
| 1643 | if (IsInterestingOpcode) |
| 1644 | InstOpcodeMap[I.getOpcode()].push_back(&I); |
| 1645 | if (I.mayReadOrWriteMemory()) |
| 1646 | ReadOrWriteInsts.push_back(&I); |
| 1647 | } |
| Johannes Doerfert | a198adb | 2020-03-13 00:32:38 -0500 | [diff] [blame] | 1648 | |
| 1649 | if (F.hasFnAttribute(Attribute::AlwaysInline) && |
| 1650 | isInlineViable(F).isSuccess()) |
| 1651 | InfoCache.InlineableFunctions.insert(&F); |
| Johannes Doerfert | 3ab9e8b | 2019-09-17 10:52:41 +0000 | [diff] [blame] | 1652 | } |
| 1653 | |
| Johannes Doerfert | 12173e6 | 2019-10-13 20:25:25 -0500 | [diff] [blame] | 1654 | void Attributor::recordDependence(const AbstractAttribute &FromAA, |
| Johannes Doerfert | 680f638 | 2019-11-02 02:48:05 -0500 | [diff] [blame] | 1655 | const AbstractAttribute &ToAA, |
| 1656 | DepClassTy DepClass) { |
| Johannes Doerfert | 2dad729 | 2019-10-13 21:10:31 -0500 | [diff] [blame] | 1657 | if (FromAA.getState().isAtFixpoint()) |
| 1658 | return; |
| 1659 | |
| Johannes Doerfert | 680f638 | 2019-11-02 02:48:05 -0500 | [diff] [blame] | 1660 | if (DepClass == DepClassTy::REQUIRED) |
| 1661 | QueryMap[&FromAA].RequiredAAs.insert( |
| 1662 | const_cast<AbstractAttribute *>(&ToAA)); |
| 1663 | else |
| 1664 | QueryMap[&FromAA].OptionalAAs.insert( |
| 1665 | const_cast<AbstractAttribute *>(&ToAA)); |
| Johannes Doerfert | 2dad729 | 2019-10-13 21:10:31 -0500 | [diff] [blame] | 1666 | QueriedNonFixAA = true; |
| Johannes Doerfert | 12173e6 | 2019-10-13 20:25:25 -0500 | [diff] [blame] | 1667 | } |
| 1668 | |
| Hideto Ueno | 3bb5cbc | 2019-09-17 05:45:18 +0000 | [diff] [blame] | 1669 | void Attributor::identifyDefaultAbstractAttributes(Function &F) { |
| Johannes Doerfert | 2f62206 | 2019-09-04 16:35:20 +0000 | [diff] [blame] | 1670 | if (!VisitedFunctions.insert(&F).second) |
| 1671 | return; |
| Johannes Doerfert | c36e2eb | 2019-10-31 20:15:02 -0500 | [diff] [blame] | 1672 | if (F.isDeclaration()) |
| 1673 | return; |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 1674 | |
| Johannes Doerfert | b1c788d | 2020-04-01 21:07:41 -0500 | [diff] [blame] | 1675 | // In non-module runs we need to look at the call sites of a function to |
| 1676 | // determine if it is part of a must-tail call edge. This will influence what |
| 1677 | // attributes we can derive. |
| 1678 | if (!isModulePass() && !InfoCache.FunctionsCalledViaMustTail.count(&F)) |
| 1679 | for (const Use &U : F.uses()) |
| 1680 | if (ImmutableCallSite ICS = ImmutableCallSite(U.getUser())) |
| 1681 | if (ICS.isCallee(&U) && ICS.isMustTailCall()) |
| 1682 | InfoCache.FunctionsCalledViaMustTail.insert(&F); |
| 1683 | |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 1684 | IRPosition FPos = IRPosition::function(F); |
| 1685 | |
| Johannes Doerfert | 305b961 | 2019-08-04 18:40:01 +0000 | [diff] [blame] | 1686 | // Check for dead BasicBlocks in every function. |
| Johannes Doerfert | 21fe0a3 | 2019-08-06 00:55:11 +0000 | [diff] [blame] | 1687 | // We need dead instruction detection because we do not want to deal with |
| 1688 | // broken IR in which SSA rules do not apply. |
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 1689 | getOrCreateAAFor<AAIsDead>(FPos); |
| Johannes Doerfert | 305b961 | 2019-08-04 18:40:01 +0000 | [diff] [blame] | 1690 | |
| 1691 | // Every function might be "will-return". |
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 1692 | getOrCreateAAFor<AAWillReturn>(FPos); |
| Johannes Doerfert | 305b961 | 2019-08-04 18:40:01 +0000 | [diff] [blame] | 1693 | |
| Johannes Doerfert | 58f324a | 2019-12-24 18:48:50 -0600 | [diff] [blame] | 1694 | // Every function might contain instructions that cause "undefined behavior". |
| 1695 | getOrCreateAAFor<AAUndefinedBehavior>(FPos); |
| 1696 | |
| Stefan Stipanovic | 5360589 | 2019-06-27 11:27:54 +0000 | [diff] [blame] | 1697 | // Every function can be nounwind. |
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 1698 | getOrCreateAAFor<AANoUnwind>(FPos); |
| Stefan Stipanovic | 5360589 | 2019-06-27 11:27:54 +0000 | [diff] [blame] | 1699 | |
| Stefan Stipanovic | 0626367 | 2019-07-11 21:37:40 +0000 | [diff] [blame] | 1700 | // Every function might be marked "nosync" |
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 1701 | getOrCreateAAFor<AANoSync>(FPos); |
| Stefan Stipanovic | 0626367 | 2019-07-11 21:37:40 +0000 | [diff] [blame] | 1702 | |
| Hideto Ueno | 65bbaf9 | 2019-07-12 17:38:51 +0000 | [diff] [blame] | 1703 | // Every function might be "no-free". |
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 1704 | getOrCreateAAFor<AANoFree>(FPos); |
| Hideto Ueno | 65bbaf9 | 2019-07-12 17:38:51 +0000 | [diff] [blame] | 1705 | |
| Johannes Doerfert | e83f303 | 2019-08-05 23:22:05 +0000 | [diff] [blame] | 1706 | // Every function might be "no-return". |
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 1707 | getOrCreateAAFor<AANoReturn>(FPos); |
| Johannes Doerfert | e83f303 | 2019-08-05 23:22:05 +0000 | [diff] [blame] | 1708 | |
| Hideto Ueno | 63f6066 | 2019-09-21 15:13:19 +0000 | [diff] [blame] | 1709 | // Every function might be "no-recurse". |
| 1710 | getOrCreateAAFor<AANoRecurse>(FPos); |
| 1711 | |
| Johannes Doerfert | 1097fab | 2019-10-07 21:07:57 +0000 | [diff] [blame] | 1712 | // Every function might be "readnone/readonly/writeonly/...". |
| 1713 | getOrCreateAAFor<AAMemoryBehavior>(FPos); |
| 1714 | |
| Johannes Doerfert | 282f5d7 | 2020-01-26 02:51:57 -0600 | [diff] [blame] | 1715 | // Every function can be "readnone/argmemonly/inaccessiblememonly/...". |
| 1716 | getOrCreateAAFor<AAMemoryLocation>(FPos); |
| 1717 | |
| Stefan Stipanovic | 431141c | 2019-09-15 21:47:41 +0000 | [diff] [blame] | 1718 | // Every function might be applicable for Heap-To-Stack conversion. |
| 1719 | if (EnableHeapToStack) |
| 1720 | getOrCreateAAFor<AAHeapToStack>(FPos); |
| 1721 | |
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 1722 | // Return attributes are only appropriate if the return type is non void. |
| 1723 | Type *ReturnType = F.getReturnType(); |
| 1724 | if (!ReturnType->isVoidTy()) { |
| 1725 | // Argument attribute "returned" --- Create only one per function even |
| 1726 | // though it is an argument attribute. |
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 1727 | getOrCreateAAFor<AAReturnedValues>(FPos); |
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 1728 | |
| Hideto Ueno | f2b9dc4 | 2019-09-07 07:03:05 +0000 | [diff] [blame] | 1729 | IRPosition RetPos = IRPosition::returned(F); |
| 1730 | |
| Johannes Doerfert | cd4aab4 | 2019-10-13 03:08:18 -0500 | [diff] [blame] | 1731 | // Every returned value might be dead. |
| 1732 | getOrCreateAAFor<AAIsDead>(RetPos); |
| 1733 | |
| Hideto Ueno | f2b9dc4 | 2019-09-07 07:03:05 +0000 | [diff] [blame] | 1734 | // Every function might be simplified. |
| 1735 | getOrCreateAAFor<AAValueSimplify>(RetPos); |
| 1736 | |
| Stefan Stipanovic | 69ebb02 | 2019-07-22 19:36:27 +0000 | [diff] [blame] | 1737 | if (ReturnType->isPointerTy()) { |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 1738 | |
| Hideto Ueno | e7bea9b | 2019-07-28 07:04:01 +0000 | [diff] [blame] | 1739 | // Every function with pointer return type might be marked align. |
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 1740 | getOrCreateAAFor<AAAlign>(RetPos); |
| Hideto Ueno | e7bea9b | 2019-07-28 07:04:01 +0000 | [diff] [blame] | 1741 | |
| Stefan Stipanovic | 69ebb02 | 2019-07-22 19:36:27 +0000 | [diff] [blame] | 1742 | // Every function with pointer return type might be marked nonnull. |
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 1743 | getOrCreateAAFor<AANonNull>(RetPos); |
| Stefan Stipanovic | 69ebb02 | 2019-07-22 19:36:27 +0000 | [diff] [blame] | 1744 | |
| 1745 | // Every function with pointer return type might be marked noalias. |
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 1746 | getOrCreateAAFor<AANoAlias>(RetPos); |
| Hideto Ueno | 19c07af | 2019-07-23 08:16:17 +0000 | [diff] [blame] | 1747 | |
| 1748 | // Every function with pointer return type might be marked |
| 1749 | // dereferenceable. |
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 1750 | getOrCreateAAFor<AADereferenceable>(RetPos); |
| Stefan Stipanovic | 69ebb02 | 2019-07-22 19:36:27 +0000 | [diff] [blame] | 1751 | } |
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 1752 | } |
| 1753 | |
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 1754 | for (Argument &Arg : F.args()) { |
| Hideto Ueno | f2b9dc4 | 2019-09-07 07:03:05 +0000 | [diff] [blame] | 1755 | IRPosition ArgPos = IRPosition::argument(Arg); |
| 1756 | |
| 1757 | // Every argument might be simplified. |
| 1758 | getOrCreateAAFor<AAValueSimplify>(ArgPos); |
| 1759 | |
| Johannes Doerfert | 1e99fc9 | 2020-02-16 16:42:47 -0600 | [diff] [blame] | 1760 | // Every argument might be dead. |
| 1761 | getOrCreateAAFor<AAIsDead>(ArgPos); |
| 1762 | |
| Hideto Ueno | 19c07af | 2019-07-23 08:16:17 +0000 | [diff] [blame] | 1763 | if (Arg.getType()->isPointerTy()) { |
| 1764 | // Every argument with pointer type might be marked nonnull. |
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 1765 | getOrCreateAAFor<AANonNull>(ArgPos); |
| Hideto Ueno | 19c07af | 2019-07-23 08:16:17 +0000 | [diff] [blame] | 1766 | |
| Hideto Ueno | cbab334 | 2019-08-29 05:52:00 +0000 | [diff] [blame] | 1767 | // Every argument with pointer type might be marked noalias. |
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 1768 | getOrCreateAAFor<AANoAlias>(ArgPos); |
| Hideto Ueno | cbab334 | 2019-08-29 05:52:00 +0000 | [diff] [blame] | 1769 | |
| Hideto Ueno | 19c07af | 2019-07-23 08:16:17 +0000 | [diff] [blame] | 1770 | // Every argument with pointer type might be marked dereferenceable. |
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 1771 | getOrCreateAAFor<AADereferenceable>(ArgPos); |
| Hideto Ueno | e7bea9b | 2019-07-28 07:04:01 +0000 | [diff] [blame] | 1772 | |
| 1773 | // Every argument with pointer type might be marked align. |
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 1774 | getOrCreateAAFor<AAAlign>(ArgPos); |
| Johannes Doerfert | 7516a5e | 2019-09-03 20:37:24 +0000 | [diff] [blame] | 1775 | |
| 1776 | // Every argument with pointer type might be marked nocapture. |
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 1777 | getOrCreateAAFor<AANoCapture>(ArgPos); |
| Johannes Doerfert | 1097fab | 2019-10-07 21:07:57 +0000 | [diff] [blame] | 1778 | |
| 1779 | // Every argument with pointer type might be marked |
| 1780 | // "readnone/readonly/writeonly/..." |
| 1781 | getOrCreateAAFor<AAMemoryBehavior>(ArgPos); |
| Stefan Stipanovic | f35740d | 2019-11-02 16:35:38 +0100 | [diff] [blame] | 1782 | |
| 1783 | // Every argument with pointer type might be marked nofree. |
| 1784 | getOrCreateAAFor<AANoFree>(ArgPos); |
| Johannes Doerfert | 89c2e73 | 2019-10-30 17:20:20 -0500 | [diff] [blame] | 1785 | |
| 1786 | // Every argument with pointer type might be privatizable (or promotable) |
| 1787 | getOrCreateAAFor<AAPrivatizablePtr>(ArgPos); |
| Hideto Ueno | 19c07af | 2019-07-23 08:16:17 +0000 | [diff] [blame] | 1788 | } |
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 1789 | } |
| 1790 | |
| Johannes Doerfert | 3ab9e8b | 2019-09-17 10:52:41 +0000 | [diff] [blame] | 1791 | auto CallSitePred = [&](Instruction &I) -> bool { |
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 1792 | CallSite CS(&I); |
| Johannes Doerfert | 86509e8 | 2020-01-12 00:34:38 -0600 | [diff] [blame] | 1793 | IRPosition CSRetPos = IRPosition::callsite_returned(CS); |
| 1794 | |
| 1795 | // Call sites might be dead if they do not have side effects and no live |
| 1796 | // users. The return value might be dead if there are no live users. |
| 1797 | getOrCreateAAFor<AAIsDead>(CSRetPos); |
| 1798 | |
| Johannes Doerfert | cd4aab4 | 2019-10-13 03:08:18 -0500 | [diff] [blame] | 1799 | if (Function *Callee = CS.getCalledFunction()) { |
| Johannes Doerfert | c36e2eb | 2019-10-31 20:15:02 -0500 | [diff] [blame] | 1800 | // Skip declerations except if annotations on their call sites were |
| 1801 | // explicitly requested. |
| Johannes Doerfert | 139c9ef | 2019-12-13 23:41:02 -0600 | [diff] [blame] | 1802 | if (!AnnotateDeclarationCallSites && Callee->isDeclaration() && |
| 1803 | !Callee->hasMetadata(LLVMContext::MD_callback)) |
| Johannes Doerfert | c36e2eb | 2019-10-31 20:15:02 -0500 | [diff] [blame] | 1804 | return true; |
| 1805 | |
| 1806 | if (!Callee->getReturnType()->isVoidTy() && !CS->use_empty()) { |
| Hideto Ueno | 188f9a3 | 2020-01-15 15:25:52 +0900 | [diff] [blame] | 1807 | |
| Johannes Doerfert | cd4aab4 | 2019-10-13 03:08:18 -0500 | [diff] [blame] | 1808 | IRPosition CSRetPos = IRPosition::callsite_returned(CS); |
| 1809 | |
| Hideto Ueno | 188f9a3 | 2020-01-15 15:25:52 +0900 | [diff] [blame] | 1810 | // Call site return integer values might be limited by a constant range. |
| Johannes Doerfert | 86509e8 | 2020-01-12 00:34:38 -0600 | [diff] [blame] | 1811 | if (Callee->getReturnType()->isIntegerTy()) |
| Hideto Ueno | 188f9a3 | 2020-01-15 15:25:52 +0900 | [diff] [blame] | 1812 | getOrCreateAAFor<AAValueConstantRange>(CSRetPos); |
| Johannes Doerfert | cd4aab4 | 2019-10-13 03:08:18 -0500 | [diff] [blame] | 1813 | } |
| 1814 | |
| Johannes Doerfert | 2888019 | 2019-12-31 00:57:00 -0600 | [diff] [blame] | 1815 | for (int i = 0, e = CS.getNumArgOperands(); i < e; i++) { |
| Hideto Ueno | f2b9dc4 | 2019-09-07 07:03:05 +0000 | [diff] [blame] | 1816 | |
| 1817 | IRPosition CSArgPos = IRPosition::callsite_argument(CS, i); |
| 1818 | |
| Johannes Doerfert | cd4aab4 | 2019-10-13 03:08:18 -0500 | [diff] [blame] | 1819 | // Every call site argument might be dead. |
| 1820 | getOrCreateAAFor<AAIsDead>(CSArgPos); |
| 1821 | |
| Hideto Ueno | f2b9dc4 | 2019-09-07 07:03:05 +0000 | [diff] [blame] | 1822 | // Call site argument might be simplified. |
| 1823 | getOrCreateAAFor<AAValueSimplify>(CSArgPos); |
| 1824 | |
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 1825 | if (!CS.getArgument(i)->getType()->isPointerTy()) |
| 1826 | continue; |
| 1827 | |
| 1828 | // Call site argument attribute "non-null". |
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 1829 | getOrCreateAAFor<AANonNull>(CSArgPos); |
| Hideto Ueno | 19c07af | 2019-07-23 08:16:17 +0000 | [diff] [blame] | 1830 | |
| Hideto Ueno | cbab334 | 2019-08-29 05:52:00 +0000 | [diff] [blame] | 1831 | // Call site argument attribute "no-alias". |
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 1832 | getOrCreateAAFor<AANoAlias>(CSArgPos); |
| Hideto Ueno | cbab334 | 2019-08-29 05:52:00 +0000 | [diff] [blame] | 1833 | |
| Hideto Ueno | 19c07af | 2019-07-23 08:16:17 +0000 | [diff] [blame] | 1834 | // Call site argument attribute "dereferenceable". |
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 1835 | getOrCreateAAFor<AADereferenceable>(CSArgPos); |
| Hideto Ueno | e7bea9b | 2019-07-28 07:04:01 +0000 | [diff] [blame] | 1836 | |
| 1837 | // Call site argument attribute "align". |
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 1838 | getOrCreateAAFor<AAAlign>(CSArgPos); |
| Stefan Stipanovic | f35740d | 2019-11-02 16:35:38 +0100 | [diff] [blame] | 1839 | |
| Johannes Doerfert | 2888019 | 2019-12-31 00:57:00 -0600 | [diff] [blame] | 1840 | // Call site argument attribute |
| 1841 | // "readnone/readonly/writeonly/..." |
| 1842 | getOrCreateAAFor<AAMemoryBehavior>(CSArgPos); |
| 1843 | |
| Hideto Ueno | 4ecf255 | 2019-12-12 13:42:40 +0000 | [diff] [blame] | 1844 | // Call site argument attribute "nofree". |
| 1845 | getOrCreateAAFor<AANoFree>(CSArgPos); |
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 1846 | } |
| 1847 | } |
| Johannes Doerfert | 3ab9e8b | 2019-09-17 10:52:41 +0000 | [diff] [blame] | 1848 | return true; |
| 1849 | }; |
| 1850 | |
| 1851 | auto &OpcodeInstMap = InfoCache.getOpcodeInstMapForFunction(F); |
| Johannes Doerfert | 23f41f1 | 2020-01-12 01:09:22 -0600 | [diff] [blame] | 1852 | bool Success; |
| Johannes Doerfert | 3ab9e8b | 2019-09-17 10:52:41 +0000 | [diff] [blame] | 1853 | Success = checkForAllInstructionsImpl( |
| Johannes Doerfert | 23f41f1 | 2020-01-12 01:09:22 -0600 | [diff] [blame] | 1854 | nullptr, OpcodeInstMap, CallSitePred, nullptr, nullptr, |
| Johannes Doerfert | 3ab9e8b | 2019-09-17 10:52:41 +0000 | [diff] [blame] | 1855 | {(unsigned)Instruction::Invoke, (unsigned)Instruction::CallBr, |
| 1856 | (unsigned)Instruction::Call}); |
| 1857 | (void)Success; |
| Johannes Doerfert | 23f41f1 | 2020-01-12 01:09:22 -0600 | [diff] [blame] | 1858 | assert(Success && "Expected the check call to be successful!"); |
| Johannes Doerfert | 3ab9e8b | 2019-09-17 10:52:41 +0000 | [diff] [blame] | 1859 | |
| 1860 | auto LoadStorePred = [&](Instruction &I) -> bool { |
| 1861 | if (isa<LoadInst>(I)) |
| 1862 | getOrCreateAAFor<AAAlign>( |
| 1863 | IRPosition::value(*cast<LoadInst>(I).getPointerOperand())); |
| 1864 | else |
| 1865 | getOrCreateAAFor<AAAlign>( |
| 1866 | IRPosition::value(*cast<StoreInst>(I).getPointerOperand())); |
| 1867 | return true; |
| 1868 | }; |
| 1869 | Success = checkForAllInstructionsImpl( |
| Johannes Doerfert | 23f41f1 | 2020-01-12 01:09:22 -0600 | [diff] [blame] | 1870 | nullptr, OpcodeInstMap, LoadStorePred, nullptr, nullptr, |
| Johannes Doerfert | 3ab9e8b | 2019-09-17 10:52:41 +0000 | [diff] [blame] | 1871 | {(unsigned)Instruction::Load, (unsigned)Instruction::Store}); |
| 1872 | (void)Success; |
| Johannes Doerfert | 23f41f1 | 2020-01-12 01:09:22 -0600 | [diff] [blame] | 1873 | assert(Success && "Expected the check call to be successful!"); |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 1874 | } |
| 1875 | |
| 1876 | /// Helpers to ease debugging through output streams and print calls. |
| 1877 | /// |
| 1878 | ///{ |
| 1879 | raw_ostream &llvm::operator<<(raw_ostream &OS, ChangeStatus S) { |
| 1880 | return OS << (S == ChangeStatus::CHANGED ? "changed" : "unchanged"); |
| 1881 | } |
| 1882 | |
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 1883 | raw_ostream &llvm::operator<<(raw_ostream &OS, IRPosition::Kind AP) { |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 1884 | switch (AP) { |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 1885 | case IRPosition::IRP_INVALID: |
| 1886 | return OS << "inv"; |
| 1887 | case IRPosition::IRP_FLOAT: |
| 1888 | return OS << "flt"; |
| 1889 | case IRPosition::IRP_RETURNED: |
| 1890 | return OS << "fn_ret"; |
| 1891 | case IRPosition::IRP_CALL_SITE_RETURNED: |
| 1892 | return OS << "cs_ret"; |
| 1893 | case IRPosition::IRP_FUNCTION: |
| 1894 | return OS << "fn"; |
| 1895 | case IRPosition::IRP_CALL_SITE: |
| 1896 | return OS << "cs"; |
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 1897 | case IRPosition::IRP_ARGUMENT: |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 1898 | return OS << "arg"; |
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 1899 | case IRPosition::IRP_CALL_SITE_ARGUMENT: |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 1900 | return OS << "cs_arg"; |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 1901 | } |
| 1902 | llvm_unreachable("Unknown attribute position!"); |
| 1903 | } |
| 1904 | |
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 1905 | raw_ostream &llvm::operator<<(raw_ostream &OS, const IRPosition &Pos) { |
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 1906 | const Value &AV = Pos.getAssociatedValue(); |
| 1907 | return OS << "{" << Pos.getPositionKind() << ":" << AV.getName() << " [" |
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 1908 | << Pos.getAnchorValue().getName() << "@" << Pos.getArgNo() << "]}"; |
| 1909 | } |
| 1910 | |
| Hideto Ueno | 188f9a3 | 2020-01-15 15:25:52 +0900 | [diff] [blame] | 1911 | raw_ostream &llvm::operator<<(raw_ostream &OS, const IntegerRangeState &S) { |
| 1912 | OS << "range-state(" << S.getBitWidth() << ")<"; |
| 1913 | S.getKnown().print(OS); |
| 1914 | OS << " / "; |
| 1915 | S.getAssumed().print(OS); |
| 1916 | OS << ">"; |
| 1917 | |
| 1918 | return OS << static_cast<const AbstractState &>(S); |
| 1919 | } |
| 1920 | |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 1921 | raw_ostream &llvm::operator<<(raw_ostream &OS, const AbstractState &S) { |
| 1922 | return OS << (!S.isValidState() ? "top" : (S.isAtFixpoint() ? "fix" : "")); |
| 1923 | } |
| 1924 | |
| 1925 | raw_ostream &llvm::operator<<(raw_ostream &OS, const AbstractAttribute &AA) { |
| 1926 | AA.print(OS); |
| 1927 | return OS; |
| 1928 | } |
| 1929 | |
| 1930 | void AbstractAttribute::print(raw_ostream &OS) const { |
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 1931 | OS << "[P: " << getIRPosition() << "][" << getAsStr() << "][S: " << getState() |
| 1932 | << "]"; |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 1933 | } |
| 1934 | ///} |
| 1935 | |
| 1936 | /// ---------------------------------------------------------------------------- |
| 1937 | /// Pass (Manager) Boilerplate |
| 1938 | /// ---------------------------------------------------------------------------- |
| 1939 | |
| Johannes Doerfert | b0c77c3 | 2019-11-27 00:30:12 -0600 | [diff] [blame] | 1940 | static bool runAttributorOnFunctions(InformationCache &InfoCache, |
| 1941 | SetVector<Function *> &Functions, |
| 1942 | AnalysisGetter &AG, |
| 1943 | CallGraphUpdater &CGUpdater) { |
| Tarindu Jayatilaka | b43b59f | 2020-04-05 11:45:19 -0500 | [diff] [blame] | 1944 | if (Functions.empty()) |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 1945 | return false; |
| 1946 | |
| Johannes Doerfert | b0c77c3 | 2019-11-27 00:30:12 -0600 | [diff] [blame] | 1947 | LLVM_DEBUG(dbgs() << "[Attributor] Run on module with " << Functions.size() |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 1948 | << " functions.\n"); |
| 1949 | |
| 1950 | // Create an Attributor and initially empty information cache that is filled |
| 1951 | // while we identify default attribute opportunities. |
| Johannes Doerfert | b0c77c3 | 2019-11-27 00:30:12 -0600 | [diff] [blame] | 1952 | Attributor A(Functions, InfoCache, CGUpdater, DepRecInterval); |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 1953 | |
| Stefanos Baziotis | a650d55 | 2020-03-23 22:44:10 +0200 | [diff] [blame] | 1954 | // Note: _Don't_ combine/fuse this loop with the one below because |
| 1955 | // when A.identifyDefaultAbstractAttributes() is called for one |
| 1956 | // function, it assumes that the information cach has been |
| 1957 | // initialized for _all_ functions. |
| Johannes Doerfert | b0c77c3 | 2019-11-27 00:30:12 -0600 | [diff] [blame] | 1958 | for (Function *F : Functions) |
| 1959 | A.initializeInformationCache(*F); |
| Johannes Doerfert | 3ab9e8b | 2019-09-17 10:52:41 +0000 | [diff] [blame] | 1960 | |
| Luofan Chen | eec6d87 | 2020-04-04 11:32:36 -0500 | [diff] [blame] | 1961 | // Create shallow wrappers for all functions that are not IPO amendable |
| 1962 | if (AllowShallowWrappers) |
| 1963 | for (Function *F : Functions) |
| 1964 | if (!A.isFunctionIPOAmendable(*F)) |
| 1965 | createShallowWrapper(*F); |
| 1966 | |
| Johannes Doerfert | b0c77c3 | 2019-11-27 00:30:12 -0600 | [diff] [blame] | 1967 | for (Function *F : Functions) { |
| 1968 | if (F->hasExactDefinition()) |
| Johannes Doerfert | b0412e4 | 2019-09-04 16:16:13 +0000 | [diff] [blame] | 1969 | NumFnWithExactDefinition++; |
| 1970 | else |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 1971 | NumFnWithoutExactDefinition++; |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 1972 | |
| Johannes Doerfert | 2f62206 | 2019-09-04 16:35:20 +0000 | [diff] [blame] | 1973 | // We look at internal functions only on-demand but if any use is not a |
| Johannes Doerfert | b0c77c3 | 2019-11-27 00:30:12 -0600 | [diff] [blame] | 1974 | // direct call or outside the current set of analyzed functions, we have to |
| 1975 | // do it eagerly. |
| 1976 | if (F->hasLocalLinkage()) { |
| 1977 | if (llvm::all_of(F->uses(), [&Functions](const Use &U) { |
| 1978 | ImmutableCallSite ICS(U.getUser()); |
| 1979 | return ICS && ICS.isCallee(&U) && |
| 1980 | Functions.count(const_cast<Function *>(ICS.getCaller())); |
| Johannes Doerfert | 2f62206 | 2019-09-04 16:35:20 +0000 | [diff] [blame] | 1981 | })) |
| 1982 | continue; |
| 1983 | } |
| 1984 | |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 1985 | // Populate the Attributor with abstract attribute opportunities in the |
| 1986 | // function and the information cache with IR information. |
| Johannes Doerfert | b0c77c3 | 2019-11-27 00:30:12 -0600 | [diff] [blame] | 1987 | A.identifyDefaultAbstractAttributes(*F); |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 1988 | } |
| 1989 | |
| Johannes Doerfert | 54d6a60 | 2020-03-16 20:18:07 -0500 | [diff] [blame] | 1990 | Module &M = *Functions.front()->getParent(); |
| 1991 | (void)M; |
| Johannes Doerfert | 77a9e61 | 2020-01-11 23:36:17 -0600 | [diff] [blame] | 1992 | ChangeStatus Changed = A.run(); |
| Johannes Doerfert | 54d6a60 | 2020-03-16 20:18:07 -0500 | [diff] [blame] | 1993 | assert(!verifyModule(M, &errs()) && "Module verification failed!"); |
| Johannes Doerfert | 77a9e61 | 2020-01-11 23:36:17 -0600 | [diff] [blame] | 1994 | LLVM_DEBUG(dbgs() << "[Attributor] Done with " << Functions.size() |
| 1995 | << " functions, result: " << Changed << ".\n"); |
| 1996 | return Changed == ChangeStatus::CHANGED; |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 1997 | } |
| 1998 | |
| 1999 | PreservedAnalyses AttributorPass::run(Module &M, ModuleAnalysisManager &AM) { |
| Johannes Doerfert | b0c77c3 | 2019-11-27 00:30:12 -0600 | [diff] [blame] | 2000 | FunctionAnalysisManager &FAM = |
| 2001 | AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); |
| 2002 | AnalysisGetter AG(FAM); |
| 2003 | |
| 2004 | SetVector<Function *> Functions; |
| 2005 | for (Function &F : M) |
| 2006 | Functions.insert(&F); |
| 2007 | |
| 2008 | CallGraphUpdater CGUpdater; |
| 2009 | InformationCache InfoCache(M, AG, /* CGSCC */ nullptr); |
| 2010 | if (runAttributorOnFunctions(InfoCache, Functions, AG, CGUpdater)) { |
| 2011 | // FIXME: Think about passes we will preserve and add them here. |
| 2012 | return PreservedAnalyses::none(); |
| 2013 | } |
| 2014 | return PreservedAnalyses::all(); |
| 2015 | } |
| 2016 | |
| 2017 | PreservedAnalyses AttributorCGSCCPass::run(LazyCallGraph::SCC &C, |
| 2018 | CGSCCAnalysisManager &AM, |
| 2019 | LazyCallGraph &CG, |
| 2020 | CGSCCUpdateResult &UR) { |
| 2021 | FunctionAnalysisManager &FAM = |
| 2022 | AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager(); |
| 2023 | AnalysisGetter AG(FAM); |
| 2024 | |
| 2025 | SetVector<Function *> Functions; |
| 2026 | for (LazyCallGraph::Node &N : C) |
| 2027 | Functions.insert(&N.getFunction()); |
| 2028 | |
| 2029 | if (Functions.empty()) |
| 2030 | return PreservedAnalyses::all(); |
| 2031 | |
| 2032 | Module &M = *Functions.back()->getParent(); |
| 2033 | CallGraphUpdater CGUpdater; |
| 2034 | CGUpdater.initialize(CG, C, AM, UR); |
| 2035 | InformationCache InfoCache(M, AG, /* CGSCC */ &Functions); |
| 2036 | if (runAttributorOnFunctions(InfoCache, Functions, AG, CGUpdater)) { |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 2037 | // FIXME: Think about passes we will preserve and add them here. |
| 2038 | return PreservedAnalyses::none(); |
| 2039 | } |
| 2040 | return PreservedAnalyses::all(); |
| 2041 | } |
| 2042 | |
| 2043 | namespace { |
| 2044 | |
| 2045 | struct AttributorLegacyPass : public ModulePass { |
| 2046 | static char ID; |
| 2047 | |
| 2048 | AttributorLegacyPass() : ModulePass(ID) { |
| 2049 | initializeAttributorLegacyPassPass(*PassRegistry::getPassRegistry()); |
| 2050 | } |
| 2051 | |
| 2052 | bool runOnModule(Module &M) override { |
| 2053 | if (skipModule(M)) |
| 2054 | return false; |
| Stefan Stipanovic | 431141c | 2019-09-15 21:47:41 +0000 | [diff] [blame] | 2055 | |
| Hideto Ueno | 3bb5cbc | 2019-09-17 05:45:18 +0000 | [diff] [blame] | 2056 | AnalysisGetter AG; |
| Johannes Doerfert | b0c77c3 | 2019-11-27 00:30:12 -0600 | [diff] [blame] | 2057 | SetVector<Function *> Functions; |
| 2058 | for (Function &F : M) |
| 2059 | Functions.insert(&F); |
| 2060 | |
| 2061 | CallGraphUpdater CGUpdater; |
| 2062 | InformationCache InfoCache(M, AG, /* CGSCC */ nullptr); |
| 2063 | return runAttributorOnFunctions(InfoCache, Functions, AG, CGUpdater); |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 2064 | } |
| 2065 | |
| 2066 | void getAnalysisUsage(AnalysisUsage &AU) const override { |
| 2067 | // FIXME: Think about passes we will preserve and add them here. |
| Stefan Stipanovic | 431141c | 2019-09-15 21:47:41 +0000 | [diff] [blame] | 2068 | AU.addRequired<TargetLibraryInfoWrapperPass>(); |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 2069 | } |
| 2070 | }; |
| 2071 | |
| Johannes Doerfert | b0c77c3 | 2019-11-27 00:30:12 -0600 | [diff] [blame] | 2072 | struct AttributorCGSCCLegacyPass : public CallGraphSCCPass { |
| 2073 | CallGraphUpdater CGUpdater; |
| 2074 | static char ID; |
| 2075 | |
| 2076 | AttributorCGSCCLegacyPass() : CallGraphSCCPass(ID) { |
| 2077 | initializeAttributorCGSCCLegacyPassPass(*PassRegistry::getPassRegistry()); |
| 2078 | } |
| 2079 | |
| 2080 | bool runOnSCC(CallGraphSCC &SCC) override { |
| 2081 | if (skipSCC(SCC)) |
| 2082 | return false; |
| 2083 | |
| 2084 | SetVector<Function *> Functions; |
| 2085 | for (CallGraphNode *CGN : SCC) |
| 2086 | if (Function *Fn = CGN->getFunction()) |
| 2087 | if (!Fn->isDeclaration()) |
| 2088 | Functions.insert(Fn); |
| 2089 | |
| 2090 | if (Functions.empty()) |
| 2091 | return false; |
| 2092 | |
| 2093 | AnalysisGetter AG; |
| 2094 | CallGraph &CG = const_cast<CallGraph &>(SCC.getCallGraph()); |
| 2095 | CGUpdater.initialize(CG, SCC); |
| 2096 | Module &M = *Functions.back()->getParent(); |
| 2097 | InformationCache InfoCache(M, AG, /* CGSCC */ &Functions); |
| 2098 | return runAttributorOnFunctions(InfoCache, Functions, AG, CGUpdater); |
| 2099 | } |
| 2100 | |
| 2101 | bool doFinalization(CallGraph &CG) override { return CGUpdater.finalize(); } |
| 2102 | |
| 2103 | void getAnalysisUsage(AnalysisUsage &AU) const override { |
| 2104 | // FIXME: Think about passes we will preserve and add them here. |
| 2105 | AU.addRequired<TargetLibraryInfoWrapperPass>(); |
| 2106 | CallGraphSCCPass::getAnalysisUsage(AU); |
| 2107 | } |
| 2108 | }; |
| 2109 | |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 2110 | } // end anonymous namespace |
| 2111 | |
| 2112 | Pass *llvm::createAttributorLegacyPass() { return new AttributorLegacyPass(); } |
| Johannes Doerfert | b0c77c3 | 2019-11-27 00:30:12 -0600 | [diff] [blame] | 2113 | Pass *llvm::createAttributorCGSCCLegacyPass() { |
| 2114 | return new AttributorCGSCCLegacyPass(); |
| 2115 | } |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 2116 | |
| 2117 | char AttributorLegacyPass::ID = 0; |
| Johannes Doerfert | b0c77c3 | 2019-11-27 00:30:12 -0600 | [diff] [blame] | 2118 | char AttributorCGSCCLegacyPass::ID = 0; |
| Johannes Doerfert | 2402062 | 2019-08-05 23:30:01 +0000 | [diff] [blame] | 2119 | |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 2120 | INITIALIZE_PASS_BEGIN(AttributorLegacyPass, "attributor", |
| 2121 | "Deduce and propagate attributes", false, false) |
| Stefan Stipanovic | 431141c | 2019-09-15 21:47:41 +0000 | [diff] [blame] | 2122 | INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) |
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 2123 | INITIALIZE_PASS_END(AttributorLegacyPass, "attributor", |
| 2124 | "Deduce and propagate attributes", false, false) |
| Johannes Doerfert | b0c77c3 | 2019-11-27 00:30:12 -0600 | [diff] [blame] | 2125 | INITIALIZE_PASS_BEGIN(AttributorCGSCCLegacyPass, "attributor-cgscc", |
| 2126 | "Deduce and propagate attributes (CGSCC pass)", false, |
| 2127 | false) |
| 2128 | INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) |
| 2129 | INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass) |
| 2130 | INITIALIZE_PASS_END(AttributorCGSCCLegacyPass, "attributor-cgscc", |
| 2131 | "Deduce and propagate attributes (CGSCC pass)", false, |
| 2132 | false) |