| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 1 | //===- Attributor.cpp - Module-wide attribute deduction -------------------===// | 
|  | 2 | // | 
|  | 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | 4 | // See https://llvm.org/LICENSE.txt for license information. | 
|  | 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | 6 | // | 
|  | 7 | //===----------------------------------------------------------------------===// | 
|  | 8 | // | 
|  | 9 | // This file implements an inter procedural pass that deduces and/or propagating | 
|  | 10 | // attributes. This is done in an abstract interpretation style fixpoint | 
|  | 11 | // iteration. See the Attributor.h file comment and the class descriptions in | 
|  | 12 | // that file for more information. | 
|  | 13 | // | 
|  | 14 | //===----------------------------------------------------------------------===// | 
|  | 15 |  | 
|  | 16 | #include "llvm/Transforms/IPO/Attributor.h" | 
|  | 17 |  | 
| Hideto Ueno | 11d3710 | 2019-07-17 15:15:43 +0000 | [diff] [blame] | 18 | #include "llvm/ADT/DepthFirstIterator.h" | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 19 | #include "llvm/ADT/STLExtras.h" | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 20 | #include "llvm/ADT/SmallPtrSet.h" | 
|  | 21 | #include "llvm/ADT/SmallVector.h" | 
|  | 22 | #include "llvm/ADT/Statistic.h" | 
| Stefan Stipanovic | 69ebb02 | 2019-07-22 19:36:27 +0000 | [diff] [blame] | 23 | #include "llvm/Analysis/CaptureTracking.h" | 
| Johannes Doerfert | 924d213 | 2019-08-05 21:34:45 +0000 | [diff] [blame] | 24 | #include "llvm/Analysis/EHPersonalities.h" | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 25 | #include "llvm/Analysis/GlobalsModRef.h" | 
| Hideto Ueno | 19c07af | 2019-07-23 08:16:17 +0000 | [diff] [blame] | 26 | #include "llvm/Analysis/Loads.h" | 
| Stefan Stipanovic | 431141c | 2019-09-15 21:47:41 +0000 | [diff] [blame] | 27 | #include "llvm/Analysis/MemoryBuiltins.h" | 
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 28 | #include "llvm/Analysis/ValueTracking.h" | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 29 | #include "llvm/IR/Argument.h" | 
|  | 30 | #include "llvm/IR/Attributes.h" | 
| Hideto Ueno | 11d3710 | 2019-07-17 15:15:43 +0000 | [diff] [blame] | 31 | #include "llvm/IR/CFG.h" | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 32 | #include "llvm/IR/InstIterator.h" | 
| Stefan Stipanovic | 0626367 | 2019-07-11 21:37:40 +0000 | [diff] [blame] | 33 | #include "llvm/IR/IntrinsicInst.h" | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 34 | #include "llvm/Support/CommandLine.h" | 
|  | 35 | #include "llvm/Support/Debug.h" | 
|  | 36 | #include "llvm/Support/raw_ostream.h" | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 37 | #include "llvm/Transforms/Utils/BasicBlockUtils.h" | 
|  | 38 | #include "llvm/Transforms/Utils/Local.h" | 
|  | 39 |  | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 40 | #include <cassert> | 
|  | 41 |  | 
|  | 42 | using namespace llvm; | 
|  | 43 |  | 
|  | 44 | #define DEBUG_TYPE "attributor" | 
|  | 45 |  | 
|  | 46 | STATISTIC(NumFnWithExactDefinition, | 
|  | 47 | "Number of function with exact definitions"); | 
|  | 48 | STATISTIC(NumFnWithoutExactDefinition, | 
|  | 49 | "Number of function without exact definitions"); | 
|  | 50 | STATISTIC(NumAttributesTimedOut, | 
|  | 51 | "Number of abstract attributes timed out before fixpoint"); | 
|  | 52 | STATISTIC(NumAttributesValidFixpoint, | 
|  | 53 | "Number of abstract attributes in a valid fixpoint state"); | 
|  | 54 | STATISTIC(NumAttributesManifested, | 
|  | 55 | "Number of abstract attributes manifested in IR"); | 
|  | 56 |  | 
| Johannes Doerfert | d1b79e0 | 2019-08-07 22:46:11 +0000 | [diff] [blame] | 57 | // Some helper macros to deal with statistics tracking. | 
|  | 58 | // | 
|  | 59 | // Usage: | 
|  | 60 | // For simple IR attribute tracking overload trackStatistics in the abstract | 
| Johannes Doerfert | 17b578b | 2019-08-14 21:46:25 +0000 | [diff] [blame] | 61 | // attribute and choose the right STATS_DECLTRACK_********* macro, | 
| Johannes Doerfert | d1b79e0 | 2019-08-07 22:46:11 +0000 | [diff] [blame] | 62 | // e.g.,: | 
|  | 63 | //  void trackStatistics() const override { | 
| Johannes Doerfert | 17b578b | 2019-08-14 21:46:25 +0000 | [diff] [blame] | 64 | //    STATS_DECLTRACK_ARG_ATTR(returned) | 
| Johannes Doerfert | d1b79e0 | 2019-08-07 22:46:11 +0000 | [diff] [blame] | 65 | //  } | 
|  | 66 | // If there is a single "increment" side one can use the macro | 
| Johannes Doerfert | 17b578b | 2019-08-14 21:46:25 +0000 | [diff] [blame] | 67 | // STATS_DECLTRACK with a custom message. If there are multiple increment | 
| Johannes Doerfert | d1b79e0 | 2019-08-07 22:46:11 +0000 | [diff] [blame] | 68 | // sides, STATS_DECL and STATS_TRACK can also be used separatly. | 
|  | 69 | // | 
|  | 70 | #define BUILD_STAT_MSG_IR_ATTR(TYPE, NAME)                                     \ | 
|  | 71 | ("Number of " #TYPE " marked '" #NAME "'") | 
|  | 72 | #define BUILD_STAT_NAME(NAME, TYPE) NumIR##TYPE##_##NAME | 
| Johannes Doerfert | a7a3b3a | 2019-09-04 19:01:08 +0000 | [diff] [blame] | 73 | #define STATS_DECL_(NAME, MSG) STATISTIC(NAME, MSG); | 
|  | 74 | #define STATS_DECL(NAME, TYPE, MSG)                                            \ | 
|  | 75 | STATS_DECL_(BUILD_STAT_NAME(NAME, TYPE), MSG); | 
| Johannes Doerfert | d1b79e0 | 2019-08-07 22:46:11 +0000 | [diff] [blame] | 76 | #define STATS_TRACK(NAME, TYPE) ++(BUILD_STAT_NAME(NAME, TYPE)); | 
| Johannes Doerfert | 17b578b | 2019-08-14 21:46:25 +0000 | [diff] [blame] | 77 | #define STATS_DECLTRACK(NAME, TYPE, MSG)                                       \ | 
| Johannes Doerfert | 169af99 | 2019-08-20 06:09:56 +0000 | [diff] [blame] | 78 | {                                                                            \ | 
|  | 79 | STATS_DECL(NAME, TYPE, MSG)                                                \ | 
|  | 80 | STATS_TRACK(NAME, TYPE)                                                    \ | 
|  | 81 | } | 
| Johannes Doerfert | 17b578b | 2019-08-14 21:46:25 +0000 | [diff] [blame] | 82 | #define STATS_DECLTRACK_ARG_ATTR(NAME)                                         \ | 
|  | 83 | STATS_DECLTRACK(NAME, Arguments, BUILD_STAT_MSG_IR_ATTR(arguments, NAME)) | 
|  | 84 | #define STATS_DECLTRACK_CSARG_ATTR(NAME)                                       \ | 
|  | 85 | STATS_DECLTRACK(NAME, CSArguments,                                           \ | 
|  | 86 | BUILD_STAT_MSG_IR_ATTR(call site arguments, NAME)) | 
|  | 87 | #define STATS_DECLTRACK_FN_ATTR(NAME)                                          \ | 
|  | 88 | STATS_DECLTRACK(NAME, Function, BUILD_STAT_MSG_IR_ATTR(functions, NAME)) | 
|  | 89 | #define STATS_DECLTRACK_CS_ATTR(NAME)                                          \ | 
|  | 90 | STATS_DECLTRACK(NAME, CS, BUILD_STAT_MSG_IR_ATTR(call site, NAME)) | 
|  | 91 | #define STATS_DECLTRACK_FNRET_ATTR(NAME)                                       \ | 
|  | 92 | STATS_DECLTRACK(NAME, FunctionReturn,                                        \ | 
| Johannes Doerfert | 2db8528 | 2019-08-21 20:56:56 +0000 | [diff] [blame] | 93 | BUILD_STAT_MSG_IR_ATTR(function returns, NAME)) | 
| Johannes Doerfert | 17b578b | 2019-08-14 21:46:25 +0000 | [diff] [blame] | 94 | #define STATS_DECLTRACK_CSRET_ATTR(NAME)                                       \ | 
|  | 95 | STATS_DECLTRACK(NAME, CSReturn,                                              \ | 
|  | 96 | BUILD_STAT_MSG_IR_ATTR(call site returns, NAME)) | 
|  | 97 | #define STATS_DECLTRACK_FLOATING_ATTR(NAME)                                    \ | 
|  | 98 | STATS_DECLTRACK(NAME, Floating,                                              \ | 
|  | 99 | ("Number of floating values known to be '" #NAME "'")) | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 100 |  | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 101 | // TODO: Determine a good default value. | 
|  | 102 | // | 
|  | 103 | // In the LLVM-TS and SPEC2006, 32 seems to not induce compile time overheads | 
|  | 104 | // (when run with the first 5 abstract attributes). The results also indicate | 
|  | 105 | // that we never reach 32 iterations but always find a fixpoint sooner. | 
|  | 106 | // | 
|  | 107 | // This will become more evolved once we perform two interleaved fixpoint | 
|  | 108 | // iterations: bottom-up and top-down. | 
|  | 109 | static cl::opt<unsigned> | 
|  | 110 | MaxFixpointIterations("attributor-max-iterations", cl::Hidden, | 
|  | 111 | cl::desc("Maximal number of fixpoint iterations."), | 
|  | 112 | cl::init(32)); | 
| Johannes Doerfert | b504eb8 | 2019-08-26 18:55:47 +0000 | [diff] [blame] | 113 | static cl::opt<bool> VerifyMaxFixpointIterations( | 
|  | 114 | "attributor-max-iterations-verify", cl::Hidden, | 
|  | 115 | cl::desc("Verify that max-iterations is a tight bound for a fixpoint"), | 
|  | 116 | cl::init(false)); | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 117 |  | 
|  | 118 | static cl::opt<bool> DisableAttributor( | 
|  | 119 | "attributor-disable", cl::Hidden, | 
|  | 120 | cl::desc("Disable the attributor inter-procedural deduction pass."), | 
| Johannes Doerfert | 282d34e | 2019-06-14 14:53:41 +0000 | [diff] [blame] | 121 | cl::init(true)); | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 122 |  | 
| Johannes Doerfert | 7516a5e | 2019-09-03 20:37:24 +0000 | [diff] [blame] | 123 | static cl::opt<bool> ManifestInternal( | 
|  | 124 | "attributor-manifest-internal", cl::Hidden, | 
|  | 125 | cl::desc("Manifest Attributor internal string attributes."), | 
|  | 126 | cl::init(false)); | 
|  | 127 |  | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 128 | static cl::opt<bool> VerifyAttributor( | 
|  | 129 | "attributor-verify", cl::Hidden, | 
|  | 130 | cl::desc("Verify the Attributor deduction and " | 
|  | 131 | "manifestation of attributes -- may issue false-positive errors"), | 
|  | 132 | cl::init(false)); | 
|  | 133 |  | 
| Johannes Doerfert | f7ca0fe | 2019-08-28 16:58:52 +0000 | [diff] [blame] | 134 | static cl::opt<unsigned> DepRecInterval( | 
|  | 135 | "attributor-dependence-recompute-interval", cl::Hidden, | 
|  | 136 | cl::desc("Number of iterations until dependences are recomputed."), | 
|  | 137 | cl::init(4)); | 
|  | 138 |  | 
| Stefan Stipanovic | 431141c | 2019-09-15 21:47:41 +0000 | [diff] [blame] | 139 | static cl::opt<bool> EnableHeapToStack("enable-heap-to-stack-conversion", | 
|  | 140 | cl::init(true), cl::Hidden); | 
|  | 141 |  | 
|  | 142 | static cl::opt<int> MaxHeapToStackSize("max-heap-to-stack-size", | 
|  | 143 | cl::init(128), cl::Hidden); | 
|  | 144 |  | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 145 | /// Logic operators for the change status enum class. | 
|  | 146 | /// | 
|  | 147 | ///{ | 
|  | 148 | ChangeStatus llvm::operator|(ChangeStatus l, ChangeStatus r) { | 
|  | 149 | return l == ChangeStatus::CHANGED ? l : r; | 
|  | 150 | } | 
|  | 151 | ChangeStatus llvm::operator&(ChangeStatus l, ChangeStatus r) { | 
|  | 152 | return l == ChangeStatus::UNCHANGED ? l : r; | 
|  | 153 | } | 
|  | 154 | ///} | 
|  | 155 |  | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 156 | /// Recursively visit all values that might become \p IRP at some point. This | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 157 | /// will be done by looking through cast instructions, selects, phis, and calls | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 158 | /// with the "returned" attribute. Once we cannot look through the value any | 
|  | 159 | /// further, the callback \p VisitValueCB is invoked and passed the current | 
|  | 160 | /// value, the \p State, and a flag to indicate if we stripped anything. To | 
|  | 161 | /// limit how much effort is invested, we will never visit more values than | 
|  | 162 | /// specified by \p MaxValues. | 
|  | 163 | template <typename AAType, typename StateTy> | 
|  | 164 | bool genericValueTraversal( | 
|  | 165 | Attributor &A, IRPosition IRP, const AAType &QueryingAA, StateTy &State, | 
| Johannes Doerfert | b9b8791 | 2019-08-20 06:02:39 +0000 | [diff] [blame] | 166 | const function_ref<bool(Value &, StateTy &, bool)> &VisitValueCB, | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 167 | int MaxValues = 8) { | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 168 |  | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 169 | const AAIsDead *LivenessAA = nullptr; | 
|  | 170 | if (IRP.getAnchorScope()) | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 171 | LivenessAA = &A.getAAFor<AAIsDead>( | 
| Johannes Doerfert | 19b0043 | 2019-08-26 17:48:05 +0000 | [diff] [blame] | 172 | QueryingAA, IRPosition::function(*IRP.getAnchorScope()), | 
|  | 173 | /* TrackDependence */ false); | 
|  | 174 | bool AnyDead = false; | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 175 |  | 
|  | 176 | // TODO: Use Positions here to allow context sensitivity in VisitValueCB | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 177 | SmallPtrSet<Value *, 16> Visited; | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 178 | SmallVector<Value *, 16> Worklist; | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 179 | Worklist.push_back(&IRP.getAssociatedValue()); | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 180 |  | 
|  | 181 | int Iteration = 0; | 
|  | 182 | do { | 
|  | 183 | Value *V = Worklist.pop_back_val(); | 
|  | 184 |  | 
|  | 185 | // Check if we should process the current value. To prevent endless | 
|  | 186 | // recursion keep a record of the values we followed! | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 187 | if (!Visited.insert(V).second) | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 188 | continue; | 
|  | 189 |  | 
|  | 190 | // Make sure we limit the compile time for complex expressions. | 
|  | 191 | if (Iteration++ >= MaxValues) | 
|  | 192 | return false; | 
|  | 193 |  | 
|  | 194 | // Explicitly look through calls with a "returned" attribute if we do | 
|  | 195 | // not have a pointer as stripPointerCasts only works on them. | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 196 | Value *NewV = nullptr; | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 197 | if (V->getType()->isPointerTy()) { | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 198 | NewV = V->stripPointerCasts(); | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 199 | } else { | 
|  | 200 | CallSite CS(V); | 
|  | 201 | if (CS && CS.getCalledFunction()) { | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 202 | for (Argument &Arg : CS.getCalledFunction()->args()) | 
|  | 203 | if (Arg.hasReturnedAttr()) { | 
|  | 204 | NewV = CS.getArgOperand(Arg.getArgNo()); | 
|  | 205 | break; | 
|  | 206 | } | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 207 | } | 
|  | 208 | } | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 209 | if (NewV && NewV != V) { | 
|  | 210 | Worklist.push_back(NewV); | 
|  | 211 | continue; | 
|  | 212 | } | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 213 |  | 
|  | 214 | // Look through select instructions, visit both potential values. | 
|  | 215 | if (auto *SI = dyn_cast<SelectInst>(V)) { | 
|  | 216 | Worklist.push_back(SI->getTrueValue()); | 
|  | 217 | Worklist.push_back(SI->getFalseValue()); | 
|  | 218 | continue; | 
|  | 219 | } | 
|  | 220 |  | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 221 | // Look through phi nodes, visit all live operands. | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 222 | if (auto *PHI = dyn_cast<PHINode>(V)) { | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 223 | assert(LivenessAA && | 
|  | 224 | "Expected liveness in the presence of instructions!"); | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 225 | for (unsigned u = 0, e = PHI->getNumIncomingValues(); u < e; u++) { | 
|  | 226 | const BasicBlock *IncomingBB = PHI->getIncomingBlock(u); | 
| Johannes Doerfert | 19b0043 | 2019-08-26 17:48:05 +0000 | [diff] [blame] | 227 | if (LivenessAA->isAssumedDead(IncomingBB->getTerminator())) { | 
| Hideto Ueno | f2b9dc4 | 2019-09-07 07:03:05 +0000 | [diff] [blame] | 228 | AnyDead = true; | 
| Johannes Doerfert | 19b0043 | 2019-08-26 17:48:05 +0000 | [diff] [blame] | 229 | continue; | 
|  | 230 | } | 
|  | 231 | Worklist.push_back(PHI->getIncomingValue(u)); | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 232 | } | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 233 | continue; | 
|  | 234 | } | 
|  | 235 |  | 
|  | 236 | // Once a leaf is reached we inform the user through the callback. | 
| Johannes Doerfert | b9b8791 | 2019-08-20 06:02:39 +0000 | [diff] [blame] | 237 | if (!VisitValueCB(*V, State, Iteration > 1)) | 
|  | 238 | return false; | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 239 | } while (!Worklist.empty()); | 
|  | 240 |  | 
| Johannes Doerfert | 19b0043 | 2019-08-26 17:48:05 +0000 | [diff] [blame] | 241 | // If we actually used liveness information so we have to record a dependence. | 
|  | 242 | if (AnyDead) | 
|  | 243 | A.recordDependence(*LivenessAA, QueryingAA); | 
|  | 244 |  | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 245 | // All values have been visited. | 
|  | 246 | return true; | 
|  | 247 | } | 
|  | 248 |  | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 249 | /// Return true if \p New is equal or worse than \p Old. | 
|  | 250 | static bool isEqualOrWorse(const Attribute &New, const Attribute &Old) { | 
|  | 251 | if (!Old.isIntAttribute()) | 
|  | 252 | return true; | 
|  | 253 |  | 
|  | 254 | return Old.getValueAsInt() >= New.getValueAsInt(); | 
|  | 255 | } | 
|  | 256 |  | 
|  | 257 | /// Return true if the information provided by \p Attr was added to the | 
|  | 258 | /// attribute list \p Attrs. This is only the case if it was not already present | 
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 259 | /// in \p Attrs at the position describe by \p PK and \p AttrIdx. | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 260 | static bool addIfNotExistent(LLVMContext &Ctx, const Attribute &Attr, | 
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 261 | AttributeList &Attrs, int AttrIdx) { | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 262 |  | 
|  | 263 | if (Attr.isEnumAttribute()) { | 
|  | 264 | Attribute::AttrKind Kind = Attr.getKindAsEnum(); | 
|  | 265 | if (Attrs.hasAttribute(AttrIdx, Kind)) | 
|  | 266 | if (isEqualOrWorse(Attr, Attrs.getAttribute(AttrIdx, Kind))) | 
|  | 267 | return false; | 
|  | 268 | Attrs = Attrs.addAttribute(Ctx, AttrIdx, Attr); | 
|  | 269 | return true; | 
|  | 270 | } | 
|  | 271 | if (Attr.isStringAttribute()) { | 
|  | 272 | StringRef Kind = Attr.getKindAsString(); | 
|  | 273 | if (Attrs.hasAttribute(AttrIdx, Kind)) | 
|  | 274 | if (isEqualOrWorse(Attr, Attrs.getAttribute(AttrIdx, Kind))) | 
|  | 275 | return false; | 
|  | 276 | Attrs = Attrs.addAttribute(Ctx, AttrIdx, Attr); | 
|  | 277 | return true; | 
|  | 278 | } | 
| Hideto Ueno | 19c07af | 2019-07-23 08:16:17 +0000 | [diff] [blame] | 279 | if (Attr.isIntAttribute()) { | 
|  | 280 | Attribute::AttrKind Kind = Attr.getKindAsEnum(); | 
|  | 281 | if (Attrs.hasAttribute(AttrIdx, Kind)) | 
|  | 282 | if (isEqualOrWorse(Attr, Attrs.getAttribute(AttrIdx, Kind))) | 
|  | 283 | return false; | 
|  | 284 | Attrs = Attrs.removeAttribute(Ctx, AttrIdx, Kind); | 
|  | 285 | Attrs = Attrs.addAttribute(Ctx, AttrIdx, Attr); | 
|  | 286 | return true; | 
|  | 287 | } | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 288 |  | 
|  | 289 | llvm_unreachable("Expected enum or string attribute!"); | 
|  | 290 | } | 
|  | 291 |  | 
| Johannes Doerfert | ece8190 | 2019-08-12 22:05:53 +0000 | [diff] [blame] | 292 | ChangeStatus AbstractAttribute::update(Attributor &A) { | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 293 | ChangeStatus HasChanged = ChangeStatus::UNCHANGED; | 
|  | 294 | if (getState().isAtFixpoint()) | 
|  | 295 | return HasChanged; | 
|  | 296 |  | 
|  | 297 | LLVM_DEBUG(dbgs() << "[Attributor] Update: " << *this << "\n"); | 
|  | 298 |  | 
| Johannes Doerfert | ece8190 | 2019-08-12 22:05:53 +0000 | [diff] [blame] | 299 | HasChanged = updateImpl(A); | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 300 |  | 
|  | 301 | LLVM_DEBUG(dbgs() << "[Attributor] Update " << HasChanged << " " << *this | 
|  | 302 | << "\n"); | 
|  | 303 |  | 
|  | 304 | return HasChanged; | 
|  | 305 | } | 
|  | 306 |  | 
| Johannes Doerfert | d1b79e0 | 2019-08-07 22:46:11 +0000 | [diff] [blame] | 307 | ChangeStatus | 
|  | 308 | IRAttributeManifest::manifestAttrs(Attributor &A, IRPosition &IRP, | 
|  | 309 | const ArrayRef<Attribute> &DeducedAttrs) { | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 310 | Function *ScopeFn = IRP.getAssociatedFunction(); | 
| Kristina Brooks | 26e60f0 | 2019-08-06 19:53:19 +0000 | [diff] [blame] | 311 | IRPosition::Kind PK = IRP.getPositionKind(); | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 312 |  | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 313 | // In the following some generic code that will manifest attributes in | 
|  | 314 | // DeducedAttrs if they improve the current IR. Due to the different | 
|  | 315 | // annotation positions we use the underlying AttributeList interface. | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 316 |  | 
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 317 | AttributeList Attrs; | 
|  | 318 | switch (PK) { | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 319 | case IRPosition::IRP_INVALID: | 
|  | 320 | case IRPosition::IRP_FLOAT: | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 321 | return ChangeStatus::UNCHANGED; | 
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 322 | case IRPosition::IRP_ARGUMENT: | 
|  | 323 | case IRPosition::IRP_FUNCTION: | 
|  | 324 | case IRPosition::IRP_RETURNED: | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 325 | Attrs = ScopeFn->getAttributes(); | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 326 | break; | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 327 | case IRPosition::IRP_CALL_SITE: | 
|  | 328 | case IRPosition::IRP_CALL_SITE_RETURNED: | 
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 329 | case IRPosition::IRP_CALL_SITE_ARGUMENT: | 
| Kristina Brooks | 26e60f0 | 2019-08-06 19:53:19 +0000 | [diff] [blame] | 330 | Attrs = ImmutableCallSite(&IRP.getAnchorValue()).getAttributes(); | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 331 | break; | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 332 | } | 
|  | 333 |  | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 334 | ChangeStatus HasChanged = ChangeStatus::UNCHANGED; | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 335 | LLVMContext &Ctx = IRP.getAnchorValue().getContext(); | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 336 | for (const Attribute &Attr : DeducedAttrs) { | 
| Kristina Brooks | 26e60f0 | 2019-08-06 19:53:19 +0000 | [diff] [blame] | 337 | if (!addIfNotExistent(Ctx, Attr, Attrs, IRP.getAttrIdx())) | 
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 338 | continue; | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 339 |  | 
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 340 | HasChanged = ChangeStatus::CHANGED; | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 341 | } | 
|  | 342 |  | 
|  | 343 | if (HasChanged == ChangeStatus::UNCHANGED) | 
|  | 344 | return HasChanged; | 
|  | 345 |  | 
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 346 | switch (PK) { | 
|  | 347 | case IRPosition::IRP_ARGUMENT: | 
|  | 348 | case IRPosition::IRP_FUNCTION: | 
|  | 349 | case IRPosition::IRP_RETURNED: | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 350 | ScopeFn->setAttributes(Attrs); | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 351 | break; | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 352 | case IRPosition::IRP_CALL_SITE: | 
|  | 353 | case IRPosition::IRP_CALL_SITE_RETURNED: | 
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 354 | case IRPosition::IRP_CALL_SITE_ARGUMENT: | 
| Kristina Brooks | 26e60f0 | 2019-08-06 19:53:19 +0000 | [diff] [blame] | 355 | CallSite(&IRP.getAnchorValue()).setAttributes(Attrs); | 
| Johannes Doerfert | 4395b31 | 2019-08-14 21:46:28 +0000 | [diff] [blame] | 356 | break; | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 357 | case IRPosition::IRP_INVALID: | 
| Johannes Doerfert | 4395b31 | 2019-08-14 21:46:28 +0000 | [diff] [blame] | 358 | case IRPosition::IRP_FLOAT: | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 359 | break; | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 360 | } | 
|  | 361 |  | 
|  | 362 | return HasChanged; | 
|  | 363 | } | 
|  | 364 |  | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 365 | const IRPosition IRPosition::EmptyKey(255); | 
|  | 366 | const IRPosition IRPosition::TombstoneKey(256); | 
|  | 367 |  | 
|  | 368 | SubsumingPositionIterator::SubsumingPositionIterator(const IRPosition &IRP) { | 
|  | 369 | IRPositions.emplace_back(IRP); | 
|  | 370 |  | 
|  | 371 | ImmutableCallSite ICS(&IRP.getAnchorValue()); | 
|  | 372 | switch (IRP.getPositionKind()) { | 
|  | 373 | case IRPosition::IRP_INVALID: | 
|  | 374 | case IRPosition::IRP_FLOAT: | 
|  | 375 | case IRPosition::IRP_FUNCTION: | 
|  | 376 | return; | 
|  | 377 | case IRPosition::IRP_ARGUMENT: | 
|  | 378 | case IRPosition::IRP_RETURNED: | 
|  | 379 | IRPositions.emplace_back( | 
|  | 380 | IRPosition::function(*IRP.getAssociatedFunction())); | 
|  | 381 | return; | 
|  | 382 | case IRPosition::IRP_CALL_SITE: | 
|  | 383 | assert(ICS && "Expected call site!"); | 
|  | 384 | // TODO: We need to look at the operand bundles similar to the redirection | 
|  | 385 | //       in CallBase. | 
|  | 386 | if (!ICS.hasOperandBundles()) | 
|  | 387 | if (const Function *Callee = ICS.getCalledFunction()) | 
|  | 388 | IRPositions.emplace_back(IRPosition::function(*Callee)); | 
|  | 389 | return; | 
|  | 390 | case IRPosition::IRP_CALL_SITE_RETURNED: | 
|  | 391 | assert(ICS && "Expected call site!"); | 
|  | 392 | // TODO: We need to look at the operand bundles similar to the redirection | 
|  | 393 | //       in CallBase. | 
|  | 394 | if (!ICS.hasOperandBundles()) { | 
|  | 395 | if (const Function *Callee = ICS.getCalledFunction()) { | 
|  | 396 | IRPositions.emplace_back(IRPosition::returned(*Callee)); | 
|  | 397 | IRPositions.emplace_back(IRPosition::function(*Callee)); | 
|  | 398 | } | 
|  | 399 | } | 
|  | 400 | IRPositions.emplace_back( | 
|  | 401 | IRPosition::callsite_function(cast<CallBase>(*ICS.getInstruction()))); | 
|  | 402 | return; | 
|  | 403 | case IRPosition::IRP_CALL_SITE_ARGUMENT: { | 
|  | 404 | int ArgNo = IRP.getArgNo(); | 
|  | 405 | assert(ICS && ArgNo >= 0 && "Expected call site!"); | 
|  | 406 | // TODO: We need to look at the operand bundles similar to the redirection | 
|  | 407 | //       in CallBase. | 
|  | 408 | if (!ICS.hasOperandBundles()) { | 
|  | 409 | const Function *Callee = ICS.getCalledFunction(); | 
|  | 410 | if (Callee && Callee->arg_size() > unsigned(ArgNo)) | 
|  | 411 | IRPositions.emplace_back(IRPosition::argument(*Callee->getArg(ArgNo))); | 
|  | 412 | if (Callee) | 
|  | 413 | IRPositions.emplace_back(IRPosition::function(*Callee)); | 
|  | 414 | } | 
|  | 415 | IRPositions.emplace_back(IRPosition::value(IRP.getAssociatedValue())); | 
|  | 416 | return; | 
|  | 417 | } | 
|  | 418 | } | 
|  | 419 | } | 
|  | 420 |  | 
|  | 421 | bool IRPosition::hasAttr(ArrayRef<Attribute::AttrKind> AKs) const { | 
|  | 422 | for (const IRPosition &EquivIRP : SubsumingPositionIterator(*this)) | 
|  | 423 | for (Attribute::AttrKind AK : AKs) | 
|  | 424 | if (EquivIRP.getAttr(AK).getKindAsEnum() == AK) | 
|  | 425 | return true; | 
|  | 426 | return false; | 
|  | 427 | } | 
|  | 428 |  | 
|  | 429 | void IRPosition::getAttrs(ArrayRef<Attribute::AttrKind> AKs, | 
|  | 430 | SmallVectorImpl<Attribute> &Attrs) const { | 
|  | 431 | for (const IRPosition &EquivIRP : SubsumingPositionIterator(*this)) | 
|  | 432 | for (Attribute::AttrKind AK : AKs) { | 
|  | 433 | const Attribute &Attr = EquivIRP.getAttr(AK); | 
|  | 434 | if (Attr.getKindAsEnum() == AK) | 
|  | 435 | Attrs.push_back(Attr); | 
|  | 436 | } | 
|  | 437 | } | 
|  | 438 |  | 
|  | 439 | void IRPosition::verify() { | 
|  | 440 | switch (KindOrArgNo) { | 
|  | 441 | default: | 
|  | 442 | assert(KindOrArgNo >= 0 && "Expected argument or call site argument!"); | 
|  | 443 | assert((isa<CallBase>(AnchorVal) || isa<Argument>(AnchorVal)) && | 
|  | 444 | "Expected call base or argument for positive attribute index!"); | 
| Simon Pilgrim | 920b040 | 2019-08-29 10:08:45 +0000 | [diff] [blame] | 445 | if (isa<Argument>(AnchorVal)) { | 
|  | 446 | assert(cast<Argument>(AnchorVal)->getArgNo() == unsigned(getArgNo()) && | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 447 | "Argument number mismatch!"); | 
| Simon Pilgrim | 920b040 | 2019-08-29 10:08:45 +0000 | [diff] [blame] | 448 | assert(cast<Argument>(AnchorVal) == &getAssociatedValue() && | 
|  | 449 | "Associated value mismatch!"); | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 450 | } else { | 
| Simon Pilgrim | 920b040 | 2019-08-29 10:08:45 +0000 | [diff] [blame] | 451 | assert(cast<CallBase>(*AnchorVal).arg_size() > unsigned(getArgNo()) && | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 452 | "Call site argument number mismatch!"); | 
| Simon Pilgrim | 920b040 | 2019-08-29 10:08:45 +0000 | [diff] [blame] | 453 | assert(cast<CallBase>(*AnchorVal).getArgOperand(getArgNo()) == | 
|  | 454 | &getAssociatedValue() && | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 455 | "Associated value mismatch!"); | 
|  | 456 | } | 
|  | 457 | break; | 
|  | 458 | case IRP_INVALID: | 
|  | 459 | assert(!AnchorVal && "Expected no value for an invalid position!"); | 
|  | 460 | break; | 
|  | 461 | case IRP_FLOAT: | 
|  | 462 | assert((!isa<CallBase>(&getAssociatedValue()) && | 
|  | 463 | !isa<Argument>(&getAssociatedValue())) && | 
|  | 464 | "Expected specialized kind for call base and argument values!"); | 
|  | 465 | break; | 
|  | 466 | case IRP_RETURNED: | 
|  | 467 | assert(isa<Function>(AnchorVal) && | 
|  | 468 | "Expected function for a 'returned' position!"); | 
|  | 469 | assert(AnchorVal == &getAssociatedValue() && "Associated value mismatch!"); | 
|  | 470 | break; | 
|  | 471 | case IRP_CALL_SITE_RETURNED: | 
|  | 472 | assert((isa<CallBase>(AnchorVal)) && | 
|  | 473 | "Expected call base for 'call site returned' position!"); | 
|  | 474 | assert(AnchorVal == &getAssociatedValue() && "Associated value mismatch!"); | 
|  | 475 | break; | 
|  | 476 | case IRP_CALL_SITE: | 
|  | 477 | assert((isa<CallBase>(AnchorVal)) && | 
|  | 478 | "Expected call base for 'call site function' position!"); | 
|  | 479 | assert(AnchorVal == &getAssociatedValue() && "Associated value mismatch!"); | 
|  | 480 | break; | 
|  | 481 | case IRP_FUNCTION: | 
|  | 482 | assert(isa<Function>(AnchorVal) && | 
|  | 483 | "Expected function for a 'function' position!"); | 
|  | 484 | assert(AnchorVal == &getAssociatedValue() && "Associated value mismatch!"); | 
|  | 485 | break; | 
|  | 486 | } | 
|  | 487 | } | 
|  | 488 |  | 
| Johannes Doerfert | 234eda5 | 2019-08-16 19:51:23 +0000 | [diff] [blame] | 489 | /// Helper functions to clamp a state \p S of type \p StateType with the | 
|  | 490 | /// information in \p R and indicate/return if \p S did change (as-in update is | 
|  | 491 | /// required to be run again). | 
|  | 492 | /// | 
|  | 493 | ///{ | 
|  | 494 | template <typename StateType> | 
|  | 495 | ChangeStatus clampStateAndIndicateChange(StateType &S, const StateType &R); | 
|  | 496 |  | 
|  | 497 | template <> | 
|  | 498 | ChangeStatus clampStateAndIndicateChange<IntegerState>(IntegerState &S, | 
|  | 499 | const IntegerState &R) { | 
|  | 500 | auto Assumed = S.getAssumed(); | 
|  | 501 | S ^= R; | 
|  | 502 | return Assumed == S.getAssumed() ? ChangeStatus::UNCHANGED | 
|  | 503 | : ChangeStatus::CHANGED; | 
|  | 504 | } | 
| Johannes Doerfert | b9b8791 | 2019-08-20 06:02:39 +0000 | [diff] [blame] | 505 |  | 
|  | 506 | template <> | 
|  | 507 | ChangeStatus clampStateAndIndicateChange<BooleanState>(BooleanState &S, | 
|  | 508 | const BooleanState &R) { | 
|  | 509 | return clampStateAndIndicateChange<IntegerState>(S, R); | 
|  | 510 | } | 
| Johannes Doerfert | 234eda5 | 2019-08-16 19:51:23 +0000 | [diff] [blame] | 511 | ///} | 
|  | 512 |  | 
|  | 513 | /// Clamp the information known for all returned values of a function | 
|  | 514 | /// (identified by \p QueryingAA) into \p S. | 
|  | 515 | template <typename AAType, typename StateType = typename AAType::StateType> | 
|  | 516 | static void clampReturnedValueStates(Attributor &A, const AAType &QueryingAA, | 
|  | 517 | StateType &S) { | 
|  | 518 | LLVM_DEBUG(dbgs() << "[Attributor] Clamp return value states for " | 
|  | 519 | << static_cast<const AbstractAttribute &>(QueryingAA) | 
|  | 520 | << " into " << S << "\n"); | 
|  | 521 |  | 
|  | 522 | assert((QueryingAA.getIRPosition().getPositionKind() == | 
|  | 523 | IRPosition::IRP_RETURNED || | 
|  | 524 | QueryingAA.getIRPosition().getPositionKind() == | 
|  | 525 | IRPosition::IRP_CALL_SITE_RETURNED) && | 
|  | 526 | "Can only clamp returned value states for a function returned or call " | 
|  | 527 | "site returned position!"); | 
|  | 528 |  | 
|  | 529 | // Use an optional state as there might not be any return values and we want | 
|  | 530 | // to join (IntegerState::operator&) the state of all there are. | 
|  | 531 | Optional<StateType> T; | 
|  | 532 |  | 
|  | 533 | // Callback for each possibly returned value. | 
|  | 534 | auto CheckReturnValue = [&](Value &RV) -> bool { | 
|  | 535 | const IRPosition &RVPos = IRPosition::value(RV); | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 536 | const AAType &AA = A.getAAFor<AAType>(QueryingAA, RVPos); | 
|  | 537 | LLVM_DEBUG(dbgs() << "[Attributor] RV: " << RV << " AA: " << AA.getAsStr() | 
|  | 538 | << " @ " << RVPos << "\n"); | 
|  | 539 | const StateType &AAS = static_cast<const StateType &>(AA.getState()); | 
| Johannes Doerfert | 234eda5 | 2019-08-16 19:51:23 +0000 | [diff] [blame] | 540 | if (T.hasValue()) | 
|  | 541 | *T &= AAS; | 
|  | 542 | else | 
|  | 543 | T = AAS; | 
|  | 544 | LLVM_DEBUG(dbgs() << "[Attributor] AA State: " << AAS << " RV State: " << T | 
|  | 545 | << "\n"); | 
|  | 546 | return T->isValidState(); | 
|  | 547 | }; | 
|  | 548 |  | 
|  | 549 | if (!A.checkForAllReturnedValues(CheckReturnValue, QueryingAA)) | 
|  | 550 | S.indicatePessimisticFixpoint(); | 
|  | 551 | else if (T.hasValue()) | 
|  | 552 | S ^= *T; | 
|  | 553 | } | 
|  | 554 |  | 
|  | 555 | /// Helper class for generic deduction: return value -> returned position. | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 556 | template <typename AAType, typename Base, | 
|  | 557 | typename StateType = typename AAType::StateType> | 
|  | 558 | struct AAReturnedFromReturnedValues : public Base { | 
|  | 559 | AAReturnedFromReturnedValues(const IRPosition &IRP) : Base(IRP) {} | 
| Johannes Doerfert | 234eda5 | 2019-08-16 19:51:23 +0000 | [diff] [blame] | 560 |  | 
|  | 561 | /// See AbstractAttribute::updateImpl(...). | 
|  | 562 | ChangeStatus updateImpl(Attributor &A) override { | 
|  | 563 | StateType S; | 
|  | 564 | clampReturnedValueStates<AAType, StateType>(A, *this, S); | 
| Johannes Doerfert | 028b2aa | 2019-08-20 05:57:01 +0000 | [diff] [blame] | 565 | // TODO: If we know we visited all returned values, thus no are assumed | 
|  | 566 | // dead, we can take the known information from the state T. | 
| Johannes Doerfert | 234eda5 | 2019-08-16 19:51:23 +0000 | [diff] [blame] | 567 | return clampStateAndIndicateChange<StateType>(this->getState(), S); | 
|  | 568 | } | 
|  | 569 | }; | 
|  | 570 |  | 
|  | 571 | /// Clamp the information known at all call sites for a given argument | 
|  | 572 | /// (identified by \p QueryingAA) into \p S. | 
|  | 573 | template <typename AAType, typename StateType = typename AAType::StateType> | 
|  | 574 | static void clampCallSiteArgumentStates(Attributor &A, const AAType &QueryingAA, | 
|  | 575 | StateType &S) { | 
|  | 576 | LLVM_DEBUG(dbgs() << "[Attributor] Clamp call site argument states for " | 
|  | 577 | << static_cast<const AbstractAttribute &>(QueryingAA) | 
|  | 578 | << " into " << S << "\n"); | 
|  | 579 |  | 
|  | 580 | assert(QueryingAA.getIRPosition().getPositionKind() == | 
|  | 581 | IRPosition::IRP_ARGUMENT && | 
|  | 582 | "Can only clamp call site argument states for an argument position!"); | 
|  | 583 |  | 
|  | 584 | // Use an optional state as there might not be any return values and we want | 
|  | 585 | // to join (IntegerState::operator&) the state of all there are. | 
|  | 586 | Optional<StateType> T; | 
|  | 587 |  | 
|  | 588 | // The argument number which is also the call site argument number. | 
|  | 589 | unsigned ArgNo = QueryingAA.getIRPosition().getArgNo(); | 
|  | 590 |  | 
|  | 591 | auto CallSiteCheck = [&](CallSite CS) { | 
|  | 592 | const IRPosition &CSArgPos = IRPosition::callsite_argument(CS, ArgNo); | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 593 | const AAType &AA = A.getAAFor<AAType>(QueryingAA, CSArgPos); | 
| Johannes Doerfert | 234eda5 | 2019-08-16 19:51:23 +0000 | [diff] [blame] | 594 | LLVM_DEBUG(dbgs() << "[Attributor] CS: " << *CS.getInstruction() | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 595 | << " AA: " << AA.getAsStr() << " @" << CSArgPos << "\n"); | 
|  | 596 | const StateType &AAS = static_cast<const StateType &>(AA.getState()); | 
| Johannes Doerfert | 234eda5 | 2019-08-16 19:51:23 +0000 | [diff] [blame] | 597 | if (T.hasValue()) | 
|  | 598 | *T &= AAS; | 
|  | 599 | else | 
|  | 600 | T = AAS; | 
|  | 601 | LLVM_DEBUG(dbgs() << "[Attributor] AA State: " << AAS << " CSA State: " << T | 
|  | 602 | << "\n"); | 
|  | 603 | return T->isValidState(); | 
|  | 604 | }; | 
|  | 605 |  | 
|  | 606 | if (!A.checkForAllCallSites(CallSiteCheck, QueryingAA, true)) | 
|  | 607 | S.indicatePessimisticFixpoint(); | 
|  | 608 | else if (T.hasValue()) | 
|  | 609 | S ^= *T; | 
|  | 610 | } | 
|  | 611 |  | 
|  | 612 | /// Helper class for generic deduction: call site argument -> argument position. | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 613 | template <typename AAType, typename Base, | 
|  | 614 | typename StateType = typename AAType::StateType> | 
|  | 615 | struct AAArgumentFromCallSiteArguments : public Base { | 
|  | 616 | AAArgumentFromCallSiteArguments(const IRPosition &IRP) : Base(IRP) {} | 
| Johannes Doerfert | 234eda5 | 2019-08-16 19:51:23 +0000 | [diff] [blame] | 617 |  | 
|  | 618 | /// See AbstractAttribute::updateImpl(...). | 
|  | 619 | ChangeStatus updateImpl(Attributor &A) override { | 
|  | 620 | StateType S; | 
|  | 621 | clampCallSiteArgumentStates<AAType, StateType>(A, *this, S); | 
| Johannes Doerfert | 028b2aa | 2019-08-20 05:57:01 +0000 | [diff] [blame] | 622 | // TODO: If we know we visited all incoming values, thus no are assumed | 
|  | 623 | // dead, we can take the known information from the state T. | 
| Johannes Doerfert | 234eda5 | 2019-08-16 19:51:23 +0000 | [diff] [blame] | 624 | return clampStateAndIndicateChange<StateType>(this->getState(), S); | 
|  | 625 | } | 
|  | 626 | }; | 
|  | 627 |  | 
|  | 628 | /// Helper class for generic replication: function returned -> cs returned. | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 629 | template <typename AAType, typename Base> | 
|  | 630 | struct AACallSiteReturnedFromReturned : public Base { | 
|  | 631 | AACallSiteReturnedFromReturned(const IRPosition &IRP) : Base(IRP) {} | 
| Johannes Doerfert | 234eda5 | 2019-08-16 19:51:23 +0000 | [diff] [blame] | 632 |  | 
|  | 633 | /// See AbstractAttribute::updateImpl(...). | 
|  | 634 | ChangeStatus updateImpl(Attributor &A) override { | 
|  | 635 | assert(this->getIRPosition().getPositionKind() == | 
|  | 636 | IRPosition::IRP_CALL_SITE_RETURNED && | 
|  | 637 | "Can only wrap function returned positions for call site returned " | 
|  | 638 | "positions!"); | 
|  | 639 | auto &S = this->getState(); | 
|  | 640 |  | 
|  | 641 | const Function *AssociatedFunction = | 
|  | 642 | this->getIRPosition().getAssociatedFunction(); | 
|  | 643 | if (!AssociatedFunction) | 
|  | 644 | return S.indicatePessimisticFixpoint(); | 
|  | 645 |  | 
|  | 646 | IRPosition FnPos = IRPosition::returned(*AssociatedFunction); | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 647 | const AAType &AA = A.getAAFor<AAType>(*this, FnPos); | 
| Johannes Doerfert | 234eda5 | 2019-08-16 19:51:23 +0000 | [diff] [blame] | 648 | return clampStateAndIndicateChange( | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 649 | S, static_cast<const typename AAType::StateType &>(AA.getState())); | 
| Johannes Doerfert | 234eda5 | 2019-08-16 19:51:23 +0000 | [diff] [blame] | 650 | } | 
|  | 651 | }; | 
|  | 652 |  | 
| Stefan Stipanovic | 5360589 | 2019-06-27 11:27:54 +0000 | [diff] [blame] | 653 | /// -----------------------NoUnwind Function Attribute-------------------------- | 
|  | 654 |  | 
| Johannes Doerfert | 344d038 | 2019-08-07 22:34:26 +0000 | [diff] [blame] | 655 | struct AANoUnwindImpl : AANoUnwind { | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 656 | AANoUnwindImpl(const IRPosition &IRP) : AANoUnwind(IRP) {} | 
| Stefan Stipanovic | 5360589 | 2019-06-27 11:27:54 +0000 | [diff] [blame] | 657 |  | 
| Stefan Stipanovic | 15e86f7 | 2019-07-12 17:42:14 +0000 | [diff] [blame] | 658 | const std::string getAsStr() const override { | 
| Stefan Stipanovic | 5360589 | 2019-06-27 11:27:54 +0000 | [diff] [blame] | 659 | return getAssumed() ? "nounwind" : "may-unwind"; | 
|  | 660 | } | 
|  | 661 |  | 
|  | 662 | /// See AbstractAttribute::updateImpl(...). | 
| Johannes Doerfert | fe6dbad | 2019-08-16 19:36:17 +0000 | [diff] [blame] | 663 | ChangeStatus updateImpl(Attributor &A) override { | 
|  | 664 | auto Opcodes = { | 
|  | 665 | (unsigned)Instruction::Invoke,      (unsigned)Instruction::CallBr, | 
|  | 666 | (unsigned)Instruction::Call,        (unsigned)Instruction::CleanupRet, | 
|  | 667 | (unsigned)Instruction::CatchSwitch, (unsigned)Instruction::Resume}; | 
|  | 668 |  | 
|  | 669 | auto CheckForNoUnwind = [&](Instruction &I) { | 
|  | 670 | if (!I.mayThrow()) | 
|  | 671 | return true; | 
|  | 672 |  | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 673 | if (ImmutableCallSite ICS = ImmutableCallSite(&I)) { | 
|  | 674 | const auto &NoUnwindAA = | 
|  | 675 | A.getAAFor<AANoUnwind>(*this, IRPosition::callsite_function(ICS)); | 
|  | 676 | return NoUnwindAA.isAssumedNoUnwind(); | 
|  | 677 | } | 
|  | 678 | return false; | 
| Johannes Doerfert | fe6dbad | 2019-08-16 19:36:17 +0000 | [diff] [blame] | 679 | }; | 
|  | 680 |  | 
|  | 681 | if (!A.checkForAllInstructions(CheckForNoUnwind, *this, Opcodes)) | 
|  | 682 | return indicatePessimisticFixpoint(); | 
|  | 683 |  | 
|  | 684 | return ChangeStatus::UNCHANGED; | 
|  | 685 | } | 
| Stefan Stipanovic | 5360589 | 2019-06-27 11:27:54 +0000 | [diff] [blame] | 686 | }; | 
|  | 687 |  | 
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 688 | struct AANoUnwindFunction final : public AANoUnwindImpl { | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 689 | AANoUnwindFunction(const IRPosition &IRP) : AANoUnwindImpl(IRP) {} | 
| Johannes Doerfert | d1b79e0 | 2019-08-07 22:46:11 +0000 | [diff] [blame] | 690 |  | 
|  | 691 | /// See AbstractAttribute::trackStatistics() | 
| Johannes Doerfert | 17b578b | 2019-08-14 21:46:25 +0000 | [diff] [blame] | 692 | void trackStatistics() const override { STATS_DECLTRACK_FN_ATTR(nounwind) } | 
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 693 | }; | 
|  | 694 |  | 
| Johannes Doerfert | 66cf87e | 2019-08-16 19:49:00 +0000 | [diff] [blame] | 695 | /// NoUnwind attribute deduction for a call sites. | 
| Johannes Doerfert | 3fac668 | 2019-08-30 15:24:52 +0000 | [diff] [blame] | 696 | struct AANoUnwindCallSite final : AANoUnwindImpl { | 
|  | 697 | AANoUnwindCallSite(const IRPosition &IRP) : AANoUnwindImpl(IRP) {} | 
|  | 698 |  | 
|  | 699 | /// See AbstractAttribute::initialize(...). | 
|  | 700 | void initialize(Attributor &A) override { | 
|  | 701 | AANoUnwindImpl::initialize(A); | 
|  | 702 | Function *F = getAssociatedFunction(); | 
| Johannes Doerfert | b0412e4 | 2019-09-04 16:16:13 +0000 | [diff] [blame] | 703 | if (!F) | 
| Johannes Doerfert | 3fac668 | 2019-08-30 15:24:52 +0000 | [diff] [blame] | 704 | indicatePessimisticFixpoint(); | 
|  | 705 | } | 
|  | 706 |  | 
|  | 707 | /// See AbstractAttribute::updateImpl(...). | 
|  | 708 | ChangeStatus updateImpl(Attributor &A) override { | 
|  | 709 | // TODO: Once we have call site specific value information we can provide | 
|  | 710 | //       call site specific liveness information and then it makes | 
|  | 711 | //       sense to specialize attributes for call sites arguments instead of | 
|  | 712 | //       redirecting requests to the callee argument. | 
|  | 713 | Function *F = getAssociatedFunction(); | 
|  | 714 | const IRPosition &FnPos = IRPosition::function(*F); | 
|  | 715 | auto &FnAA = A.getAAFor<AANoUnwind>(*this, FnPos); | 
|  | 716 | return clampStateAndIndicateChange( | 
|  | 717 | getState(), | 
|  | 718 | static_cast<const AANoUnwind::StateType &>(FnAA.getState())); | 
|  | 719 | } | 
|  | 720 |  | 
|  | 721 | /// See AbstractAttribute::trackStatistics() | 
|  | 722 | void trackStatistics() const override { STATS_DECLTRACK_CS_ATTR(nounwind); } | 
|  | 723 | }; | 
| Johannes Doerfert | 66cf87e | 2019-08-16 19:49:00 +0000 | [diff] [blame] | 724 |  | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 725 | /// --------------------- Function Return Values ------------------------------- | 
|  | 726 |  | 
|  | 727 | /// "Attribute" that collects all potential returned values and the return | 
|  | 728 | /// instructions that they arise from. | 
|  | 729 | /// | 
|  | 730 | /// If there is a unique returned value R, the manifest method will: | 
|  | 731 | ///   - mark R with the "returned" attribute, if R is an argument. | 
| Johannes Doerfert | eccdf08 | 2019-08-05 23:35:12 +0000 | [diff] [blame] | 732 | class AAReturnedValuesImpl : public AAReturnedValues, public AbstractState { | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 733 |  | 
|  | 734 | /// Mapping of values potentially returned by the associated function to the | 
|  | 735 | /// return instructions that might return them. | 
| Johannes Doerfert | a4a308c | 2019-08-26 17:51:23 +0000 | [diff] [blame] | 736 | MapVector<Value *, SmallSetVector<ReturnInst *, 4>> ReturnedValues; | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 737 |  | 
| Johannes Doerfert | deb9ea3 | 2019-08-23 15:42:19 +0000 | [diff] [blame] | 738 | /// Mapping to remember the number of returned values for a call site such | 
|  | 739 | /// that we can avoid updates if nothing changed. | 
|  | 740 | DenseMap<const CallBase *, unsigned> NumReturnedValuesPerKnownAA; | 
|  | 741 |  | 
|  | 742 | /// Set of unresolved calls returned by the associated function. | 
| Johannes Doerfert | 695089e | 2019-08-23 15:23:49 +0000 | [diff] [blame] | 743 | SmallSetVector<CallBase *, 4> UnresolvedCalls; | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 744 |  | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 745 | /// State flags | 
|  | 746 | /// | 
|  | 747 | ///{ | 
| Johannes Doerfert | deb9ea3 | 2019-08-23 15:42:19 +0000 | [diff] [blame] | 748 | bool IsFixed = false; | 
|  | 749 | bool IsValidState = true; | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 750 | ///} | 
|  | 751 |  | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 752 | public: | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 753 | AAReturnedValuesImpl(const IRPosition &IRP) : AAReturnedValues(IRP) {} | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 754 |  | 
|  | 755 | /// See AbstractAttribute::initialize(...). | 
| Johannes Doerfert | ece8190 | 2019-08-12 22:05:53 +0000 | [diff] [blame] | 756 | void initialize(Attributor &A) override { | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 757 | // Reset the state. | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 758 | IsFixed = false; | 
|  | 759 | IsValidState = true; | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 760 | ReturnedValues.clear(); | 
|  | 761 |  | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 762 | Function *F = getAssociatedFunction(); | 
| Johannes Doerfert | b0412e4 | 2019-09-04 16:16:13 +0000 | [diff] [blame] | 763 | if (!F) { | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 764 | indicatePessimisticFixpoint(); | 
|  | 765 | return; | 
|  | 766 | } | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 767 |  | 
|  | 768 | // The map from instruction opcodes to those instructions in the function. | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 769 | auto &OpcodeInstMap = A.getInfoCache().getOpcodeInstMapForFunction(*F); | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 770 |  | 
|  | 771 | // Look through all arguments, if one is marked as returned we are done. | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 772 | for (Argument &Arg : F->args()) { | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 773 | if (Arg.hasReturnedAttr()) { | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 774 | auto &ReturnInstSet = ReturnedValues[&Arg]; | 
|  | 775 | for (Instruction *RI : OpcodeInstMap[Instruction::Ret]) | 
|  | 776 | ReturnInstSet.insert(cast<ReturnInst>(RI)); | 
|  | 777 |  | 
|  | 778 | indicateOptimisticFixpoint(); | 
|  | 779 | return; | 
|  | 780 | } | 
|  | 781 | } | 
| Johannes Doerfert | b0412e4 | 2019-09-04 16:16:13 +0000 | [diff] [blame] | 782 |  | 
|  | 783 | if (!F->hasExactDefinition()) | 
|  | 784 | indicatePessimisticFixpoint(); | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 785 | } | 
|  | 786 |  | 
|  | 787 | /// See AbstractAttribute::manifest(...). | 
| Stefan Stipanovic | 15e86f7 | 2019-07-12 17:42:14 +0000 | [diff] [blame] | 788 | ChangeStatus manifest(Attributor &A) override; | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 789 |  | 
|  | 790 | /// See AbstractAttribute::getState(...). | 
| Stefan Stipanovic | 15e86f7 | 2019-07-12 17:42:14 +0000 | [diff] [blame] | 791 | AbstractState &getState() override { return *this; } | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 792 |  | 
|  | 793 | /// See AbstractAttribute::getState(...). | 
| Stefan Stipanovic | 15e86f7 | 2019-07-12 17:42:14 +0000 | [diff] [blame] | 794 | const AbstractState &getState() const override { return *this; } | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 795 |  | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 796 | /// See AbstractAttribute::updateImpl(Attributor &A). | 
| Johannes Doerfert | ece8190 | 2019-08-12 22:05:53 +0000 | [diff] [blame] | 797 | ChangeStatus updateImpl(Attributor &A) override; | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 798 |  | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 799 | llvm::iterator_range<iterator> returned_values() override { | 
|  | 800 | return llvm::make_range(ReturnedValues.begin(), ReturnedValues.end()); | 
|  | 801 | } | 
|  | 802 |  | 
|  | 803 | llvm::iterator_range<const_iterator> returned_values() const override { | 
|  | 804 | return llvm::make_range(ReturnedValues.begin(), ReturnedValues.end()); | 
|  | 805 | } | 
|  | 806 |  | 
| Johannes Doerfert | 695089e | 2019-08-23 15:23:49 +0000 | [diff] [blame] | 807 | const SmallSetVector<CallBase *, 4> &getUnresolvedCalls() const override { | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 808 | return UnresolvedCalls; | 
|  | 809 | } | 
|  | 810 |  | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 811 | /// Return the number of potential return values, -1 if unknown. | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 812 | size_t getNumReturnValues() const override { | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 813 | return isValidState() ? ReturnedValues.size() : -1; | 
|  | 814 | } | 
|  | 815 |  | 
|  | 816 | /// Return an assumed unique return value if a single candidate is found. If | 
|  | 817 | /// there cannot be one, return a nullptr. If it is not clear yet, return the | 
|  | 818 | /// Optional::NoneType. | 
| Johannes Doerfert | 14a0493 | 2019-08-07 22:27:24 +0000 | [diff] [blame] | 819 | Optional<Value *> getAssumedUniqueReturnValue(Attributor &A) const; | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 820 |  | 
| Johannes Doerfert | 14a0493 | 2019-08-07 22:27:24 +0000 | [diff] [blame] | 821 | /// See AbstractState::checkForAllReturnedValues(...). | 
|  | 822 | bool checkForAllReturnedValuesAndReturnInsts( | 
| Johannes Doerfert | 695089e | 2019-08-23 15:23:49 +0000 | [diff] [blame] | 823 | const function_ref<bool(Value &, const SmallSetVector<ReturnInst *, 4> &)> | 
| Johannes Doerfert | 14a0493 | 2019-08-07 22:27:24 +0000 | [diff] [blame] | 824 | &Pred) const override; | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 825 |  | 
|  | 826 | /// Pretty print the attribute similar to the IR representation. | 
| Stefan Stipanovic | 15e86f7 | 2019-07-12 17:42:14 +0000 | [diff] [blame] | 827 | const std::string getAsStr() const override; | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 828 |  | 
|  | 829 | /// See AbstractState::isAtFixpoint(). | 
|  | 830 | bool isAtFixpoint() const override { return IsFixed; } | 
|  | 831 |  | 
|  | 832 | /// See AbstractState::isValidState(). | 
|  | 833 | bool isValidState() const override { return IsValidState; } | 
|  | 834 |  | 
|  | 835 | /// See AbstractState::indicateOptimisticFixpoint(...). | 
| Johannes Doerfert | d1c3793 | 2019-08-04 18:37:38 +0000 | [diff] [blame] | 836 | ChangeStatus indicateOptimisticFixpoint() override { | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 837 | IsFixed = true; | 
| Johannes Doerfert | d1c3793 | 2019-08-04 18:37:38 +0000 | [diff] [blame] | 838 | return ChangeStatus::UNCHANGED; | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 839 | } | 
| Stefan Stipanovic | d021617 | 2019-08-02 21:31:22 +0000 | [diff] [blame] | 840 |  | 
| Johannes Doerfert | d1c3793 | 2019-08-04 18:37:38 +0000 | [diff] [blame] | 841 | ChangeStatus indicatePessimisticFixpoint() override { | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 842 | IsFixed = true; | 
|  | 843 | IsValidState = false; | 
| Johannes Doerfert | d1c3793 | 2019-08-04 18:37:38 +0000 | [diff] [blame] | 844 | return ChangeStatus::CHANGED; | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 845 | } | 
|  | 846 | }; | 
|  | 847 |  | 
|  | 848 | ChangeStatus AAReturnedValuesImpl::manifest(Attributor &A) { | 
|  | 849 | ChangeStatus Changed = ChangeStatus::UNCHANGED; | 
|  | 850 |  | 
|  | 851 | // Bookkeeping. | 
|  | 852 | assert(isValidState()); | 
| Johannes Doerfert | 17b578b | 2019-08-14 21:46:25 +0000 | [diff] [blame] | 853 | STATS_DECLTRACK(KnownReturnValues, FunctionReturn, | 
|  | 854 | "Number of function with known return values"); | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 855 |  | 
|  | 856 | // Check if we have an assumed unique return value that we could manifest. | 
| Johannes Doerfert | 14a0493 | 2019-08-07 22:27:24 +0000 | [diff] [blame] | 857 | Optional<Value *> UniqueRV = getAssumedUniqueReturnValue(A); | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 858 |  | 
|  | 859 | if (!UniqueRV.hasValue() || !UniqueRV.getValue()) | 
|  | 860 | return Changed; | 
|  | 861 |  | 
|  | 862 | // Bookkeeping. | 
| Johannes Doerfert | 17b578b | 2019-08-14 21:46:25 +0000 | [diff] [blame] | 863 | STATS_DECLTRACK(UniqueReturnValue, FunctionReturn, | 
|  | 864 | "Number of function with unique return"); | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 865 |  | 
| Johannes Doerfert | 23400e61 | 2019-08-23 17:41:37 +0000 | [diff] [blame] | 866 | // Callback to replace the uses of CB with the constant C. | 
|  | 867 | auto ReplaceCallSiteUsersWith = [](CallBase &CB, Constant &C) { | 
|  | 868 | if (CB.getNumUses() == 0) | 
|  | 869 | return ChangeStatus::UNCHANGED; | 
|  | 870 | CB.replaceAllUsesWith(&C); | 
|  | 871 | return ChangeStatus::CHANGED; | 
|  | 872 | }; | 
|  | 873 |  | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 874 | // If the assumed unique return value is an argument, annotate it. | 
|  | 875 | if (auto *UniqueRVArg = dyn_cast<Argument>(UniqueRV.getValue())) { | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 876 | getIRPosition() = IRPosition::argument(*UniqueRVArg); | 
| Johannes Doerfert | 23400e61 | 2019-08-23 17:41:37 +0000 | [diff] [blame] | 877 | Changed = IRAttribute::manifest(A); | 
|  | 878 | } else if (auto *RVC = dyn_cast<Constant>(UniqueRV.getValue())) { | 
|  | 879 | // We can replace the returned value with the unique returned constant. | 
|  | 880 | Value &AnchorValue = getAnchorValue(); | 
|  | 881 | if (Function *F = dyn_cast<Function>(&AnchorValue)) { | 
|  | 882 | for (const Use &U : F->uses()) | 
|  | 883 | if (CallBase *CB = dyn_cast<CallBase>(U.getUser())) | 
| Johannes Doerfert | e7c6f97 | 2019-09-14 02:57:50 +0000 | [diff] [blame] | 884 | if (CB->isCallee(&U)) { | 
|  | 885 | Constant *RVCCast = | 
|  | 886 | ConstantExpr::getTruncOrBitCast(RVC, CB->getType()); | 
|  | 887 | Changed = ReplaceCallSiteUsersWith(*CB, *RVCCast) | Changed; | 
|  | 888 | } | 
| Johannes Doerfert | 23400e61 | 2019-08-23 17:41:37 +0000 | [diff] [blame] | 889 | } else { | 
|  | 890 | assert(isa<CallBase>(AnchorValue) && | 
|  | 891 | "Expcected a function or call base anchor!"); | 
| Johannes Doerfert | e7c6f97 | 2019-09-14 02:57:50 +0000 | [diff] [blame] | 892 | Constant *RVCCast = | 
|  | 893 | ConstantExpr::getTruncOrBitCast(RVC, AnchorValue.getType()); | 
|  | 894 | Changed = ReplaceCallSiteUsersWith(cast<CallBase>(AnchorValue), *RVCCast); | 
| Johannes Doerfert | 23400e61 | 2019-08-23 17:41:37 +0000 | [diff] [blame] | 895 | } | 
|  | 896 | if (Changed == ChangeStatus::CHANGED) | 
|  | 897 | STATS_DECLTRACK(UniqueConstantReturnValue, FunctionReturn, | 
|  | 898 | "Number of function returns replaced by constant return"); | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 899 | } | 
|  | 900 |  | 
|  | 901 | return Changed; | 
|  | 902 | } | 
|  | 903 |  | 
|  | 904 | const std::string AAReturnedValuesImpl::getAsStr() const { | 
|  | 905 | return (isAtFixpoint() ? "returns(#" : "may-return(#") + | 
| Johannes Doerfert | 6471bb6 | 2019-08-04 18:39:28 +0000 | [diff] [blame] | 906 | (isValidState() ? std::to_string(getNumReturnValues()) : "?") + | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 907 | ")[#UC: " + std::to_string(UnresolvedCalls.size()) + "]"; | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 908 | } | 
|  | 909 |  | 
| Johannes Doerfert | 14a0493 | 2019-08-07 22:27:24 +0000 | [diff] [blame] | 910 | Optional<Value *> | 
|  | 911 | AAReturnedValuesImpl::getAssumedUniqueReturnValue(Attributor &A) const { | 
|  | 912 | // If checkForAllReturnedValues provides a unique value, ignoring potential | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 913 | // undef values that can also be present, it is assumed to be the actual | 
|  | 914 | // return value and forwarded to the caller of this method. If there are | 
|  | 915 | // multiple, a nullptr is returned indicating there cannot be a unique | 
|  | 916 | // returned value. | 
|  | 917 | Optional<Value *> UniqueRV; | 
|  | 918 |  | 
| Johannes Doerfert | 14a0493 | 2019-08-07 22:27:24 +0000 | [diff] [blame] | 919 | auto Pred = [&](Value &RV) -> bool { | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 920 | // If we found a second returned value and neither the current nor the saved | 
|  | 921 | // one is an undef, there is no unique returned value. Undefs are special | 
|  | 922 | // since we can pretend they have any value. | 
|  | 923 | if (UniqueRV.hasValue() && UniqueRV != &RV && | 
|  | 924 | !(isa<UndefValue>(RV) || isa<UndefValue>(UniqueRV.getValue()))) { | 
|  | 925 | UniqueRV = nullptr; | 
|  | 926 | return false; | 
|  | 927 | } | 
|  | 928 |  | 
|  | 929 | // Do not overwrite a value with an undef. | 
|  | 930 | if (!UniqueRV.hasValue() || !isa<UndefValue>(RV)) | 
|  | 931 | UniqueRV = &RV; | 
|  | 932 |  | 
|  | 933 | return true; | 
|  | 934 | }; | 
|  | 935 |  | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 936 | if (!A.checkForAllReturnedValues(Pred, *this)) | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 937 | UniqueRV = nullptr; | 
|  | 938 |  | 
|  | 939 | return UniqueRV; | 
|  | 940 | } | 
|  | 941 |  | 
| Johannes Doerfert | 14a0493 | 2019-08-07 22:27:24 +0000 | [diff] [blame] | 942 | bool AAReturnedValuesImpl::checkForAllReturnedValuesAndReturnInsts( | 
| Johannes Doerfert | 695089e | 2019-08-23 15:23:49 +0000 | [diff] [blame] | 943 | const function_ref<bool(Value &, const SmallSetVector<ReturnInst *, 4> &)> | 
| Johannes Doerfert | 14a0493 | 2019-08-07 22:27:24 +0000 | [diff] [blame] | 944 | &Pred) const { | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 945 | if (!isValidState()) | 
|  | 946 | return false; | 
|  | 947 |  | 
|  | 948 | // Check all returned values but ignore call sites as long as we have not | 
|  | 949 | // encountered an overdefined one during an update. | 
|  | 950 | for (auto &It : ReturnedValues) { | 
|  | 951 | Value *RV = It.first; | 
|  | 952 |  | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 953 | CallBase *CB = dyn_cast<CallBase>(RV); | 
|  | 954 | if (CB && !UnresolvedCalls.count(CB)) | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 955 | continue; | 
|  | 956 |  | 
| Johannes Doerfert | 695089e | 2019-08-23 15:23:49 +0000 | [diff] [blame] | 957 | if (!Pred(*RV, It.second)) | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 958 | return false; | 
|  | 959 | } | 
|  | 960 |  | 
|  | 961 | return true; | 
|  | 962 | } | 
|  | 963 |  | 
| Johannes Doerfert | ece8190 | 2019-08-12 22:05:53 +0000 | [diff] [blame] | 964 | ChangeStatus AAReturnedValuesImpl::updateImpl(Attributor &A) { | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 965 | size_t NumUnresolvedCalls = UnresolvedCalls.size(); | 
|  | 966 | bool Changed = false; | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 967 |  | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 968 | // State used in the value traversals starting in returned values. | 
|  | 969 | struct RVState { | 
|  | 970 | // The map in which we collect return values -> return instrs. | 
|  | 971 | decltype(ReturnedValues) &RetValsMap; | 
|  | 972 | // The flag to indicate a change. | 
| Johannes Doerfert | 056f1b5 | 2019-08-19 19:14:10 +0000 | [diff] [blame] | 973 | bool &Changed; | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 974 | // The return instrs we come from. | 
| Johannes Doerfert | 695089e | 2019-08-23 15:23:49 +0000 | [diff] [blame] | 975 | SmallSetVector<ReturnInst *, 4> RetInsts; | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 976 | }; | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 977 |  | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 978 | // Callback for a leaf value returned by the associated function. | 
| Johannes Doerfert | b9b8791 | 2019-08-20 06:02:39 +0000 | [diff] [blame] | 979 | auto VisitValueCB = [](Value &Val, RVState &RVS, bool) -> bool { | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 980 | auto Size = RVS.RetValsMap[&Val].size(); | 
|  | 981 | RVS.RetValsMap[&Val].insert(RVS.RetInsts.begin(), RVS.RetInsts.end()); | 
|  | 982 | bool Inserted = RVS.RetValsMap[&Val].size() != Size; | 
|  | 983 | RVS.Changed |= Inserted; | 
|  | 984 | LLVM_DEBUG({ | 
|  | 985 | if (Inserted) | 
|  | 986 | dbgs() << "[AAReturnedValues] 1 Add new returned value " << Val | 
|  | 987 | << " => " << RVS.RetInsts.size() << "\n"; | 
|  | 988 | }); | 
| Johannes Doerfert | b9b8791 | 2019-08-20 06:02:39 +0000 | [diff] [blame] | 989 | return true; | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 990 | }; | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 991 |  | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 992 | // Helper method to invoke the generic value traversal. | 
|  | 993 | auto VisitReturnedValue = [&](Value &RV, RVState &RVS) { | 
|  | 994 | IRPosition RetValPos = IRPosition::value(RV); | 
|  | 995 | return genericValueTraversal<AAReturnedValues, RVState>(A, RetValPos, *this, | 
|  | 996 | RVS, VisitValueCB); | 
|  | 997 | }; | 
| Johannes Doerfert | da4d811 | 2019-08-01 16:21:54 +0000 | [diff] [blame] | 998 |  | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 999 | // Callback for all "return intructions" live in the associated function. | 
|  | 1000 | auto CheckReturnInst = [this, &VisitReturnedValue, &Changed](Instruction &I) { | 
|  | 1001 | ReturnInst &Ret = cast<ReturnInst>(I); | 
| Johannes Doerfert | 056f1b5 | 2019-08-19 19:14:10 +0000 | [diff] [blame] | 1002 | RVState RVS({ReturnedValues, Changed, {}}); | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 1003 | RVS.RetInsts.insert(&Ret); | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 1004 | return VisitReturnedValue(*Ret.getReturnValue(), RVS); | 
|  | 1005 | }; | 
| Stefan Stipanovic | d021617 | 2019-08-02 21:31:22 +0000 | [diff] [blame] | 1006 |  | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 1007 | // Start by discovering returned values from all live returned instructions in | 
|  | 1008 | // the associated function. | 
|  | 1009 | if (!A.checkForAllInstructions(CheckReturnInst, *this, {Instruction::Ret})) | 
|  | 1010 | return indicatePessimisticFixpoint(); | 
|  | 1011 |  | 
|  | 1012 | // Once returned values "directly" present in the code are handled we try to | 
|  | 1013 | // resolve returned calls. | 
|  | 1014 | decltype(ReturnedValues) NewRVsMap; | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 1015 | for (auto &It : ReturnedValues) { | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 1016 | LLVM_DEBUG(dbgs() << "[AAReturnedValues] Returned value: " << *It.first | 
|  | 1017 | << " by #" << It.second.size() << " RIs\n"); | 
|  | 1018 | CallBase *CB = dyn_cast<CallBase>(It.first); | 
|  | 1019 | if (!CB || UnresolvedCalls.count(CB)) | 
|  | 1020 | continue; | 
| Stefan Stipanovic | d021617 | 2019-08-02 21:31:22 +0000 | [diff] [blame] | 1021 |  | 
| Johannes Doerfert | 07a5c12 | 2019-08-28 14:09:14 +0000 | [diff] [blame] | 1022 | if (!CB->getCalledFunction()) { | 
|  | 1023 | LLVM_DEBUG(dbgs() << "[AAReturnedValues] Unresolved call: " << *CB | 
|  | 1024 | << "\n"); | 
|  | 1025 | UnresolvedCalls.insert(CB); | 
|  | 1026 | continue; | 
|  | 1027 | } | 
|  | 1028 |  | 
|  | 1029 | // TODO: use the function scope once we have call site AAReturnedValues. | 
|  | 1030 | const auto &RetValAA = A.getAAFor<AAReturnedValues>( | 
|  | 1031 | *this, IRPosition::function(*CB->getCalledFunction())); | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 1032 | LLVM_DEBUG(dbgs() << "[AAReturnedValues] Found another AAReturnedValues: " | 
|  | 1033 | << static_cast<const AbstractAttribute &>(RetValAA) | 
|  | 1034 | << "\n"); | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 1035 |  | 
|  | 1036 | // Skip dead ends, thus if we do not know anything about the returned | 
|  | 1037 | // call we mark it as unresolved and it will stay that way. | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 1038 | if (!RetValAA.getState().isValidState()) { | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 1039 | LLVM_DEBUG(dbgs() << "[AAReturnedValues] Unresolved call: " << *CB | 
|  | 1040 | << "\n"); | 
|  | 1041 | UnresolvedCalls.insert(CB); | 
|  | 1042 | continue; | 
|  | 1043 | } | 
|  | 1044 |  | 
| Johannes Doerfert | de7674c | 2019-08-19 21:35:31 +0000 | [diff] [blame] | 1045 | // Do not try to learn partial information. If the callee has unresolved | 
|  | 1046 | // return values we will treat the call as unresolved/opaque. | 
|  | 1047 | auto &RetValAAUnresolvedCalls = RetValAA.getUnresolvedCalls(); | 
|  | 1048 | if (!RetValAAUnresolvedCalls.empty()) { | 
|  | 1049 | UnresolvedCalls.insert(CB); | 
|  | 1050 | continue; | 
|  | 1051 | } | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 1052 |  | 
| Johannes Doerfert | de7674c | 2019-08-19 21:35:31 +0000 | [diff] [blame] | 1053 | // Now check if we can track transitively returned values. If possible, thus | 
|  | 1054 | // if all return value can be represented in the current scope, do so. | 
|  | 1055 | bool Unresolved = false; | 
|  | 1056 | for (auto &RetValAAIt : RetValAA.returned_values()) { | 
|  | 1057 | Value *RetVal = RetValAAIt.first; | 
|  | 1058 | if (isa<Argument>(RetVal) || isa<CallBase>(RetVal) || | 
|  | 1059 | isa<Constant>(RetVal)) | 
|  | 1060 | continue; | 
|  | 1061 | // Anything that did not fit in the above categories cannot be resolved, | 
|  | 1062 | // mark the call as unresolved. | 
|  | 1063 | LLVM_DEBUG(dbgs() << "[AAReturnedValues] transitively returned value " | 
|  | 1064 | "cannot be translated: " | 
|  | 1065 | << *RetVal << "\n"); | 
|  | 1066 | UnresolvedCalls.insert(CB); | 
|  | 1067 | Unresolved = true; | 
|  | 1068 | break; | 
|  | 1069 | } | 
|  | 1070 |  | 
|  | 1071 | if (Unresolved) | 
|  | 1072 | continue; | 
|  | 1073 |  | 
| Johannes Doerfert | deb9ea3 | 2019-08-23 15:42:19 +0000 | [diff] [blame] | 1074 | // Now track transitively returned values. | 
|  | 1075 | unsigned &NumRetAA = NumReturnedValuesPerKnownAA[CB]; | 
|  | 1076 | if (NumRetAA == RetValAA.getNumReturnValues()) { | 
|  | 1077 | LLVM_DEBUG(dbgs() << "[AAReturnedValues] Skip call as it has not " | 
|  | 1078 | "changed since it was seen last\n"); | 
|  | 1079 | continue; | 
|  | 1080 | } | 
|  | 1081 | NumRetAA = RetValAA.getNumReturnValues(); | 
|  | 1082 |  | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 1083 | for (auto &RetValAAIt : RetValAA.returned_values()) { | 
|  | 1084 | Value *RetVal = RetValAAIt.first; | 
|  | 1085 | if (Argument *Arg = dyn_cast<Argument>(RetVal)) { | 
|  | 1086 | // Arguments are mapped to call site operands and we begin the traversal | 
|  | 1087 | // again. | 
| Johannes Doerfert | 056f1b5 | 2019-08-19 19:14:10 +0000 | [diff] [blame] | 1088 | bool Unused = false; | 
|  | 1089 | RVState RVS({NewRVsMap, Unused, RetValAAIt.second}); | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 1090 | VisitReturnedValue(*CB->getArgOperand(Arg->getArgNo()), RVS); | 
|  | 1091 | continue; | 
|  | 1092 | } else if (isa<CallBase>(RetVal)) { | 
|  | 1093 | // Call sites are resolved by the callee attribute over time, no need to | 
|  | 1094 | // do anything for us. | 
|  | 1095 | continue; | 
|  | 1096 | } else if (isa<Constant>(RetVal)) { | 
|  | 1097 | // Constants are valid everywhere, we can simply take them. | 
|  | 1098 | NewRVsMap[RetVal].insert(It.second.begin(), It.second.end()); | 
|  | 1099 | continue; | 
|  | 1100 | } | 
| Johannes Doerfert | 4361da2 | 2019-08-04 18:38:53 +0000 | [diff] [blame] | 1101 | } | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 1102 | } | 
|  | 1103 |  | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 1104 | // To avoid modifications to the ReturnedValues map while we iterate over it | 
|  | 1105 | // we kept record of potential new entries in a copy map, NewRVsMap. | 
|  | 1106 | for (auto &It : NewRVsMap) { | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 1107 | assert(!It.second.empty() && "Entry does not add anything."); | 
|  | 1108 | auto &ReturnInsts = ReturnedValues[It.first]; | 
|  | 1109 | for (ReturnInst *RI : It.second) | 
| Johannes Doerfert | 695089e | 2019-08-23 15:23:49 +0000 | [diff] [blame] | 1110 | if (ReturnInsts.insert(RI)) { | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 1111 | LLVM_DEBUG(dbgs() << "[AAReturnedValues] Add new returned value " | 
|  | 1112 | << *It.first << " => " << *RI << "\n"); | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 1113 | Changed = true; | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 1114 | } | 
|  | 1115 | } | 
|  | 1116 |  | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 1117 | Changed |= (NumUnresolvedCalls != UnresolvedCalls.size()); | 
|  | 1118 | return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED; | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 1119 | } | 
|  | 1120 |  | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 1121 | struct AAReturnedValuesFunction final : public AAReturnedValuesImpl { | 
|  | 1122 | AAReturnedValuesFunction(const IRPosition &IRP) : AAReturnedValuesImpl(IRP) {} | 
|  | 1123 |  | 
|  | 1124 | /// See AbstractAttribute::trackStatistics() | 
| Johannes Doerfert | 17b578b | 2019-08-14 21:46:25 +0000 | [diff] [blame] | 1125 | void trackStatistics() const override { STATS_DECLTRACK_ARG_ATTR(returned) } | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 1126 | }; | 
|  | 1127 |  | 
| Johannes Doerfert | 66cf87e | 2019-08-16 19:49:00 +0000 | [diff] [blame] | 1128 | /// Returned values information for a call sites. | 
| Johannes Doerfert | 07a5c12 | 2019-08-28 14:09:14 +0000 | [diff] [blame] | 1129 | struct AAReturnedValuesCallSite final : AAReturnedValuesImpl { | 
|  | 1130 | AAReturnedValuesCallSite(const IRPosition &IRP) : AAReturnedValuesImpl(IRP) {} | 
|  | 1131 |  | 
|  | 1132 | /// See AbstractAttribute::initialize(...). | 
|  | 1133 | void initialize(Attributor &A) override { | 
|  | 1134 | // TODO: Once we have call site specific value information we can provide | 
| Johannes Doerfert | 3fac668 | 2019-08-30 15:24:52 +0000 | [diff] [blame] | 1135 | //       call site specific liveness information and then it makes | 
| Johannes Doerfert | 07a5c12 | 2019-08-28 14:09:14 +0000 | [diff] [blame] | 1136 | //       sense to specialize attributes for call sites instead of | 
|  | 1137 | //       redirecting requests to the callee. | 
|  | 1138 | llvm_unreachable("Abstract attributes for returned values are not " | 
|  | 1139 | "supported for call sites yet!"); | 
|  | 1140 | } | 
|  | 1141 |  | 
|  | 1142 | /// See AbstractAttribute::updateImpl(...). | 
|  | 1143 | ChangeStatus updateImpl(Attributor &A) override { | 
|  | 1144 | return indicatePessimisticFixpoint(); | 
|  | 1145 | } | 
|  | 1146 |  | 
|  | 1147 | /// See AbstractAttribute::trackStatistics() | 
|  | 1148 | void trackStatistics() const override {} | 
|  | 1149 | }; | 
| Johannes Doerfert | 66cf87e | 2019-08-16 19:49:00 +0000 | [diff] [blame] | 1150 |  | 
| Stefan Stipanovic | 0626367 | 2019-07-11 21:37:40 +0000 | [diff] [blame] | 1151 | /// ------------------------ NoSync Function Attribute ------------------------- | 
|  | 1152 |  | 
| Johannes Doerfert | 344d038 | 2019-08-07 22:34:26 +0000 | [diff] [blame] | 1153 | struct AANoSyncImpl : AANoSync { | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 1154 | AANoSyncImpl(const IRPosition &IRP) : AANoSync(IRP) {} | 
| Stefan Stipanovic | 0626367 | 2019-07-11 21:37:40 +0000 | [diff] [blame] | 1155 |  | 
| Stefan Stipanovic | cb5ecae | 2019-07-12 18:34:06 +0000 | [diff] [blame] | 1156 | const std::string getAsStr() const override { | 
| Stefan Stipanovic | 0626367 | 2019-07-11 21:37:40 +0000 | [diff] [blame] | 1157 | return getAssumed() ? "nosync" : "may-sync"; | 
|  | 1158 | } | 
|  | 1159 |  | 
|  | 1160 | /// See AbstractAttribute::updateImpl(...). | 
| Johannes Doerfert | ece8190 | 2019-08-12 22:05:53 +0000 | [diff] [blame] | 1161 | ChangeStatus updateImpl(Attributor &A) override; | 
| Stefan Stipanovic | 0626367 | 2019-07-11 21:37:40 +0000 | [diff] [blame] | 1162 |  | 
| Stefan Stipanovic | 0626367 | 2019-07-11 21:37:40 +0000 | [diff] [blame] | 1163 | /// Helper function used to determine whether an instruction is non-relaxed | 
|  | 1164 | /// atomic. In other words, if an atomic instruction does not have unordered | 
|  | 1165 | /// or monotonic ordering | 
|  | 1166 | static bool isNonRelaxedAtomic(Instruction *I); | 
|  | 1167 |  | 
|  | 1168 | /// Helper function used to determine whether an instruction is volatile. | 
|  | 1169 | static bool isVolatile(Instruction *I); | 
|  | 1170 |  | 
| Johannes Doerfert | c7a1db3 | 2019-07-13 01:09:27 +0000 | [diff] [blame] | 1171 | /// Helper function uset to check if intrinsic is volatile (memcpy, memmove, | 
|  | 1172 | /// memset). | 
| Stefan Stipanovic | 0626367 | 2019-07-11 21:37:40 +0000 | [diff] [blame] | 1173 | static bool isNoSyncIntrinsic(Instruction *I); | 
|  | 1174 | }; | 
|  | 1175 |  | 
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 1176 | bool AANoSyncImpl::isNonRelaxedAtomic(Instruction *I) { | 
| Stefan Stipanovic | 0626367 | 2019-07-11 21:37:40 +0000 | [diff] [blame] | 1177 | if (!I->isAtomic()) | 
|  | 1178 | return false; | 
|  | 1179 |  | 
|  | 1180 | AtomicOrdering Ordering; | 
|  | 1181 | switch (I->getOpcode()) { | 
|  | 1182 | case Instruction::AtomicRMW: | 
|  | 1183 | Ordering = cast<AtomicRMWInst>(I)->getOrdering(); | 
|  | 1184 | break; | 
|  | 1185 | case Instruction::Store: | 
|  | 1186 | Ordering = cast<StoreInst>(I)->getOrdering(); | 
|  | 1187 | break; | 
|  | 1188 | case Instruction::Load: | 
|  | 1189 | Ordering = cast<LoadInst>(I)->getOrdering(); | 
|  | 1190 | break; | 
|  | 1191 | case Instruction::Fence: { | 
|  | 1192 | auto *FI = cast<FenceInst>(I); | 
|  | 1193 | if (FI->getSyncScopeID() == SyncScope::SingleThread) | 
|  | 1194 | return false; | 
|  | 1195 | Ordering = FI->getOrdering(); | 
|  | 1196 | break; | 
|  | 1197 | } | 
|  | 1198 | case Instruction::AtomicCmpXchg: { | 
|  | 1199 | AtomicOrdering Success = cast<AtomicCmpXchgInst>(I)->getSuccessOrdering(); | 
|  | 1200 | AtomicOrdering Failure = cast<AtomicCmpXchgInst>(I)->getFailureOrdering(); | 
|  | 1201 | // Only if both are relaxed, than it can be treated as relaxed. | 
|  | 1202 | // Otherwise it is non-relaxed. | 
|  | 1203 | if (Success != AtomicOrdering::Unordered && | 
|  | 1204 | Success != AtomicOrdering::Monotonic) | 
|  | 1205 | return true; | 
|  | 1206 | if (Failure != AtomicOrdering::Unordered && | 
|  | 1207 | Failure != AtomicOrdering::Monotonic) | 
|  | 1208 | return true; | 
|  | 1209 | return false; | 
|  | 1210 | } | 
|  | 1211 | default: | 
|  | 1212 | llvm_unreachable( | 
|  | 1213 | "New atomic operations need to be known in the attributor."); | 
|  | 1214 | } | 
|  | 1215 |  | 
|  | 1216 | // Relaxed. | 
|  | 1217 | if (Ordering == AtomicOrdering::Unordered || | 
|  | 1218 | Ordering == AtomicOrdering::Monotonic) | 
|  | 1219 | return false; | 
|  | 1220 | return true; | 
|  | 1221 | } | 
|  | 1222 |  | 
|  | 1223 | /// Checks if an intrinsic is nosync. Currently only checks mem* intrinsics. | 
|  | 1224 | /// FIXME: We should ipmrove the handling of intrinsics. | 
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 1225 | bool AANoSyncImpl::isNoSyncIntrinsic(Instruction *I) { | 
| Stefan Stipanovic | 0626367 | 2019-07-11 21:37:40 +0000 | [diff] [blame] | 1226 | if (auto *II = dyn_cast<IntrinsicInst>(I)) { | 
|  | 1227 | switch (II->getIntrinsicID()) { | 
|  | 1228 | /// Element wise atomic memory intrinsics are can only be unordered, | 
|  | 1229 | /// therefore nosync. | 
|  | 1230 | case Intrinsic::memset_element_unordered_atomic: | 
|  | 1231 | case Intrinsic::memmove_element_unordered_atomic: | 
|  | 1232 | case Intrinsic::memcpy_element_unordered_atomic: | 
|  | 1233 | return true; | 
|  | 1234 | case Intrinsic::memset: | 
|  | 1235 | case Intrinsic::memmove: | 
|  | 1236 | case Intrinsic::memcpy: | 
|  | 1237 | if (!cast<MemIntrinsic>(II)->isVolatile()) | 
|  | 1238 | return true; | 
|  | 1239 | return false; | 
|  | 1240 | default: | 
|  | 1241 | return false; | 
|  | 1242 | } | 
|  | 1243 | } | 
|  | 1244 | return false; | 
|  | 1245 | } | 
|  | 1246 |  | 
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 1247 | bool AANoSyncImpl::isVolatile(Instruction *I) { | 
| Stefan Stipanovic | 0626367 | 2019-07-11 21:37:40 +0000 | [diff] [blame] | 1248 | assert(!ImmutableCallSite(I) && !isa<CallBase>(I) && | 
|  | 1249 | "Calls should not be checked here"); | 
|  | 1250 |  | 
|  | 1251 | switch (I->getOpcode()) { | 
|  | 1252 | case Instruction::AtomicRMW: | 
|  | 1253 | return cast<AtomicRMWInst>(I)->isVolatile(); | 
|  | 1254 | case Instruction::Store: | 
|  | 1255 | return cast<StoreInst>(I)->isVolatile(); | 
|  | 1256 | case Instruction::Load: | 
|  | 1257 | return cast<LoadInst>(I)->isVolatile(); | 
|  | 1258 | case Instruction::AtomicCmpXchg: | 
|  | 1259 | return cast<AtomicCmpXchgInst>(I)->isVolatile(); | 
|  | 1260 | default: | 
|  | 1261 | return false; | 
|  | 1262 | } | 
|  | 1263 | } | 
|  | 1264 |  | 
| Johannes Doerfert | ece8190 | 2019-08-12 22:05:53 +0000 | [diff] [blame] | 1265 | ChangeStatus AANoSyncImpl::updateImpl(Attributor &A) { | 
| Stefan Stipanovic | 0626367 | 2019-07-11 21:37:40 +0000 | [diff] [blame] | 1266 |  | 
| Stefan Stipanovic | aaa5270 | 2019-08-07 18:26:02 +0000 | [diff] [blame] | 1267 | auto CheckRWInstForNoSync = [&](Instruction &I) { | 
|  | 1268 | /// We are looking for volatile instructions or Non-Relaxed atomics. | 
|  | 1269 | /// FIXME: We should ipmrove the handling of intrinsics. | 
| Stefan Stipanovic | d021617 | 2019-08-02 21:31:22 +0000 | [diff] [blame] | 1270 |  | 
| Stefan Stipanovic | aaa5270 | 2019-08-07 18:26:02 +0000 | [diff] [blame] | 1271 | if (isa<IntrinsicInst>(&I) && isNoSyncIntrinsic(&I)) | 
|  | 1272 | return true; | 
| Stefan Stipanovic | 0626367 | 2019-07-11 21:37:40 +0000 | [diff] [blame] | 1273 |  | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 1274 | if (ImmutableCallSite ICS = ImmutableCallSite(&I)) { | 
|  | 1275 | if (ICS.hasFnAttr(Attribute::NoSync)) | 
|  | 1276 | return true; | 
| Stefan Stipanovic | 0626367 | 2019-07-11 21:37:40 +0000 | [diff] [blame] | 1277 |  | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 1278 | const auto &NoSyncAA = | 
|  | 1279 | A.getAAFor<AANoSync>(*this, IRPosition::callsite_function(ICS)); | 
|  | 1280 | if (NoSyncAA.isAssumedNoSync()) | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 1281 | return true; | 
|  | 1282 | return false; | 
|  | 1283 | } | 
| Stefan Stipanovic | 0626367 | 2019-07-11 21:37:40 +0000 | [diff] [blame] | 1284 |  | 
| Stefan Stipanovic | aaa5270 | 2019-08-07 18:26:02 +0000 | [diff] [blame] | 1285 | if (!isVolatile(&I) && !isNonRelaxedAtomic(&I)) | 
|  | 1286 | return true; | 
| Stefan Stipanovic | 0626367 | 2019-07-11 21:37:40 +0000 | [diff] [blame] | 1287 |  | 
| Stefan Stipanovic | aaa5270 | 2019-08-07 18:26:02 +0000 | [diff] [blame] | 1288 | return false; | 
|  | 1289 | }; | 
| Stefan Stipanovic | 0626367 | 2019-07-11 21:37:40 +0000 | [diff] [blame] | 1290 |  | 
| Johannes Doerfert | d0f6400 | 2019-08-06 00:32:43 +0000 | [diff] [blame] | 1291 | auto CheckForNoSync = [&](Instruction &I) { | 
|  | 1292 | // At this point we handled all read/write effects and they are all | 
|  | 1293 | // nosync, so they can be skipped. | 
|  | 1294 | if (I.mayReadOrWriteMemory()) | 
|  | 1295 | return true; | 
| Stefan Stipanovic | 0626367 | 2019-07-11 21:37:40 +0000 | [diff] [blame] | 1296 |  | 
| Johannes Doerfert | d0f6400 | 2019-08-06 00:32:43 +0000 | [diff] [blame] | 1297 | // non-convergent and readnone imply nosync. | 
|  | 1298 | return !ImmutableCallSite(&I).isConvergent(); | 
|  | 1299 | }; | 
| Stefan Stipanovic | 0626367 | 2019-07-11 21:37:40 +0000 | [diff] [blame] | 1300 |  | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 1301 | if (!A.checkForAllReadWriteInstructions(CheckRWInstForNoSync, *this) || | 
|  | 1302 | !A.checkForAllCallLikeInstructions(CheckForNoSync, *this)) | 
| Johannes Doerfert | d0f6400 | 2019-08-06 00:32:43 +0000 | [diff] [blame] | 1303 | return indicatePessimisticFixpoint(); | 
| Stefan Stipanovic | aaa5270 | 2019-08-07 18:26:02 +0000 | [diff] [blame] | 1304 |  | 
| Stefan Stipanovic | 0626367 | 2019-07-11 21:37:40 +0000 | [diff] [blame] | 1305 | return ChangeStatus::UNCHANGED; | 
|  | 1306 | } | 
|  | 1307 |  | 
| Johannes Doerfert | 66cf87e | 2019-08-16 19:49:00 +0000 | [diff] [blame] | 1308 | struct AANoSyncFunction final : public AANoSyncImpl { | 
|  | 1309 | AANoSyncFunction(const IRPosition &IRP) : AANoSyncImpl(IRP) {} | 
|  | 1310 |  | 
|  | 1311 | /// See AbstractAttribute::trackStatistics() | 
|  | 1312 | void trackStatistics() const override { STATS_DECLTRACK_FN_ATTR(nosync) } | 
|  | 1313 | }; | 
|  | 1314 |  | 
|  | 1315 | /// NoSync attribute deduction for a call sites. | 
| Johannes Doerfert | 3fac668 | 2019-08-30 15:24:52 +0000 | [diff] [blame] | 1316 | struct AANoSyncCallSite final : AANoSyncImpl { | 
|  | 1317 | AANoSyncCallSite(const IRPosition &IRP) : AANoSyncImpl(IRP) {} | 
|  | 1318 |  | 
|  | 1319 | /// See AbstractAttribute::initialize(...). | 
|  | 1320 | void initialize(Attributor &A) override { | 
|  | 1321 | AANoSyncImpl::initialize(A); | 
|  | 1322 | Function *F = getAssociatedFunction(); | 
| Johannes Doerfert | b0412e4 | 2019-09-04 16:16:13 +0000 | [diff] [blame] | 1323 | if (!F) | 
| Johannes Doerfert | 3fac668 | 2019-08-30 15:24:52 +0000 | [diff] [blame] | 1324 | indicatePessimisticFixpoint(); | 
|  | 1325 | } | 
|  | 1326 |  | 
|  | 1327 | /// See AbstractAttribute::updateImpl(...). | 
|  | 1328 | ChangeStatus updateImpl(Attributor &A) override { | 
|  | 1329 | // TODO: Once we have call site specific value information we can provide | 
|  | 1330 | //       call site specific liveness information and then it makes | 
|  | 1331 | //       sense to specialize attributes for call sites arguments instead of | 
|  | 1332 | //       redirecting requests to the callee argument. | 
|  | 1333 | Function *F = getAssociatedFunction(); | 
|  | 1334 | const IRPosition &FnPos = IRPosition::function(*F); | 
|  | 1335 | auto &FnAA = A.getAAFor<AANoSync>(*this, FnPos); | 
|  | 1336 | return clampStateAndIndicateChange( | 
|  | 1337 | getState(), static_cast<const AANoSync::StateType &>(FnAA.getState())); | 
|  | 1338 | } | 
|  | 1339 |  | 
|  | 1340 | /// See AbstractAttribute::trackStatistics() | 
|  | 1341 | void trackStatistics() const override { STATS_DECLTRACK_CS_ATTR(nosync); } | 
|  | 1342 | }; | 
| Johannes Doerfert | 66cf87e | 2019-08-16 19:49:00 +0000 | [diff] [blame] | 1343 |  | 
| Hideto Ueno | 65bbaf9 | 2019-07-12 17:38:51 +0000 | [diff] [blame] | 1344 | /// ------------------------ No-Free Attributes ---------------------------- | 
|  | 1345 |  | 
| Johannes Doerfert | 344d038 | 2019-08-07 22:34:26 +0000 | [diff] [blame] | 1346 | struct AANoFreeImpl : public AANoFree { | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 1347 | AANoFreeImpl(const IRPosition &IRP) : AANoFree(IRP) {} | 
| Hideto Ueno | 65bbaf9 | 2019-07-12 17:38:51 +0000 | [diff] [blame] | 1348 |  | 
| Johannes Doerfert | fe6dbad | 2019-08-16 19:36:17 +0000 | [diff] [blame] | 1349 | /// See AbstractAttribute::updateImpl(...). | 
|  | 1350 | ChangeStatus updateImpl(Attributor &A) override { | 
|  | 1351 | auto CheckForNoFree = [&](Instruction &I) { | 
|  | 1352 | ImmutableCallSite ICS(&I); | 
|  | 1353 | if (ICS.hasFnAttr(Attribute::NoFree)) | 
|  | 1354 | return true; | 
|  | 1355 |  | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 1356 | const auto &NoFreeAA = | 
|  | 1357 | A.getAAFor<AANoFree>(*this, IRPosition::callsite_function(ICS)); | 
|  | 1358 | return NoFreeAA.isAssumedNoFree(); | 
| Johannes Doerfert | fe6dbad | 2019-08-16 19:36:17 +0000 | [diff] [blame] | 1359 | }; | 
|  | 1360 |  | 
|  | 1361 | if (!A.checkForAllCallLikeInstructions(CheckForNoFree, *this)) | 
|  | 1362 | return indicatePessimisticFixpoint(); | 
|  | 1363 | return ChangeStatus::UNCHANGED; | 
|  | 1364 | } | 
|  | 1365 |  | 
| Hideto Ueno | 65bbaf9 | 2019-07-12 17:38:51 +0000 | [diff] [blame] | 1366 | /// See AbstractAttribute::getAsStr(). | 
|  | 1367 | const std::string getAsStr() const override { | 
|  | 1368 | return getAssumed() ? "nofree" : "may-free"; | 
|  | 1369 | } | 
| Hideto Ueno | 65bbaf9 | 2019-07-12 17:38:51 +0000 | [diff] [blame] | 1370 | }; | 
|  | 1371 |  | 
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 1372 | struct AANoFreeFunction final : public AANoFreeImpl { | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 1373 | AANoFreeFunction(const IRPosition &IRP) : AANoFreeImpl(IRP) {} | 
| Johannes Doerfert | d1b79e0 | 2019-08-07 22:46:11 +0000 | [diff] [blame] | 1374 |  | 
|  | 1375 | /// See AbstractAttribute::trackStatistics() | 
| Johannes Doerfert | 17b578b | 2019-08-14 21:46:25 +0000 | [diff] [blame] | 1376 | void trackStatistics() const override { STATS_DECLTRACK_FN_ATTR(nofree) } | 
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 1377 | }; | 
|  | 1378 |  | 
| Johannes Doerfert | 66cf87e | 2019-08-16 19:49:00 +0000 | [diff] [blame] | 1379 | /// NoFree attribute deduction for a call sites. | 
| Johannes Doerfert | 3fac668 | 2019-08-30 15:24:52 +0000 | [diff] [blame] | 1380 | struct AANoFreeCallSite final : AANoFreeImpl { | 
|  | 1381 | AANoFreeCallSite(const IRPosition &IRP) : AANoFreeImpl(IRP) {} | 
|  | 1382 |  | 
|  | 1383 | /// See AbstractAttribute::initialize(...). | 
|  | 1384 | void initialize(Attributor &A) override { | 
|  | 1385 | AANoFreeImpl::initialize(A); | 
|  | 1386 | Function *F = getAssociatedFunction(); | 
| Johannes Doerfert | b0412e4 | 2019-09-04 16:16:13 +0000 | [diff] [blame] | 1387 | if (!F) | 
| Johannes Doerfert | 3fac668 | 2019-08-30 15:24:52 +0000 | [diff] [blame] | 1388 | indicatePessimisticFixpoint(); | 
|  | 1389 | } | 
|  | 1390 |  | 
|  | 1391 | /// See AbstractAttribute::updateImpl(...). | 
|  | 1392 | ChangeStatus updateImpl(Attributor &A) override { | 
|  | 1393 | // TODO: Once we have call site specific value information we can provide | 
|  | 1394 | //       call site specific liveness information and then it makes | 
|  | 1395 | //       sense to specialize attributes for call sites arguments instead of | 
|  | 1396 | //       redirecting requests to the callee argument. | 
|  | 1397 | Function *F = getAssociatedFunction(); | 
|  | 1398 | const IRPosition &FnPos = IRPosition::function(*F); | 
|  | 1399 | auto &FnAA = A.getAAFor<AANoFree>(*this, FnPos); | 
|  | 1400 | return clampStateAndIndicateChange( | 
|  | 1401 | getState(), static_cast<const AANoFree::StateType &>(FnAA.getState())); | 
|  | 1402 | } | 
|  | 1403 |  | 
|  | 1404 | /// See AbstractAttribute::trackStatistics() | 
|  | 1405 | void trackStatistics() const override { STATS_DECLTRACK_CS_ATTR(nofree); } | 
|  | 1406 | }; | 
| Johannes Doerfert | 66cf87e | 2019-08-16 19:49:00 +0000 | [diff] [blame] | 1407 |  | 
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 1408 | /// ------------------------ NonNull Argument Attribute ------------------------ | 
| Johannes Doerfert | 344d038 | 2019-08-07 22:34:26 +0000 | [diff] [blame] | 1409 | struct AANonNullImpl : AANonNull { | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 1410 | AANonNullImpl(const IRPosition &IRP) : AANonNull(IRP) {} | 
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 1411 |  | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 1412 | /// See AbstractAttribute::initialize(...). | 
|  | 1413 | void initialize(Attributor &A) override { | 
|  | 1414 | if (hasAttr({Attribute::NonNull, Attribute::Dereferenceable})) | 
|  | 1415 | indicateOptimisticFixpoint(); | 
| Johannes Doerfert | b0412e4 | 2019-09-04 16:16:13 +0000 | [diff] [blame] | 1416 | else | 
|  | 1417 | AANonNull::initialize(A); | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 1418 | } | 
|  | 1419 |  | 
| Johannes Doerfert | b9b8791 | 2019-08-20 06:02:39 +0000 | [diff] [blame] | 1420 | /// See AbstractAttribute::getAsStr(). | 
|  | 1421 | const std::string getAsStr() const override { | 
|  | 1422 | return getAssumed() ? "nonnull" : "may-null"; | 
|  | 1423 | } | 
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 1424 | }; | 
|  | 1425 |  | 
| Johannes Doerfert | b9b8791 | 2019-08-20 06:02:39 +0000 | [diff] [blame] | 1426 | /// NonNull attribute for a floating value. | 
|  | 1427 | struct AANonNullFloating : AANonNullImpl { | 
|  | 1428 | AANonNullFloating(const IRPosition &IRP) : AANonNullImpl(IRP) {} | 
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 1429 |  | 
| Johannes Doerfert | b9b8791 | 2019-08-20 06:02:39 +0000 | [diff] [blame] | 1430 | /// See AbstractAttribute::initialize(...). | 
|  | 1431 | void initialize(Attributor &A) override { | 
|  | 1432 | AANonNullImpl::initialize(A); | 
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 1433 |  | 
| Johannes Doerfert | b9b8791 | 2019-08-20 06:02:39 +0000 | [diff] [blame] | 1434 | if (isAtFixpoint()) | 
|  | 1435 | return; | 
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 1436 |  | 
| Johannes Doerfert | b9b8791 | 2019-08-20 06:02:39 +0000 | [diff] [blame] | 1437 | const IRPosition &IRP = getIRPosition(); | 
|  | 1438 | const Value &V = IRP.getAssociatedValue(); | 
|  | 1439 | const DataLayout &DL = A.getDataLayout(); | 
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 1440 |  | 
| Johannes Doerfert | b9b8791 | 2019-08-20 06:02:39 +0000 | [diff] [blame] | 1441 | // TODO: This context sensitive query should be removed once we can do | 
|  | 1442 | // context sensitive queries in the genericValueTraversal below. | 
|  | 1443 | if (isKnownNonZero(&V, DL, 0, /* TODO: AC */ nullptr, IRP.getCtxI(), | 
|  | 1444 | /* TODO: DT */ nullptr)) | 
|  | 1445 | indicateOptimisticFixpoint(); | 
|  | 1446 | } | 
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 1447 |  | 
|  | 1448 | /// See AbstractAttribute::updateImpl(...). | 
| Johannes Doerfert | fe6dbad | 2019-08-16 19:36:17 +0000 | [diff] [blame] | 1449 | ChangeStatus updateImpl(Attributor &A) override { | 
| Johannes Doerfert | b9b8791 | 2019-08-20 06:02:39 +0000 | [diff] [blame] | 1450 | const DataLayout &DL = A.getDataLayout(); | 
| Johannes Doerfert | fe6dbad | 2019-08-16 19:36:17 +0000 | [diff] [blame] | 1451 |  | 
| Johannes Doerfert | b9b8791 | 2019-08-20 06:02:39 +0000 | [diff] [blame] | 1452 | auto VisitValueCB = [&](Value &V, AAAlign::StateType &T, | 
|  | 1453 | bool Stripped) -> bool { | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 1454 | const auto &AA = A.getAAFor<AANonNull>(*this, IRPosition::value(V)); | 
|  | 1455 | if (!Stripped && this == &AA) { | 
|  | 1456 | if (!isKnownNonZero(&V, DL, 0, /* TODO: AC */ nullptr, | 
| Johannes Doerfert | 3fac668 | 2019-08-30 15:24:52 +0000 | [diff] [blame] | 1457 | /* TODO: CtxI */ nullptr, | 
|  | 1458 | /* TODO: DT */ nullptr)) | 
| Johannes Doerfert | b9b8791 | 2019-08-20 06:02:39 +0000 | [diff] [blame] | 1459 | T.indicatePessimisticFixpoint(); | 
|  | 1460 | } else { | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 1461 | // Use abstract attribute information. | 
|  | 1462 | const AANonNull::StateType &NS = | 
|  | 1463 | static_cast<const AANonNull::StateType &>(AA.getState()); | 
|  | 1464 | T ^= NS; | 
| Johannes Doerfert | b9b8791 | 2019-08-20 06:02:39 +0000 | [diff] [blame] | 1465 | } | 
|  | 1466 | return T.isValidState(); | 
|  | 1467 | }; | 
|  | 1468 |  | 
|  | 1469 | StateType T; | 
|  | 1470 | if (!genericValueTraversal<AANonNull, StateType>(A, getIRPosition(), *this, | 
|  | 1471 | T, VisitValueCB)) | 
| Johannes Doerfert | fe6dbad | 2019-08-16 19:36:17 +0000 | [diff] [blame] | 1472 | return indicatePessimisticFixpoint(); | 
| Johannes Doerfert | b9b8791 | 2019-08-20 06:02:39 +0000 | [diff] [blame] | 1473 |  | 
|  | 1474 | return clampStateAndIndicateChange(getState(), T); | 
| Johannes Doerfert | fe6dbad | 2019-08-16 19:36:17 +0000 | [diff] [blame] | 1475 | } | 
| Johannes Doerfert | d1b79e0 | 2019-08-07 22:46:11 +0000 | [diff] [blame] | 1476 |  | 
|  | 1477 | /// See AbstractAttribute::trackStatistics() | 
| Johannes Doerfert | 17b578b | 2019-08-14 21:46:25 +0000 | [diff] [blame] | 1478 | void trackStatistics() const override { STATS_DECLTRACK_FNRET_ATTR(nonnull) } | 
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 1479 | }; | 
|  | 1480 |  | 
| Johannes Doerfert | b9b8791 | 2019-08-20 06:02:39 +0000 | [diff] [blame] | 1481 | /// NonNull attribute for function return value. | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 1482 | struct AANonNullReturned final | 
|  | 1483 | : AAReturnedFromReturnedValues<AANonNull, AANonNullImpl> { | 
| Johannes Doerfert | b9b8791 | 2019-08-20 06:02:39 +0000 | [diff] [blame] | 1484 | AANonNullReturned(const IRPosition &IRP) | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 1485 | : AAReturnedFromReturnedValues<AANonNull, AANonNullImpl>(IRP) {} | 
| Johannes Doerfert | b9b8791 | 2019-08-20 06:02:39 +0000 | [diff] [blame] | 1486 |  | 
|  | 1487 | /// See AbstractAttribute::trackStatistics() | 
|  | 1488 | void trackStatistics() const override { STATS_DECLTRACK_FNRET_ATTR(nonnull) } | 
|  | 1489 | }; | 
|  | 1490 |  | 
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 1491 | /// NonNull attribute for function argument. | 
| Johannes Doerfert | b9b8791 | 2019-08-20 06:02:39 +0000 | [diff] [blame] | 1492 | struct AANonNullArgument final | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 1493 | : AAArgumentFromCallSiteArguments<AANonNull, AANonNullImpl> { | 
| Johannes Doerfert | b9b8791 | 2019-08-20 06:02:39 +0000 | [diff] [blame] | 1494 | AANonNullArgument(const IRPosition &IRP) | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 1495 | : AAArgumentFromCallSiteArguments<AANonNull, AANonNullImpl>(IRP) {} | 
| Johannes Doerfert | d1b79e0 | 2019-08-07 22:46:11 +0000 | [diff] [blame] | 1496 |  | 
|  | 1497 | /// See AbstractAttribute::trackStatistics() | 
| Johannes Doerfert | 17b578b | 2019-08-14 21:46:25 +0000 | [diff] [blame] | 1498 | void trackStatistics() const override { STATS_DECLTRACK_ARG_ATTR(nonnull) } | 
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 1499 | }; | 
|  | 1500 |  | 
| Johannes Doerfert | b9b8791 | 2019-08-20 06:02:39 +0000 | [diff] [blame] | 1501 | struct AANonNullCallSiteArgument final : AANonNullFloating { | 
|  | 1502 | AANonNullCallSiteArgument(const IRPosition &IRP) : AANonNullFloating(IRP) {} | 
| Johannes Doerfert | d1b79e0 | 2019-08-07 22:46:11 +0000 | [diff] [blame] | 1503 |  | 
|  | 1504 | /// See AbstractAttribute::trackStatistics() | 
| Johannes Doerfert | 1aac182 | 2019-08-29 01:26:09 +0000 | [diff] [blame] | 1505 | void trackStatistics() const override { STATS_DECLTRACK_CSARG_ATTR(nonnull) } | 
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 1506 | }; | 
| Johannes Doerfert | 007153e | 2019-08-05 23:26:06 +0000 | [diff] [blame] | 1507 |  | 
| Johannes Doerfert | b9b8791 | 2019-08-20 06:02:39 +0000 | [diff] [blame] | 1508 | /// NonNull attribute for a call site return position. | 
|  | 1509 | struct AANonNullCallSiteReturned final | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 1510 | : AACallSiteReturnedFromReturned<AANonNull, AANonNullImpl> { | 
| Johannes Doerfert | b9b8791 | 2019-08-20 06:02:39 +0000 | [diff] [blame] | 1511 | AANonNullCallSiteReturned(const IRPosition &IRP) | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 1512 | : AACallSiteReturnedFromReturned<AANonNull, AANonNullImpl>(IRP) {} | 
| Johannes Doerfert | b9b8791 | 2019-08-20 06:02:39 +0000 | [diff] [blame] | 1513 |  | 
|  | 1514 | /// See AbstractAttribute::trackStatistics() | 
|  | 1515 | void trackStatistics() const override { STATS_DECLTRACK_CSRET_ATTR(nonnull) } | 
|  | 1516 | }; | 
| Johannes Doerfert | 66cf87e | 2019-08-16 19:49:00 +0000 | [diff] [blame] | 1517 |  | 
| Johannes Doerfert | 6dedc78 | 2019-08-16 21:31:11 +0000 | [diff] [blame] | 1518 | /// ------------------------ No-Recurse Attributes ---------------------------- | 
|  | 1519 |  | 
|  | 1520 | struct AANoRecurseImpl : public AANoRecurse { | 
|  | 1521 | AANoRecurseImpl(const IRPosition &IRP) : AANoRecurse(IRP) {} | 
|  | 1522 |  | 
| Johannes Doerfert | 6dedc78 | 2019-08-16 21:31:11 +0000 | [diff] [blame] | 1523 | /// See AbstractAttribute::getAsStr() | 
|  | 1524 | const std::string getAsStr() const override { | 
|  | 1525 | return getAssumed() ? "norecurse" : "may-recurse"; | 
|  | 1526 | } | 
|  | 1527 | }; | 
|  | 1528 |  | 
|  | 1529 | struct AANoRecurseFunction final : AANoRecurseImpl { | 
|  | 1530 | AANoRecurseFunction(const IRPosition &IRP) : AANoRecurseImpl(IRP) {} | 
|  | 1531 |  | 
|  | 1532 | /// See AbstractAttribute::updateImpl(...). | 
|  | 1533 | ChangeStatus updateImpl(Attributor &A) override { | 
|  | 1534 | // TODO: Implement this. | 
|  | 1535 | return indicatePessimisticFixpoint(); | 
|  | 1536 | } | 
|  | 1537 |  | 
|  | 1538 | void trackStatistics() const override { STATS_DECLTRACK_FN_ATTR(norecurse) } | 
|  | 1539 | }; | 
|  | 1540 |  | 
| Johannes Doerfert | 3fac668 | 2019-08-30 15:24:52 +0000 | [diff] [blame] | 1541 | /// NoRecurse attribute deduction for a call sites. | 
|  | 1542 | struct AANoRecurseCallSite final : AANoRecurseImpl { | 
|  | 1543 | AANoRecurseCallSite(const IRPosition &IRP) : AANoRecurseImpl(IRP) {} | 
|  | 1544 |  | 
|  | 1545 | /// See AbstractAttribute::initialize(...). | 
|  | 1546 | void initialize(Attributor &A) override { | 
|  | 1547 | AANoRecurseImpl::initialize(A); | 
|  | 1548 | Function *F = getAssociatedFunction(); | 
| Johannes Doerfert | b0412e4 | 2019-09-04 16:16:13 +0000 | [diff] [blame] | 1549 | if (!F) | 
| Johannes Doerfert | 3fac668 | 2019-08-30 15:24:52 +0000 | [diff] [blame] | 1550 | indicatePessimisticFixpoint(); | 
|  | 1551 | } | 
|  | 1552 |  | 
|  | 1553 | /// See AbstractAttribute::updateImpl(...). | 
|  | 1554 | ChangeStatus updateImpl(Attributor &A) override { | 
|  | 1555 | // TODO: Once we have call site specific value information we can provide | 
|  | 1556 | //       call site specific liveness information and then it makes | 
|  | 1557 | //       sense to specialize attributes for call sites arguments instead of | 
|  | 1558 | //       redirecting requests to the callee argument. | 
|  | 1559 | Function *F = getAssociatedFunction(); | 
|  | 1560 | const IRPosition &FnPos = IRPosition::function(*F); | 
|  | 1561 | auto &FnAA = A.getAAFor<AANoRecurse>(*this, FnPos); | 
|  | 1562 | return clampStateAndIndicateChange( | 
|  | 1563 | getState(), | 
|  | 1564 | static_cast<const AANoRecurse::StateType &>(FnAA.getState())); | 
|  | 1565 | } | 
|  | 1566 |  | 
|  | 1567 | /// See AbstractAttribute::trackStatistics() | 
|  | 1568 | void trackStatistics() const override { STATS_DECLTRACK_CS_ATTR(norecurse); } | 
|  | 1569 | }; | 
| Johannes Doerfert | 6dedc78 | 2019-08-16 21:31:11 +0000 | [diff] [blame] | 1570 |  | 
| Hideto Ueno | 11d3710 | 2019-07-17 15:15:43 +0000 | [diff] [blame] | 1571 | /// ------------------------ Will-Return Attributes ---------------------------- | 
|  | 1572 |  | 
| Hideto Ueno | 11d3710 | 2019-07-17 15:15:43 +0000 | [diff] [blame] | 1573 | // Helper function that checks whether a function has any cycle. | 
|  | 1574 | // TODO: Replace with more efficent code | 
| Johannes Doerfert | fe6dbad | 2019-08-16 19:36:17 +0000 | [diff] [blame] | 1575 | static bool containsCycle(Function &F) { | 
| Hideto Ueno | 11d3710 | 2019-07-17 15:15:43 +0000 | [diff] [blame] | 1576 | SmallPtrSet<BasicBlock *, 32> Visited; | 
|  | 1577 |  | 
|  | 1578 | // Traverse BB by dfs and check whether successor is already visited. | 
|  | 1579 | for (BasicBlock *BB : depth_first(&F)) { | 
|  | 1580 | Visited.insert(BB); | 
|  | 1581 | for (auto *SuccBB : successors(BB)) { | 
|  | 1582 | if (Visited.count(SuccBB)) | 
|  | 1583 | return true; | 
|  | 1584 | } | 
|  | 1585 | } | 
|  | 1586 | return false; | 
|  | 1587 | } | 
|  | 1588 |  | 
|  | 1589 | // Helper function that checks the function have a loop which might become an | 
|  | 1590 | // endless loop | 
|  | 1591 | // FIXME: Any cycle is regarded as endless loop for now. | 
|  | 1592 | //        We have to allow some patterns. | 
| Johannes Doerfert | 6dedc78 | 2019-08-16 21:31:11 +0000 | [diff] [blame] | 1593 | static bool containsPossiblyEndlessLoop(Function *F) { | 
|  | 1594 | return !F || !F->hasExactDefinition() || containsCycle(*F); | 
| Hideto Ueno | 11d3710 | 2019-07-17 15:15:43 +0000 | [diff] [blame] | 1595 | } | 
|  | 1596 |  | 
| Johannes Doerfert | fe6dbad | 2019-08-16 19:36:17 +0000 | [diff] [blame] | 1597 | struct AAWillReturnImpl : public AAWillReturn { | 
|  | 1598 | AAWillReturnImpl(const IRPosition &IRP) : AAWillReturn(IRP) {} | 
| Hideto Ueno | 11d3710 | 2019-07-17 15:15:43 +0000 | [diff] [blame] | 1599 |  | 
| Johannes Doerfert | fe6dbad | 2019-08-16 19:36:17 +0000 | [diff] [blame] | 1600 | /// See AbstractAttribute::initialize(...). | 
|  | 1601 | void initialize(Attributor &A) override { | 
| Johannes Doerfert | b0412e4 | 2019-09-04 16:16:13 +0000 | [diff] [blame] | 1602 | AAWillReturn::initialize(A); | 
| Hideto Ueno | 11d3710 | 2019-07-17 15:15:43 +0000 | [diff] [blame] | 1603 |  | 
| Johannes Doerfert | 6dedc78 | 2019-08-16 21:31:11 +0000 | [diff] [blame] | 1604 | Function *F = getAssociatedFunction(); | 
| Johannes Doerfert | fe6dbad | 2019-08-16 19:36:17 +0000 | [diff] [blame] | 1605 | if (containsPossiblyEndlessLoop(F)) | 
|  | 1606 | indicatePessimisticFixpoint(); | 
|  | 1607 | } | 
| Hideto Ueno | 11d3710 | 2019-07-17 15:15:43 +0000 | [diff] [blame] | 1608 |  | 
| Johannes Doerfert | fe6dbad | 2019-08-16 19:36:17 +0000 | [diff] [blame] | 1609 | /// See AbstractAttribute::updateImpl(...). | 
|  | 1610 | ChangeStatus updateImpl(Attributor &A) override { | 
| Johannes Doerfert | fe6dbad | 2019-08-16 19:36:17 +0000 | [diff] [blame] | 1611 | auto CheckForWillReturn = [&](Instruction &I) { | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 1612 | IRPosition IPos = IRPosition::callsite_function(ImmutableCallSite(&I)); | 
|  | 1613 | const auto &WillReturnAA = A.getAAFor<AAWillReturn>(*this, IPos); | 
|  | 1614 | if (WillReturnAA.isKnownWillReturn()) | 
| Johannes Doerfert | fe6dbad | 2019-08-16 19:36:17 +0000 | [diff] [blame] | 1615 | return true; | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 1616 | if (!WillReturnAA.isAssumedWillReturn()) | 
| Johannes Doerfert | fe6dbad | 2019-08-16 19:36:17 +0000 | [diff] [blame] | 1617 | return false; | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 1618 | const auto &NoRecurseAA = A.getAAFor<AANoRecurse>(*this, IPos); | 
|  | 1619 | return NoRecurseAA.isAssumedNoRecurse(); | 
| Johannes Doerfert | fe6dbad | 2019-08-16 19:36:17 +0000 | [diff] [blame] | 1620 | }; | 
|  | 1621 |  | 
|  | 1622 | if (!A.checkForAllCallLikeInstructions(CheckForWillReturn, *this)) | 
|  | 1623 | return indicatePessimisticFixpoint(); | 
|  | 1624 |  | 
|  | 1625 | return ChangeStatus::UNCHANGED; | 
|  | 1626 | } | 
|  | 1627 |  | 
| Johannes Doerfert | 6dedc78 | 2019-08-16 21:31:11 +0000 | [diff] [blame] | 1628 | /// See AbstractAttribute::getAsStr() | 
|  | 1629 | const std::string getAsStr() const override { | 
|  | 1630 | return getAssumed() ? "willreturn" : "may-noreturn"; | 
|  | 1631 | } | 
|  | 1632 | }; | 
|  | 1633 |  | 
|  | 1634 | struct AAWillReturnFunction final : AAWillReturnImpl { | 
|  | 1635 | AAWillReturnFunction(const IRPosition &IRP) : AAWillReturnImpl(IRP) {} | 
|  | 1636 |  | 
| Johannes Doerfert | fe6dbad | 2019-08-16 19:36:17 +0000 | [diff] [blame] | 1637 | /// See AbstractAttribute::trackStatistics() | 
| Johannes Doerfert | 6dedc78 | 2019-08-16 21:31:11 +0000 | [diff] [blame] | 1638 | void trackStatistics() const override { STATS_DECLTRACK_FN_ATTR(willreturn) } | 
| Johannes Doerfert | fe6dbad | 2019-08-16 19:36:17 +0000 | [diff] [blame] | 1639 | }; | 
| Hideto Ueno | 11d3710 | 2019-07-17 15:15:43 +0000 | [diff] [blame] | 1640 |  | 
| Johannes Doerfert | 66cf87e | 2019-08-16 19:49:00 +0000 | [diff] [blame] | 1641 | /// WillReturn attribute deduction for a call sites. | 
| Johannes Doerfert | 3fac668 | 2019-08-30 15:24:52 +0000 | [diff] [blame] | 1642 | struct AAWillReturnCallSite final : AAWillReturnImpl { | 
|  | 1643 | AAWillReturnCallSite(const IRPosition &IRP) : AAWillReturnImpl(IRP) {} | 
|  | 1644 |  | 
|  | 1645 | /// See AbstractAttribute::initialize(...). | 
|  | 1646 | void initialize(Attributor &A) override { | 
|  | 1647 | AAWillReturnImpl::initialize(A); | 
|  | 1648 | Function *F = getAssociatedFunction(); | 
| Johannes Doerfert | b0412e4 | 2019-09-04 16:16:13 +0000 | [diff] [blame] | 1649 | if (!F) | 
| Johannes Doerfert | 3fac668 | 2019-08-30 15:24:52 +0000 | [diff] [blame] | 1650 | indicatePessimisticFixpoint(); | 
|  | 1651 | } | 
|  | 1652 |  | 
|  | 1653 | /// See AbstractAttribute::updateImpl(...). | 
|  | 1654 | ChangeStatus updateImpl(Attributor &A) override { | 
|  | 1655 | // TODO: Once we have call site specific value information we can provide | 
|  | 1656 | //       call site specific liveness information and then it makes | 
|  | 1657 | //       sense to specialize attributes for call sites arguments instead of | 
|  | 1658 | //       redirecting requests to the callee argument. | 
|  | 1659 | Function *F = getAssociatedFunction(); | 
|  | 1660 | const IRPosition &FnPos = IRPosition::function(*F); | 
|  | 1661 | auto &FnAA = A.getAAFor<AAWillReturn>(*this, FnPos); | 
|  | 1662 | return clampStateAndIndicateChange( | 
|  | 1663 | getState(), | 
|  | 1664 | static_cast<const AAWillReturn::StateType &>(FnAA.getState())); | 
|  | 1665 | } | 
|  | 1666 |  | 
|  | 1667 | /// See AbstractAttribute::trackStatistics() | 
|  | 1668 | void trackStatistics() const override { STATS_DECLTRACK_CS_ATTR(willreturn); } | 
|  | 1669 | }; | 
| Johannes Doerfert | 66cf87e | 2019-08-16 19:49:00 +0000 | [diff] [blame] | 1670 |  | 
| Stefan Stipanovic | 69ebb02 | 2019-07-22 19:36:27 +0000 | [diff] [blame] | 1671 | /// ------------------------ NoAlias Argument Attribute ------------------------ | 
|  | 1672 |  | 
| Johannes Doerfert | 344d038 | 2019-08-07 22:34:26 +0000 | [diff] [blame] | 1673 | struct AANoAliasImpl : AANoAlias { | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 1674 | AANoAliasImpl(const IRPosition &IRP) : AANoAlias(IRP) {} | 
| Stefan Stipanovic | 69ebb02 | 2019-07-22 19:36:27 +0000 | [diff] [blame] | 1675 |  | 
| Stefan Stipanovic | 69ebb02 | 2019-07-22 19:36:27 +0000 | [diff] [blame] | 1676 | const std::string getAsStr() const override { | 
|  | 1677 | return getAssumed() ? "noalias" : "may-alias"; | 
|  | 1678 | } | 
| Stefan Stipanovic | 69ebb02 | 2019-07-22 19:36:27 +0000 | [diff] [blame] | 1679 | }; | 
|  | 1680 |  | 
| Johannes Doerfert | 6dedc78 | 2019-08-16 21:31:11 +0000 | [diff] [blame] | 1681 | /// NoAlias attribute for a floating value. | 
|  | 1682 | struct AANoAliasFloating final : AANoAliasImpl { | 
|  | 1683 | AANoAliasFloating(const IRPosition &IRP) : AANoAliasImpl(IRP) {} | 
|  | 1684 |  | 
| Hideto Ueno | cbab334 | 2019-08-29 05:52:00 +0000 | [diff] [blame] | 1685 | /// See AbstractAttribute::initialize(...). | 
|  | 1686 | void initialize(Attributor &A) override { | 
| Hideto Ueno | 1d68ed8 | 2019-09-11 07:00:33 +0000 | [diff] [blame] | 1687 | AANoAliasImpl::initialize(A); | 
|  | 1688 | if (isa<AllocaInst>(getAnchorValue())) | 
|  | 1689 | indicateOptimisticFixpoint(); | 
| Hideto Ueno | cbab334 | 2019-08-29 05:52:00 +0000 | [diff] [blame] | 1690 | } | 
|  | 1691 |  | 
| Johannes Doerfert | 6dedc78 | 2019-08-16 21:31:11 +0000 | [diff] [blame] | 1692 | /// See AbstractAttribute::updateImpl(...). | 
|  | 1693 | ChangeStatus updateImpl(Attributor &A) override { | 
|  | 1694 | // TODO: Implement this. | 
|  | 1695 | return indicatePessimisticFixpoint(); | 
|  | 1696 | } | 
|  | 1697 |  | 
|  | 1698 | /// See AbstractAttribute::trackStatistics() | 
|  | 1699 | void trackStatistics() const override { | 
|  | 1700 | STATS_DECLTRACK_FLOATING_ATTR(noalias) | 
|  | 1701 | } | 
|  | 1702 | }; | 
|  | 1703 |  | 
|  | 1704 | /// NoAlias attribute for an argument. | 
| Hideto Ueno | cbab334 | 2019-08-29 05:52:00 +0000 | [diff] [blame] | 1705 | struct AANoAliasArgument final | 
|  | 1706 | : AAArgumentFromCallSiteArguments<AANoAlias, AANoAliasImpl> { | 
|  | 1707 | AANoAliasArgument(const IRPosition &IRP) | 
|  | 1708 | : AAArgumentFromCallSiteArguments<AANoAlias, AANoAliasImpl>(IRP) {} | 
| Johannes Doerfert | 6dedc78 | 2019-08-16 21:31:11 +0000 | [diff] [blame] | 1709 |  | 
|  | 1710 | /// See AbstractAttribute::trackStatistics() | 
|  | 1711 | void trackStatistics() const override { STATS_DECLTRACK_ARG_ATTR(noalias) } | 
|  | 1712 | }; | 
|  | 1713 |  | 
|  | 1714 | struct AANoAliasCallSiteArgument final : AANoAliasImpl { | 
|  | 1715 | AANoAliasCallSiteArgument(const IRPosition &IRP) : AANoAliasImpl(IRP) {} | 
|  | 1716 |  | 
| Hideto Ueno | cbab334 | 2019-08-29 05:52:00 +0000 | [diff] [blame] | 1717 | /// See AbstractAttribute::initialize(...). | 
|  | 1718 | void initialize(Attributor &A) override { | 
| Hideto Ueno | 6381b14 | 2019-08-30 10:00:32 +0000 | [diff] [blame] | 1719 | // See callsite argument attribute and callee argument attribute. | 
|  | 1720 | ImmutableCallSite ICS(&getAnchorValue()); | 
|  | 1721 | if (ICS.paramHasAttr(getArgNo(), Attribute::NoAlias)) | 
|  | 1722 | indicateOptimisticFixpoint(); | 
| Hideto Ueno | cbab334 | 2019-08-29 05:52:00 +0000 | [diff] [blame] | 1723 | } | 
|  | 1724 |  | 
| Johannes Doerfert | 6dedc78 | 2019-08-16 21:31:11 +0000 | [diff] [blame] | 1725 | /// See AbstractAttribute::updateImpl(...). | 
|  | 1726 | ChangeStatus updateImpl(Attributor &A) override { | 
| Hideto Ueno | 1d68ed8 | 2019-09-11 07:00:33 +0000 | [diff] [blame] | 1727 | // We can deduce "noalias" if the following conditions hold. | 
|  | 1728 | // (i)   Associated value is assumed to be noalias in the definition. | 
|  | 1729 | // (ii)  Associated value is assumed to be no-capture in all the uses | 
|  | 1730 | //       possibly executed before this callsite. | 
|  | 1731 | // (iii) There is no other pointer argument which could alias with the | 
|  | 1732 | //       value. | 
|  | 1733 |  | 
|  | 1734 | const Value &V = getAssociatedValue(); | 
|  | 1735 | const IRPosition IRP = IRPosition::value(V); | 
|  | 1736 |  | 
|  | 1737 | // (i) Check whether noalias holds in the definition. | 
|  | 1738 |  | 
|  | 1739 | auto &NoAliasAA = A.getAAFor<AANoAlias>(*this, IRP); | 
|  | 1740 |  | 
|  | 1741 | if (!NoAliasAA.isAssumedNoAlias()) | 
|  | 1742 | return indicatePessimisticFixpoint(); | 
|  | 1743 |  | 
|  | 1744 | LLVM_DEBUG(dbgs() << "[Attributor][AANoAliasCSArg] " << V | 
|  | 1745 | << " is assumed NoAlias in the definition\n"); | 
|  | 1746 |  | 
|  | 1747 | // (ii) Check whether the value is captured in the scope using AANoCapture. | 
|  | 1748 | //      FIXME: This is conservative though, it is better to look at CFG and | 
|  | 1749 | //             check only uses possibly executed before this callsite. | 
|  | 1750 |  | 
|  | 1751 | auto &NoCaptureAA = A.getAAFor<AANoCapture>(*this, IRP); | 
|  | 1752 | if (!NoCaptureAA.isAssumedNoCaptureMaybeReturned()) | 
|  | 1753 | return indicatePessimisticFixpoint(); | 
|  | 1754 |  | 
|  | 1755 | // (iii) Check there is no other pointer argument which could alias with the | 
|  | 1756 | // value. | 
|  | 1757 | ImmutableCallSite ICS(&getAnchorValue()); | 
|  | 1758 | for (unsigned i = 0; i < ICS.getNumArgOperands(); i++) { | 
|  | 1759 | if (getArgNo() == (int)i) | 
|  | 1760 | continue; | 
|  | 1761 | const Value *ArgOp = ICS.getArgOperand(i); | 
|  | 1762 | if (!ArgOp->getType()->isPointerTy()) | 
|  | 1763 | continue; | 
|  | 1764 |  | 
| Hideto Ueno | 30d86f1 | 2019-09-17 06:53:27 +0000 | [diff] [blame] | 1765 | if (const Function *F = getAnchorScope()) { | 
|  | 1766 | if (AAResults *AAR = A.getInfoCache().getAAResultsForFunction(*F)) { | 
|  | 1767 | LLVM_DEBUG(dbgs() | 
|  | 1768 | << "[Attributor][NoAliasCSArg] Check alias between " | 
|  | 1769 | "callsite arguments " | 
|  | 1770 | << AAR->isNoAlias(&getAssociatedValue(), ArgOp) << " " | 
|  | 1771 | << getAssociatedValue() << " " << *ArgOp << "\n"); | 
| Hideto Ueno | 1d68ed8 | 2019-09-11 07:00:33 +0000 | [diff] [blame] | 1772 |  | 
| Hideto Ueno | 30d86f1 | 2019-09-17 06:53:27 +0000 | [diff] [blame] | 1773 | if (AAR->isNoAlias(&getAssociatedValue(), ArgOp)) | 
|  | 1774 | continue; | 
|  | 1775 | } | 
|  | 1776 | } | 
| Hideto Ueno | 1d68ed8 | 2019-09-11 07:00:33 +0000 | [diff] [blame] | 1777 | return indicatePessimisticFixpoint(); | 
|  | 1778 | } | 
|  | 1779 |  | 
|  | 1780 | return ChangeStatus::UNCHANGED; | 
| Johannes Doerfert | 6dedc78 | 2019-08-16 21:31:11 +0000 | [diff] [blame] | 1781 | } | 
|  | 1782 |  | 
|  | 1783 | /// See AbstractAttribute::trackStatistics() | 
| Johannes Doerfert | 56e9b60 | 2019-09-04 20:34:57 +0000 | [diff] [blame] | 1784 | void trackStatistics() const override { STATS_DECLTRACK_CSARG_ATTR(noalias) } | 
| Johannes Doerfert | 6dedc78 | 2019-08-16 21:31:11 +0000 | [diff] [blame] | 1785 | }; | 
|  | 1786 |  | 
| Stefan Stipanovic | 69ebb02 | 2019-07-22 19:36:27 +0000 | [diff] [blame] | 1787 | /// NoAlias attribute for function return value. | 
| Johannes Doerfert | beb5150 | 2019-08-07 22:36:15 +0000 | [diff] [blame] | 1788 | struct AANoAliasReturned final : AANoAliasImpl { | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 1789 | AANoAliasReturned(const IRPosition &IRP) : AANoAliasImpl(IRP) {} | 
| Stefan Stipanovic | 69ebb02 | 2019-07-22 19:36:27 +0000 | [diff] [blame] | 1790 |  | 
| Stefan Stipanovic | 69ebb02 | 2019-07-22 19:36:27 +0000 | [diff] [blame] | 1791 | /// See AbstractAttribute::updateImpl(...). | 
| Johannes Doerfert | fe6dbad | 2019-08-16 19:36:17 +0000 | [diff] [blame] | 1792 | virtual ChangeStatus updateImpl(Attributor &A) override { | 
|  | 1793 |  | 
|  | 1794 | auto CheckReturnValue = [&](Value &RV) -> bool { | 
|  | 1795 | if (Constant *C = dyn_cast<Constant>(&RV)) | 
|  | 1796 | if (C->isNullValue() || isa<UndefValue>(C)) | 
|  | 1797 | return true; | 
|  | 1798 |  | 
|  | 1799 | /// For now, we can only deduce noalias if we have call sites. | 
|  | 1800 | /// FIXME: add more support. | 
|  | 1801 | ImmutableCallSite ICS(&RV); | 
|  | 1802 | if (!ICS) | 
|  | 1803 | return false; | 
|  | 1804 |  | 
| Johannes Doerfert | 7516a5e | 2019-09-03 20:37:24 +0000 | [diff] [blame] | 1805 | const IRPosition &RVPos = IRPosition::value(RV); | 
|  | 1806 | const auto &NoAliasAA = A.getAAFor<AANoAlias>(*this, RVPos); | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 1807 | if (!NoAliasAA.isAssumedNoAlias()) | 
|  | 1808 | return false; | 
| Johannes Doerfert | fe6dbad | 2019-08-16 19:36:17 +0000 | [diff] [blame] | 1809 |  | 
| Johannes Doerfert | 7516a5e | 2019-09-03 20:37:24 +0000 | [diff] [blame] | 1810 | const auto &NoCaptureAA = A.getAAFor<AANoCapture>(*this, RVPos); | 
|  | 1811 | return NoCaptureAA.isAssumedNoCaptureMaybeReturned(); | 
| Johannes Doerfert | fe6dbad | 2019-08-16 19:36:17 +0000 | [diff] [blame] | 1812 | }; | 
|  | 1813 |  | 
|  | 1814 | if (!A.checkForAllReturnedValues(CheckReturnValue, *this)) | 
|  | 1815 | return indicatePessimisticFixpoint(); | 
|  | 1816 |  | 
|  | 1817 | return ChangeStatus::UNCHANGED; | 
|  | 1818 | } | 
| Johannes Doerfert | d1b79e0 | 2019-08-07 22:46:11 +0000 | [diff] [blame] | 1819 |  | 
|  | 1820 | /// See AbstractAttribute::trackStatistics() | 
| Johannes Doerfert | 17b578b | 2019-08-14 21:46:25 +0000 | [diff] [blame] | 1821 | void trackStatistics() const override { STATS_DECLTRACK_FNRET_ATTR(noalias) } | 
| Stefan Stipanovic | 69ebb02 | 2019-07-22 19:36:27 +0000 | [diff] [blame] | 1822 | }; | 
|  | 1823 |  | 
| Johannes Doerfert | 66cf87e | 2019-08-16 19:49:00 +0000 | [diff] [blame] | 1824 | /// NoAlias attribute deduction for a call site return value. | 
| Johannes Doerfert | 3fac668 | 2019-08-30 15:24:52 +0000 | [diff] [blame] | 1825 | struct AANoAliasCallSiteReturned final : AANoAliasImpl { | 
|  | 1826 | AANoAliasCallSiteReturned(const IRPosition &IRP) : AANoAliasImpl(IRP) {} | 
|  | 1827 |  | 
|  | 1828 | /// See AbstractAttribute::initialize(...). | 
|  | 1829 | void initialize(Attributor &A) override { | 
|  | 1830 | AANoAliasImpl::initialize(A); | 
|  | 1831 | Function *F = getAssociatedFunction(); | 
| Johannes Doerfert | b0412e4 | 2019-09-04 16:16:13 +0000 | [diff] [blame] | 1832 | if (!F) | 
| Johannes Doerfert | 3fac668 | 2019-08-30 15:24:52 +0000 | [diff] [blame] | 1833 | indicatePessimisticFixpoint(); | 
|  | 1834 | } | 
|  | 1835 |  | 
|  | 1836 | /// See AbstractAttribute::updateImpl(...). | 
|  | 1837 | ChangeStatus updateImpl(Attributor &A) override { | 
|  | 1838 | // TODO: Once we have call site specific value information we can provide | 
|  | 1839 | //       call site specific liveness information and then it makes | 
|  | 1840 | //       sense to specialize attributes for call sites arguments instead of | 
|  | 1841 | //       redirecting requests to the callee argument. | 
|  | 1842 | Function *F = getAssociatedFunction(); | 
|  | 1843 | const IRPosition &FnPos = IRPosition::returned(*F); | 
|  | 1844 | auto &FnAA = A.getAAFor<AANoAlias>(*this, FnPos); | 
|  | 1845 | return clampStateAndIndicateChange( | 
|  | 1846 | getState(), static_cast<const AANoAlias::StateType &>(FnAA.getState())); | 
|  | 1847 | } | 
|  | 1848 |  | 
|  | 1849 | /// See AbstractAttribute::trackStatistics() | 
| Johannes Doerfert | 56e9b60 | 2019-09-04 20:34:57 +0000 | [diff] [blame] | 1850 | void trackStatistics() const override { STATS_DECLTRACK_CSRET_ATTR(noalias); } | 
| Johannes Doerfert | 3fac668 | 2019-08-30 15:24:52 +0000 | [diff] [blame] | 1851 | }; | 
| Johannes Doerfert | 66cf87e | 2019-08-16 19:49:00 +0000 | [diff] [blame] | 1852 |  | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 1853 | /// -------------------AAIsDead Function Attribute----------------------- | 
|  | 1854 |  | 
| Johannes Doerfert | 344d038 | 2019-08-07 22:34:26 +0000 | [diff] [blame] | 1855 | struct AAIsDeadImpl : public AAIsDead { | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 1856 | AAIsDeadImpl(const IRPosition &IRP) : AAIsDead(IRP) {} | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 1857 |  | 
| Johannes Doerfert | ece8190 | 2019-08-12 22:05:53 +0000 | [diff] [blame] | 1858 | void initialize(Attributor &A) override { | 
| Johannes Doerfert | 6dedc78 | 2019-08-16 21:31:11 +0000 | [diff] [blame] | 1859 | const Function *F = getAssociatedFunction(); | 
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 1860 | if (F && !F->isDeclaration()) | 
|  | 1861 | exploreFromEntry(A, F); | 
| Stefan Stipanovic | 26121ae | 2019-08-20 23:16:57 +0000 | [diff] [blame] | 1862 | } | 
|  | 1863 |  | 
|  | 1864 | void exploreFromEntry(Attributor &A, const Function *F) { | 
| Johannes Doerfert | 6dedc78 | 2019-08-16 21:31:11 +0000 | [diff] [blame] | 1865 | ToBeExploredPaths.insert(&(F->getEntryBlock().front())); | 
| Stefan Stipanovic | 26121ae | 2019-08-20 23:16:57 +0000 | [diff] [blame] | 1866 |  | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 1867 | for (size_t i = 0; i < ToBeExploredPaths.size(); ++i) | 
| Johannes Doerfert | 4361da2 | 2019-08-04 18:38:53 +0000 | [diff] [blame] | 1868 | if (const Instruction *NextNoReturnI = | 
|  | 1869 | findNextNoReturn(A, ToBeExploredPaths[i])) | 
|  | 1870 | NoReturnCalls.insert(NextNoReturnI); | 
| Johannes Doerfert | 3ab9e8b | 2019-09-17 10:52:41 +0000 | [diff] [blame^] | 1871 |  | 
|  | 1872 | // Mark the block live after we looked for no-return instructions. | 
|  | 1873 | assumeLive(A, F->getEntryBlock()); | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 1874 | } | 
|  | 1875 |  | 
| Johannes Doerfert | 4361da2 | 2019-08-04 18:38:53 +0000 | [diff] [blame] | 1876 | /// Find the next assumed noreturn instruction in the block of \p I starting | 
|  | 1877 | /// from, thus including, \p I. | 
|  | 1878 | /// | 
|  | 1879 | /// The caller is responsible to monitor the ToBeExploredPaths set as new | 
|  | 1880 | /// instructions discovered in other basic block will be placed in there. | 
|  | 1881 | /// | 
|  | 1882 | /// \returns The next assumed noreturn instructions in the block of \p I | 
|  | 1883 | ///          starting from, thus including, \p I. | 
|  | 1884 | const Instruction *findNextNoReturn(Attributor &A, const Instruction *I); | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 1885 |  | 
| Johannes Doerfert | beb5150 | 2019-08-07 22:36:15 +0000 | [diff] [blame] | 1886 | /// See AbstractAttribute::getAsStr(). | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 1887 | const std::string getAsStr() const override { | 
| Johannes Doerfert | beb5150 | 2019-08-07 22:36:15 +0000 | [diff] [blame] | 1888 | return "Live[#BB " + std::to_string(AssumedLiveBlocks.size()) + "/" + | 
| Johannes Doerfert | 6dedc78 | 2019-08-16 21:31:11 +0000 | [diff] [blame] | 1889 | std::to_string(getAssociatedFunction()->size()) + "][#NRI " + | 
| Johannes Doerfert | beb5150 | 2019-08-07 22:36:15 +0000 | [diff] [blame] | 1890 | std::to_string(NoReturnCalls.size()) + "]"; | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 1891 | } | 
|  | 1892 |  | 
|  | 1893 | /// See AbstractAttribute::manifest(...). | 
|  | 1894 | ChangeStatus manifest(Attributor &A) override { | 
|  | 1895 | assert(getState().isValidState() && | 
|  | 1896 | "Attempted to manifest an invalid state!"); | 
|  | 1897 |  | 
|  | 1898 | ChangeStatus HasChanged = ChangeStatus::UNCHANGED; | 
| Stefan Stipanovic | 26121ae | 2019-08-20 23:16:57 +0000 | [diff] [blame] | 1899 | Function &F = *getAssociatedFunction(); | 
|  | 1900 |  | 
|  | 1901 | if (AssumedLiveBlocks.empty()) { | 
| Johannes Doerfert | b19cd27 | 2019-09-03 20:42:16 +0000 | [diff] [blame] | 1902 | A.deleteAfterManifest(F); | 
| Stefan Stipanovic | 26121ae | 2019-08-20 23:16:57 +0000 | [diff] [blame] | 1903 | return ChangeStatus::CHANGED; | 
|  | 1904 | } | 
| Johannes Doerfert | 924d213 | 2019-08-05 21:34:45 +0000 | [diff] [blame] | 1905 |  | 
| Johannes Doerfert | beb5150 | 2019-08-07 22:36:15 +0000 | [diff] [blame] | 1906 | // Flag to determine if we can change an invoke to a call assuming the | 
|  | 1907 | // callee is nounwind. This is not possible if the personality of the | 
|  | 1908 | // function allows to catch asynchronous exceptions. | 
| Johannes Doerfert | 924d213 | 2019-08-05 21:34:45 +0000 | [diff] [blame] | 1909 | bool Invoke2CallAllowed = !mayCatchAsynchronousExceptions(F); | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 1910 |  | 
| Johannes Doerfert | 4361da2 | 2019-08-04 18:38:53 +0000 | [diff] [blame] | 1911 | for (const Instruction *NRC : NoReturnCalls) { | 
|  | 1912 | Instruction *I = const_cast<Instruction *>(NRC); | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 1913 | BasicBlock *BB = I->getParent(); | 
| Johannes Doerfert | 4361da2 | 2019-08-04 18:38:53 +0000 | [diff] [blame] | 1914 | Instruction *SplitPos = I->getNextNode(); | 
| Johannes Doerfert | d410805 | 2019-08-21 20:56:41 +0000 | [diff] [blame] | 1915 | // TODO: mark stuff before unreachable instructions as dead. | 
|  | 1916 | if (isa_and_nonnull<UnreachableInst>(SplitPos)) | 
|  | 1917 | continue; | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 1918 |  | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 1919 | if (auto *II = dyn_cast<InvokeInst>(I)) { | 
| Johannes Doerfert | 3d7bbc6 | 2019-08-05 21:35:02 +0000 | [diff] [blame] | 1920 | // If we keep the invoke the split position is at the beginning of the | 
|  | 1921 | // normal desitination block (it invokes a noreturn function after all). | 
|  | 1922 | BasicBlock *NormalDestBB = II->getNormalDest(); | 
|  | 1923 | SplitPos = &NormalDestBB->front(); | 
|  | 1924 |  | 
| Johannes Doerfert | 4361da2 | 2019-08-04 18:38:53 +0000 | [diff] [blame] | 1925 | /// Invoke is replaced with a call and unreachable is placed after it if | 
|  | 1926 | /// the callee is nounwind and noreturn. Otherwise, we keep the invoke | 
|  | 1927 | /// and only place an unreachable in the normal successor. | 
| Johannes Doerfert | 924d213 | 2019-08-05 21:34:45 +0000 | [diff] [blame] | 1928 | if (Invoke2CallAllowed) { | 
| Michael Liao | a99086d | 2019-08-20 21:02:31 +0000 | [diff] [blame] | 1929 | if (II->getCalledFunction()) { | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 1930 | const IRPosition &IPos = IRPosition::callsite_function(*II); | 
|  | 1931 | const auto &AANoUnw = A.getAAFor<AANoUnwind>(*this, IPos); | 
|  | 1932 | if (AANoUnw.isAssumedNoUnwind()) { | 
| Johannes Doerfert | 924d213 | 2019-08-05 21:34:45 +0000 | [diff] [blame] | 1933 | LLVM_DEBUG(dbgs() | 
|  | 1934 | << "[AAIsDead] Replace invoke with call inst\n"); | 
| Johannes Doerfert | 3d7bbc6 | 2019-08-05 21:35:02 +0000 | [diff] [blame] | 1935 | // We do not need an invoke (II) but instead want a call followed | 
|  | 1936 | // by an unreachable. However, we do not remove II as other | 
|  | 1937 | // abstract attributes might have it cached as part of their | 
|  | 1938 | // results. Given that we modify the CFG anyway, we simply keep II | 
|  | 1939 | // around but in a new dead block. To avoid II being live through | 
|  | 1940 | // a different edge we have to ensure the block we place it in is | 
|  | 1941 | // only reached from the current block of II and then not reached | 
|  | 1942 | // at all when we insert the unreachable. | 
|  | 1943 | SplitBlockPredecessors(NormalDestBB, {BB}, ".i2c"); | 
|  | 1944 | CallInst *CI = createCallMatchingInvoke(II); | 
|  | 1945 | CI->insertBefore(II); | 
|  | 1946 | CI->takeName(II); | 
|  | 1947 | II->replaceAllUsesWith(CI); | 
|  | 1948 | SplitPos = CI->getNextNode(); | 
| Johannes Doerfert | 924d213 | 2019-08-05 21:34:45 +0000 | [diff] [blame] | 1949 | } | 
| Johannes Doerfert | 4361da2 | 2019-08-04 18:38:53 +0000 | [diff] [blame] | 1950 | } | 
|  | 1951 | } | 
| Johannes Doerfert | b19cd27 | 2019-09-03 20:42:16 +0000 | [diff] [blame] | 1952 |  | 
| Johannes Doerfert | 7ab5253 | 2019-09-04 20:34:52 +0000 | [diff] [blame] | 1953 | if (SplitPos == &NormalDestBB->front()) { | 
|  | 1954 | // If this is an invoke of a noreturn function the edge to the normal | 
|  | 1955 | // destination block is dead but not necessarily the block itself. | 
|  | 1956 | // TODO: We need to move to an edge based system during deduction and | 
|  | 1957 | //       also manifest. | 
|  | 1958 | assert(!NormalDestBB->isLandingPad() && | 
|  | 1959 | "Expected the normal destination not to be a landingpad!"); | 
|  | 1960 | BasicBlock *SplitBB = | 
|  | 1961 | SplitBlockPredecessors(NormalDestBB, {BB}, ".dead"); | 
|  | 1962 | // The split block is live even if it contains only an unreachable | 
|  | 1963 | // instruction at the end. | 
|  | 1964 | assumeLive(A, *SplitBB); | 
|  | 1965 | SplitPos = SplitBB->getTerminator(); | 
|  | 1966 | } | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 1967 | } | 
|  | 1968 |  | 
| Johannes Doerfert | 3d7bbc6 | 2019-08-05 21:35:02 +0000 | [diff] [blame] | 1969 | BB = SplitPos->getParent(); | 
| Johannes Doerfert | 4361da2 | 2019-08-04 18:38:53 +0000 | [diff] [blame] | 1970 | SplitBlock(BB, SplitPos); | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 1971 | changeToUnreachable(BB->getTerminator(), /* UseLLVMTrap */ false); | 
|  | 1972 | HasChanged = ChangeStatus::CHANGED; | 
|  | 1973 | } | 
|  | 1974 |  | 
| Johannes Doerfert | b19cd27 | 2019-09-03 20:42:16 +0000 | [diff] [blame] | 1975 | for (BasicBlock &BB : F) | 
|  | 1976 | if (!AssumedLiveBlocks.count(&BB)) | 
|  | 1977 | A.deleteAfterManifest(BB); | 
|  | 1978 |  | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 1979 | return HasChanged; | 
|  | 1980 | } | 
|  | 1981 |  | 
|  | 1982 | /// See AbstractAttribute::updateImpl(...). | 
| Johannes Doerfert | ece8190 | 2019-08-12 22:05:53 +0000 | [diff] [blame] | 1983 | ChangeStatus updateImpl(Attributor &A) override; | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 1984 |  | 
| Stefan Stipanovic | d021617 | 2019-08-02 21:31:22 +0000 | [diff] [blame] | 1985 | /// See AAIsDead::isAssumedDead(BasicBlock *). | 
| Johannes Doerfert | 4361da2 | 2019-08-04 18:38:53 +0000 | [diff] [blame] | 1986 | bool isAssumedDead(const BasicBlock *BB) const override { | 
| Johannes Doerfert | 6dedc78 | 2019-08-16 21:31:11 +0000 | [diff] [blame] | 1987 | assert(BB->getParent() == getAssociatedFunction() && | 
| Stefan Stipanovic | d021617 | 2019-08-02 21:31:22 +0000 | [diff] [blame] | 1988 | "BB must be in the same anchor scope function."); | 
|  | 1989 |  | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 1990 | if (!getAssumed()) | 
|  | 1991 | return false; | 
|  | 1992 | return !AssumedLiveBlocks.count(BB); | 
|  | 1993 | } | 
|  | 1994 |  | 
| Stefan Stipanovic | d021617 | 2019-08-02 21:31:22 +0000 | [diff] [blame] | 1995 | /// See AAIsDead::isKnownDead(BasicBlock *). | 
| Johannes Doerfert | 4361da2 | 2019-08-04 18:38:53 +0000 | [diff] [blame] | 1996 | bool isKnownDead(const BasicBlock *BB) const override { | 
| Stefan Stipanovic | d021617 | 2019-08-02 21:31:22 +0000 | [diff] [blame] | 1997 | return getKnown() && isAssumedDead(BB); | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 1998 | } | 
|  | 1999 |  | 
| Stefan Stipanovic | d021617 | 2019-08-02 21:31:22 +0000 | [diff] [blame] | 2000 | /// See AAIsDead::isAssumed(Instruction *I). | 
| Johannes Doerfert | 4361da2 | 2019-08-04 18:38:53 +0000 | [diff] [blame] | 2001 | bool isAssumedDead(const Instruction *I) const override { | 
| Johannes Doerfert | 6dedc78 | 2019-08-16 21:31:11 +0000 | [diff] [blame] | 2002 | assert(I->getParent()->getParent() == getAssociatedFunction() && | 
| Stefan Stipanovic | d021617 | 2019-08-02 21:31:22 +0000 | [diff] [blame] | 2003 | "Instruction must be in the same anchor scope function."); | 
|  | 2004 |  | 
| Stefan Stipanovic | 7849e41 | 2019-08-03 15:27:41 +0000 | [diff] [blame] | 2005 | if (!getAssumed()) | 
| Stefan Stipanovic | d021617 | 2019-08-02 21:31:22 +0000 | [diff] [blame] | 2006 | return false; | 
|  | 2007 |  | 
|  | 2008 | // If it is not in AssumedLiveBlocks then it for sure dead. | 
|  | 2009 | // Otherwise, it can still be after noreturn call in a live block. | 
|  | 2010 | if (!AssumedLiveBlocks.count(I->getParent())) | 
|  | 2011 | return true; | 
|  | 2012 |  | 
|  | 2013 | // If it is not after a noreturn call, than it is live. | 
| Johannes Doerfert | 4361da2 | 2019-08-04 18:38:53 +0000 | [diff] [blame] | 2014 | return isAfterNoReturn(I); | 
| Stefan Stipanovic | d021617 | 2019-08-02 21:31:22 +0000 | [diff] [blame] | 2015 | } | 
|  | 2016 |  | 
|  | 2017 | /// See AAIsDead::isKnownDead(Instruction *I). | 
| Johannes Doerfert | 4361da2 | 2019-08-04 18:38:53 +0000 | [diff] [blame] | 2018 | bool isKnownDead(const Instruction *I) const override { | 
| Stefan Stipanovic | d021617 | 2019-08-02 21:31:22 +0000 | [diff] [blame] | 2019 | return getKnown() && isAssumedDead(I); | 
|  | 2020 | } | 
|  | 2021 |  | 
|  | 2022 | /// Check if instruction is after noreturn call, in other words, assumed dead. | 
| Johannes Doerfert | 4361da2 | 2019-08-04 18:38:53 +0000 | [diff] [blame] | 2023 | bool isAfterNoReturn(const Instruction *I) const; | 
| Stefan Stipanovic | d021617 | 2019-08-02 21:31:22 +0000 | [diff] [blame] | 2024 |  | 
| Johannes Doerfert | 924d213 | 2019-08-05 21:34:45 +0000 | [diff] [blame] | 2025 | /// Determine if \p F might catch asynchronous exceptions. | 
|  | 2026 | static bool mayCatchAsynchronousExceptions(const Function &F) { | 
|  | 2027 | return F.hasPersonalityFn() && !canSimplifyInvokeNoUnwind(&F); | 
|  | 2028 | } | 
|  | 2029 |  | 
| Johannes Doerfert | 2f62206 | 2019-09-04 16:35:20 +0000 | [diff] [blame] | 2030 | /// Assume \p BB is (partially) live now and indicate to the Attributor \p A | 
|  | 2031 | /// that internal function called from \p BB should now be looked at. | 
|  | 2032 | void assumeLive(Attributor &A, const BasicBlock &BB) { | 
|  | 2033 | if (!AssumedLiveBlocks.insert(&BB).second) | 
|  | 2034 | return; | 
|  | 2035 |  | 
|  | 2036 | // We assume that all of BB is (probably) live now and if there are calls to | 
|  | 2037 | // internal functions we will assume that those are now live as well. This | 
|  | 2038 | // is a performance optimization for blocks with calls to a lot of internal | 
|  | 2039 | // functions. It can however cause dead functions to be treated as live. | 
|  | 2040 | for (const Instruction &I : BB) | 
|  | 2041 | if (ImmutableCallSite ICS = ImmutableCallSite(&I)) | 
|  | 2042 | if (const Function *F = ICS.getCalledFunction()) | 
|  | 2043 | if (F->hasInternalLinkage()) | 
|  | 2044 | A.markLiveInternalFunction(*F); | 
|  | 2045 | } | 
|  | 2046 |  | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 2047 | /// Collection of to be explored paths. | 
| Johannes Doerfert | 4361da2 | 2019-08-04 18:38:53 +0000 | [diff] [blame] | 2048 | SmallSetVector<const Instruction *, 8> ToBeExploredPaths; | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 2049 |  | 
|  | 2050 | /// Collection of all assumed live BasicBlocks. | 
| Johannes Doerfert | 4361da2 | 2019-08-04 18:38:53 +0000 | [diff] [blame] | 2051 | DenseSet<const BasicBlock *> AssumedLiveBlocks; | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 2052 |  | 
|  | 2053 | /// Collection of calls with noreturn attribute, assumed or knwon. | 
| Johannes Doerfert | 4361da2 | 2019-08-04 18:38:53 +0000 | [diff] [blame] | 2054 | SmallSetVector<const Instruction *, 4> NoReturnCalls; | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 2055 | }; | 
|  | 2056 |  | 
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 2057 | struct AAIsDeadFunction final : public AAIsDeadImpl { | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 2058 | AAIsDeadFunction(const IRPosition &IRP) : AAIsDeadImpl(IRP) {} | 
| Johannes Doerfert | d1b79e0 | 2019-08-07 22:46:11 +0000 | [diff] [blame] | 2059 |  | 
|  | 2060 | /// See AbstractAttribute::trackStatistics() | 
|  | 2061 | void trackStatistics() const override { | 
| Johannes Doerfert | d1b79e0 | 2019-08-07 22:46:11 +0000 | [diff] [blame] | 2062 | STATS_DECL(PartiallyDeadBlocks, Function, | 
|  | 2063 | "Number of basic blocks classified as partially dead"); | 
|  | 2064 | BUILD_STAT_NAME(PartiallyDeadBlocks, Function) += NoReturnCalls.size(); | 
|  | 2065 | } | 
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 2066 | }; | 
|  | 2067 |  | 
|  | 2068 | bool AAIsDeadImpl::isAfterNoReturn(const Instruction *I) const { | 
| Johannes Doerfert | 4361da2 | 2019-08-04 18:38:53 +0000 | [diff] [blame] | 2069 | const Instruction *PrevI = I->getPrevNode(); | 
| Stefan Stipanovic | d021617 | 2019-08-02 21:31:22 +0000 | [diff] [blame] | 2070 | while (PrevI) { | 
|  | 2071 | if (NoReturnCalls.count(PrevI)) | 
|  | 2072 | return true; | 
|  | 2073 | PrevI = PrevI->getPrevNode(); | 
|  | 2074 | } | 
|  | 2075 | return false; | 
|  | 2076 | } | 
|  | 2077 |  | 
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 2078 | const Instruction *AAIsDeadImpl::findNextNoReturn(Attributor &A, | 
|  | 2079 | const Instruction *I) { | 
| Johannes Doerfert | 4361da2 | 2019-08-04 18:38:53 +0000 | [diff] [blame] | 2080 | const BasicBlock *BB = I->getParent(); | 
| Johannes Doerfert | 924d213 | 2019-08-05 21:34:45 +0000 | [diff] [blame] | 2081 | const Function &F = *BB->getParent(); | 
|  | 2082 |  | 
|  | 2083 | // Flag to determine if we can change an invoke to a call assuming the callee | 
|  | 2084 | // is nounwind. This is not possible if the personality of the function allows | 
|  | 2085 | // to catch asynchronous exceptions. | 
|  | 2086 | bool Invoke2CallAllowed = !mayCatchAsynchronousExceptions(F); | 
| Johannes Doerfert | 4361da2 | 2019-08-04 18:38:53 +0000 | [diff] [blame] | 2087 |  | 
|  | 2088 | // TODO: We should have a function that determines if an "edge" is dead. | 
|  | 2089 | //       Edges could be from an instruction to the next or from a terminator | 
|  | 2090 | //       to the successor. For now, we need to special case the unwind block | 
|  | 2091 | //       of InvokeInst below. | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 2092 |  | 
|  | 2093 | while (I) { | 
|  | 2094 | ImmutableCallSite ICS(I); | 
|  | 2095 |  | 
|  | 2096 | if (ICS) { | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 2097 | const IRPosition &IPos = IRPosition::callsite_function(ICS); | 
| Johannes Doerfert | 4361da2 | 2019-08-04 18:38:53 +0000 | [diff] [blame] | 2098 | // Regarless of the no-return property of an invoke instruction we only | 
|  | 2099 | // learn that the regular successor is not reachable through this | 
|  | 2100 | // instruction but the unwind block might still be. | 
|  | 2101 | if (auto *Invoke = dyn_cast<InvokeInst>(I)) { | 
|  | 2102 | // Use nounwind to justify the unwind block is dead as well. | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 2103 | const auto &AANoUnw = A.getAAFor<AANoUnwind>(*this, IPos); | 
|  | 2104 | if (!Invoke2CallAllowed || !AANoUnw.isAssumedNoUnwind()) { | 
| Johannes Doerfert | 2f62206 | 2019-09-04 16:35:20 +0000 | [diff] [blame] | 2105 | assumeLive(A, *Invoke->getUnwindDest()); | 
| Johannes Doerfert | 4361da2 | 2019-08-04 18:38:53 +0000 | [diff] [blame] | 2106 | ToBeExploredPaths.insert(&Invoke->getUnwindDest()->front()); | 
|  | 2107 | } | 
|  | 2108 | } | 
|  | 2109 |  | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 2110 | const auto &NoReturnAA = A.getAAFor<AANoReturn>(*this, IPos); | 
|  | 2111 | if (NoReturnAA.isAssumedNoReturn()) | 
| Johannes Doerfert | 4361da2 | 2019-08-04 18:38:53 +0000 | [diff] [blame] | 2112 | return I; | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 2113 | } | 
|  | 2114 |  | 
|  | 2115 | I = I->getNextNode(); | 
|  | 2116 | } | 
|  | 2117 |  | 
|  | 2118 | // get new paths (reachable blocks). | 
| Johannes Doerfert | 4361da2 | 2019-08-04 18:38:53 +0000 | [diff] [blame] | 2119 | for (const BasicBlock *SuccBB : successors(BB)) { | 
| Johannes Doerfert | 2f62206 | 2019-09-04 16:35:20 +0000 | [diff] [blame] | 2120 | assumeLive(A, *SuccBB); | 
| Johannes Doerfert | 4361da2 | 2019-08-04 18:38:53 +0000 | [diff] [blame] | 2121 | ToBeExploredPaths.insert(&SuccBB->front()); | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 2122 | } | 
|  | 2123 |  | 
| Johannes Doerfert | 4361da2 | 2019-08-04 18:38:53 +0000 | [diff] [blame] | 2124 | // No noreturn instruction found. | 
|  | 2125 | return nullptr; | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 2126 | } | 
|  | 2127 |  | 
| Johannes Doerfert | ece8190 | 2019-08-12 22:05:53 +0000 | [diff] [blame] | 2128 | ChangeStatus AAIsDeadImpl::updateImpl(Attributor &A) { | 
| Stefan Stipanovic | 26121ae | 2019-08-20 23:16:57 +0000 | [diff] [blame] | 2129 | ChangeStatus Status = ChangeStatus::UNCHANGED; | 
|  | 2130 |  | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 2131 | // Temporary collection to iterate over existing noreturn instructions. This | 
|  | 2132 | // will alow easier modification of NoReturnCalls collection | 
| Johannes Doerfert | 4361da2 | 2019-08-04 18:38:53 +0000 | [diff] [blame] | 2133 | SmallVector<const Instruction *, 8> NoReturnChanged; | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 2134 |  | 
| Johannes Doerfert | 4361da2 | 2019-08-04 18:38:53 +0000 | [diff] [blame] | 2135 | for (const Instruction *I : NoReturnCalls) | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 2136 | NoReturnChanged.push_back(I); | 
|  | 2137 |  | 
| Johannes Doerfert | 4361da2 | 2019-08-04 18:38:53 +0000 | [diff] [blame] | 2138 | for (const Instruction *I : NoReturnChanged) { | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 2139 | size_t Size = ToBeExploredPaths.size(); | 
|  | 2140 |  | 
| Johannes Doerfert | 4361da2 | 2019-08-04 18:38:53 +0000 | [diff] [blame] | 2141 | const Instruction *NextNoReturnI = findNextNoReturn(A, I); | 
|  | 2142 | if (NextNoReturnI != I) { | 
|  | 2143 | Status = ChangeStatus::CHANGED; | 
|  | 2144 | NoReturnCalls.remove(I); | 
|  | 2145 | if (NextNoReturnI) | 
|  | 2146 | NoReturnCalls.insert(NextNoReturnI); | 
|  | 2147 | } | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 2148 |  | 
| Johannes Doerfert | 4361da2 | 2019-08-04 18:38:53 +0000 | [diff] [blame] | 2149 | // Explore new paths. | 
|  | 2150 | while (Size != ToBeExploredPaths.size()) { | 
|  | 2151 | Status = ChangeStatus::CHANGED; | 
|  | 2152 | if (const Instruction *NextNoReturnI = | 
|  | 2153 | findNextNoReturn(A, ToBeExploredPaths[Size++])) | 
|  | 2154 | NoReturnCalls.insert(NextNoReturnI); | 
|  | 2155 | } | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 2156 | } | 
|  | 2157 |  | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 2158 | LLVM_DEBUG(dbgs() << "[AAIsDead] AssumedLiveBlocks: " | 
|  | 2159 | << AssumedLiveBlocks.size() << " Total number of blocks: " | 
| Johannes Doerfert | 6dedc78 | 2019-08-16 21:31:11 +0000 | [diff] [blame] | 2160 | << getAssociatedFunction()->size() << "\n"); | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 2161 |  | 
| Johannes Doerfert | d620781 | 2019-08-07 22:32:38 +0000 | [diff] [blame] | 2162 | // If we know everything is live there is no need to query for liveness. | 
|  | 2163 | if (NoReturnCalls.empty() && | 
| Johannes Doerfert | 6dedc78 | 2019-08-16 21:31:11 +0000 | [diff] [blame] | 2164 | getAssociatedFunction()->size() == AssumedLiveBlocks.size()) { | 
| Johannes Doerfert | d620781 | 2019-08-07 22:32:38 +0000 | [diff] [blame] | 2165 | // Indicating a pessimistic fixpoint will cause the state to be "invalid" | 
|  | 2166 | // which will cause the Attributor to not return the AAIsDead on request, | 
|  | 2167 | // which will prevent us from querying isAssumedDead(). | 
|  | 2168 | indicatePessimisticFixpoint(); | 
|  | 2169 | assert(!isValidState() && "Expected an invalid state!"); | 
| Johannes Doerfert | 62a9c1d | 2019-08-29 01:26:58 +0000 | [diff] [blame] | 2170 | Status = ChangeStatus::CHANGED; | 
| Johannes Doerfert | d620781 | 2019-08-07 22:32:38 +0000 | [diff] [blame] | 2171 | } | 
|  | 2172 |  | 
| Stefan Stipanovic | 6058b86 | 2019-07-22 23:58:23 +0000 | [diff] [blame] | 2173 | return Status; | 
|  | 2174 | } | 
|  | 2175 |  | 
| Johannes Doerfert | 66cf87e | 2019-08-16 19:49:00 +0000 | [diff] [blame] | 2176 | /// Liveness information for a call sites. | 
| Johannes Doerfert | 07a5c12 | 2019-08-28 14:09:14 +0000 | [diff] [blame] | 2177 | struct AAIsDeadCallSite final : AAIsDeadImpl { | 
|  | 2178 | AAIsDeadCallSite(const IRPosition &IRP) : AAIsDeadImpl(IRP) {} | 
|  | 2179 |  | 
|  | 2180 | /// See AbstractAttribute::initialize(...). | 
|  | 2181 | void initialize(Attributor &A) override { | 
|  | 2182 | // TODO: Once we have call site specific value information we can provide | 
| Johannes Doerfert | 3fac668 | 2019-08-30 15:24:52 +0000 | [diff] [blame] | 2183 | //       call site specific liveness information and then it makes | 
| Johannes Doerfert | 07a5c12 | 2019-08-28 14:09:14 +0000 | [diff] [blame] | 2184 | //       sense to specialize attributes for call sites instead of | 
|  | 2185 | //       redirecting requests to the callee. | 
|  | 2186 | llvm_unreachable("Abstract attributes for liveness are not " | 
|  | 2187 | "supported for call sites yet!"); | 
|  | 2188 | } | 
|  | 2189 |  | 
|  | 2190 | /// See AbstractAttribute::updateImpl(...). | 
|  | 2191 | ChangeStatus updateImpl(Attributor &A) override { | 
|  | 2192 | return indicatePessimisticFixpoint(); | 
|  | 2193 | } | 
|  | 2194 |  | 
|  | 2195 | /// See AbstractAttribute::trackStatistics() | 
|  | 2196 | void trackStatistics() const override {} | 
|  | 2197 | }; | 
| Johannes Doerfert | 66cf87e | 2019-08-16 19:49:00 +0000 | [diff] [blame] | 2198 |  | 
| Hideto Ueno | 19c07af | 2019-07-23 08:16:17 +0000 | [diff] [blame] | 2199 | /// -------------------- Dereferenceable Argument Attribute -------------------- | 
|  | 2200 |  | 
| Johannes Doerfert | cfcca1a | 2019-08-20 06:08:35 +0000 | [diff] [blame] | 2201 | template <> | 
|  | 2202 | ChangeStatus clampStateAndIndicateChange<DerefState>(DerefState &S, | 
|  | 2203 | const DerefState &R) { | 
|  | 2204 | ChangeStatus CS0 = clampStateAndIndicateChange<IntegerState>( | 
|  | 2205 | S.DerefBytesState, R.DerefBytesState); | 
|  | 2206 | ChangeStatus CS1 = | 
|  | 2207 | clampStateAndIndicateChange<IntegerState>(S.GlobalState, R.GlobalState); | 
|  | 2208 | return CS0 | CS1; | 
|  | 2209 | } | 
|  | 2210 |  | 
| Hideto Ueno | 70576ca | 2019-08-22 14:18:29 +0000 | [diff] [blame] | 2211 | struct AADereferenceableImpl : AADereferenceable { | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 2212 | AADereferenceableImpl(const IRPosition &IRP) : AADereferenceable(IRP) {} | 
| Johannes Doerfert | 344d038 | 2019-08-07 22:34:26 +0000 | [diff] [blame] | 2213 | using StateType = DerefState; | 
| Hideto Ueno | 19c07af | 2019-07-23 08:16:17 +0000 | [diff] [blame] | 2214 |  | 
| Johannes Doerfert | 6a1274a | 2019-08-14 21:31:32 +0000 | [diff] [blame] | 2215 | void initialize(Attributor &A) override { | 
|  | 2216 | SmallVector<Attribute, 4> Attrs; | 
|  | 2217 | getAttrs({Attribute::Dereferenceable, Attribute::DereferenceableOrNull}, | 
|  | 2218 | Attrs); | 
|  | 2219 | for (const Attribute &Attr : Attrs) | 
|  | 2220 | takeKnownDerefBytesMaximum(Attr.getValueAsInt()); | 
|  | 2221 |  | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 2222 | NonNullAA = &A.getAAFor<AANonNull>(*this, getIRPosition()); | 
| Johannes Doerfert | b0412e4 | 2019-09-04 16:16:13 +0000 | [diff] [blame] | 2223 |  | 
|  | 2224 | const IRPosition &IRP = this->getIRPosition(); | 
|  | 2225 | bool IsFnInterface = IRP.isFnInterfaceKind(); | 
|  | 2226 | const Function *FnScope = IRP.getAnchorScope(); | 
|  | 2227 | if (IsFnInterface && (!FnScope || !FnScope->hasExactDefinition())) | 
|  | 2228 | indicatePessimisticFixpoint(); | 
| Johannes Doerfert | 6a1274a | 2019-08-14 21:31:32 +0000 | [diff] [blame] | 2229 | } | 
|  | 2230 |  | 
| Hideto Ueno | 19c07af | 2019-07-23 08:16:17 +0000 | [diff] [blame] | 2231 | /// See AbstractAttribute::getState() | 
|  | 2232 | /// { | 
| Johannes Doerfert | 344d038 | 2019-08-07 22:34:26 +0000 | [diff] [blame] | 2233 | StateType &getState() override { return *this; } | 
|  | 2234 | const StateType &getState() const override { return *this; } | 
| Hideto Ueno | 19c07af | 2019-07-23 08:16:17 +0000 | [diff] [blame] | 2235 | /// } | 
|  | 2236 |  | 
| Johannes Doerfert | eccdf08 | 2019-08-05 23:35:12 +0000 | [diff] [blame] | 2237 | void getDeducedAttributes(LLVMContext &Ctx, | 
|  | 2238 | SmallVectorImpl<Attribute> &Attrs) const override { | 
| Hideto Ueno | 19c07af | 2019-07-23 08:16:17 +0000 | [diff] [blame] | 2239 | // TODO: Add *_globally support | 
|  | 2240 | if (isAssumedNonNull()) | 
|  | 2241 | Attrs.emplace_back(Attribute::getWithDereferenceableBytes( | 
|  | 2242 | Ctx, getAssumedDereferenceableBytes())); | 
|  | 2243 | else | 
|  | 2244 | Attrs.emplace_back(Attribute::getWithDereferenceableOrNullBytes( | 
|  | 2245 | Ctx, getAssumedDereferenceableBytes())); | 
|  | 2246 | } | 
| Hideto Ueno | 19c07af | 2019-07-23 08:16:17 +0000 | [diff] [blame] | 2247 |  | 
|  | 2248 | /// See AbstractAttribute::getAsStr(). | 
|  | 2249 | const std::string getAsStr() const override { | 
|  | 2250 | if (!getAssumedDereferenceableBytes()) | 
|  | 2251 | return "unknown-dereferenceable"; | 
|  | 2252 | return std::string("dereferenceable") + | 
|  | 2253 | (isAssumedNonNull() ? "" : "_or_null") + | 
|  | 2254 | (isAssumedGlobal() ? "_globally" : "") + "<" + | 
|  | 2255 | std::to_string(getKnownDereferenceableBytes()) + "-" + | 
|  | 2256 | std::to_string(getAssumedDereferenceableBytes()) + ">"; | 
|  | 2257 | } | 
|  | 2258 | }; | 
|  | 2259 |  | 
| Johannes Doerfert | cfcca1a | 2019-08-20 06:08:35 +0000 | [diff] [blame] | 2260 | /// Dereferenceable attribute for a floating value. | 
|  | 2261 | struct AADereferenceableFloating : AADereferenceableImpl { | 
|  | 2262 | AADereferenceableFloating(const IRPosition &IRP) | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 2263 | : AADereferenceableImpl(IRP) {} | 
| Hideto Ueno | 19c07af | 2019-07-23 08:16:17 +0000 | [diff] [blame] | 2264 |  | 
|  | 2265 | /// See AbstractAttribute::updateImpl(...). | 
| Johannes Doerfert | cfcca1a | 2019-08-20 06:08:35 +0000 | [diff] [blame] | 2266 | ChangeStatus updateImpl(Attributor &A) override { | 
|  | 2267 | const DataLayout &DL = A.getDataLayout(); | 
|  | 2268 |  | 
|  | 2269 | auto VisitValueCB = [&](Value &V, DerefState &T, bool Stripped) -> bool { | 
|  | 2270 | unsigned IdxWidth = | 
|  | 2271 | DL.getIndexSizeInBits(V.getType()->getPointerAddressSpace()); | 
|  | 2272 | APInt Offset(IdxWidth, 0); | 
|  | 2273 | const Value *Base = | 
|  | 2274 | V.stripAndAccumulateInBoundsConstantOffsets(DL, Offset); | 
|  | 2275 |  | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 2276 | const auto &AA = | 
|  | 2277 | A.getAAFor<AADereferenceable>(*this, IRPosition::value(*Base)); | 
| Johannes Doerfert | cfcca1a | 2019-08-20 06:08:35 +0000 | [diff] [blame] | 2278 | int64_t DerefBytes = 0; | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 2279 | if (!Stripped && this == &AA) { | 
| Johannes Doerfert | cfcca1a | 2019-08-20 06:08:35 +0000 | [diff] [blame] | 2280 | // Use IR information if we did not strip anything. | 
|  | 2281 | // TODO: track globally. | 
|  | 2282 | bool CanBeNull; | 
|  | 2283 | DerefBytes = Base->getPointerDereferenceableBytes(DL, CanBeNull); | 
|  | 2284 | T.GlobalState.indicatePessimisticFixpoint(); | 
|  | 2285 | } else { | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 2286 | const DerefState &DS = static_cast<const DerefState &>(AA.getState()); | 
| Johannes Doerfert | cfcca1a | 2019-08-20 06:08:35 +0000 | [diff] [blame] | 2287 | DerefBytes = DS.DerefBytesState.getAssumed(); | 
|  | 2288 | T.GlobalState &= DS.GlobalState; | 
|  | 2289 | } | 
|  | 2290 |  | 
| Johannes Doerfert | 2f2d7c3 | 2019-08-23 15:45:46 +0000 | [diff] [blame] | 2291 | // For now we do not try to "increase" dereferenceability due to negative | 
|  | 2292 | // indices as we first have to come up with code to deal with loops and | 
|  | 2293 | // for overflows of the dereferenceable bytes. | 
| Johannes Doerfert | 785fad3 | 2019-08-23 17:29:23 +0000 | [diff] [blame] | 2294 | int64_t OffsetSExt = Offset.getSExtValue(); | 
|  | 2295 | if (OffsetSExt < 0) | 
| Johannes Doerfert | 2f2d7c3 | 2019-08-23 15:45:46 +0000 | [diff] [blame] | 2296 | Offset = 0; | 
|  | 2297 |  | 
| Johannes Doerfert | cfcca1a | 2019-08-20 06:08:35 +0000 | [diff] [blame] | 2298 | T.takeAssumedDerefBytesMinimum( | 
| Johannes Doerfert | 785fad3 | 2019-08-23 17:29:23 +0000 | [diff] [blame] | 2299 | std::max(int64_t(0), DerefBytes - OffsetSExt)); | 
| Johannes Doerfert | cfcca1a | 2019-08-20 06:08:35 +0000 | [diff] [blame] | 2300 |  | 
| Johannes Doerfert | 785fad3 | 2019-08-23 17:29:23 +0000 | [diff] [blame] | 2301 | if (this == &AA) { | 
|  | 2302 | if (!Stripped) { | 
|  | 2303 | // If nothing was stripped IR information is all we got. | 
|  | 2304 | T.takeKnownDerefBytesMaximum( | 
|  | 2305 | std::max(int64_t(0), DerefBytes - OffsetSExt)); | 
|  | 2306 | T.indicatePessimisticFixpoint(); | 
|  | 2307 | } else if (OffsetSExt > 0) { | 
|  | 2308 | // If something was stripped but there is circular reasoning we look | 
|  | 2309 | // for the offset. If it is positive we basically decrease the | 
|  | 2310 | // dereferenceable bytes in a circluar loop now, which will simply | 
|  | 2311 | // drive them down to the known value in a very slow way which we | 
|  | 2312 | // can accelerate. | 
|  | 2313 | T.indicatePessimisticFixpoint(); | 
|  | 2314 | } | 
| Johannes Doerfert | cfcca1a | 2019-08-20 06:08:35 +0000 | [diff] [blame] | 2315 | } | 
|  | 2316 |  | 
|  | 2317 | return T.isValidState(); | 
|  | 2318 | }; | 
|  | 2319 |  | 
|  | 2320 | DerefState T; | 
|  | 2321 | if (!genericValueTraversal<AADereferenceable, DerefState>( | 
|  | 2322 | A, getIRPosition(), *this, T, VisitValueCB)) | 
|  | 2323 | return indicatePessimisticFixpoint(); | 
|  | 2324 |  | 
|  | 2325 | return clampStateAndIndicateChange(getState(), T); | 
|  | 2326 | } | 
|  | 2327 |  | 
|  | 2328 | /// See AbstractAttribute::trackStatistics() | 
|  | 2329 | void trackStatistics() const override { | 
|  | 2330 | STATS_DECLTRACK_FLOATING_ATTR(dereferenceable) | 
|  | 2331 | } | 
|  | 2332 | }; | 
|  | 2333 |  | 
|  | 2334 | /// Dereferenceable attribute for a return value. | 
|  | 2335 | struct AADereferenceableReturned final | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 2336 | : AAReturnedFromReturnedValues<AADereferenceable, AADereferenceableImpl, | 
|  | 2337 | DerefState> { | 
| Johannes Doerfert | cfcca1a | 2019-08-20 06:08:35 +0000 | [diff] [blame] | 2338 | AADereferenceableReturned(const IRPosition &IRP) | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 2339 | : AAReturnedFromReturnedValues<AADereferenceable, AADereferenceableImpl, | 
|  | 2340 | DerefState>(IRP) {} | 
| Johannes Doerfert | d1b79e0 | 2019-08-07 22:46:11 +0000 | [diff] [blame] | 2341 |  | 
|  | 2342 | /// See AbstractAttribute::trackStatistics() | 
|  | 2343 | void trackStatistics() const override { | 
| Johannes Doerfert | 17b578b | 2019-08-14 21:46:25 +0000 | [diff] [blame] | 2344 | STATS_DECLTRACK_FNRET_ATTR(dereferenceable) | 
| Johannes Doerfert | d1b79e0 | 2019-08-07 22:46:11 +0000 | [diff] [blame] | 2345 | } | 
| Hideto Ueno | 19c07af | 2019-07-23 08:16:17 +0000 | [diff] [blame] | 2346 | }; | 
|  | 2347 |  | 
| Johannes Doerfert | cfcca1a | 2019-08-20 06:08:35 +0000 | [diff] [blame] | 2348 | /// Dereferenceable attribute for an argument | 
|  | 2349 | struct AADereferenceableArgument final | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 2350 | : AAArgumentFromCallSiteArguments<AADereferenceable, AADereferenceableImpl, | 
|  | 2351 | DerefState> { | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 2352 | AADereferenceableArgument(const IRPosition &IRP) | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 2353 | : AAArgumentFromCallSiteArguments<AADereferenceable, | 
|  | 2354 | AADereferenceableImpl, DerefState>( | 
|  | 2355 | IRP) {} | 
| Johannes Doerfert | d1b79e0 | 2019-08-07 22:46:11 +0000 | [diff] [blame] | 2356 |  | 
|  | 2357 | /// See AbstractAttribute::trackStatistics() | 
| Johannes Doerfert | 3fac668 | 2019-08-30 15:24:52 +0000 | [diff] [blame] | 2358 | void trackStatistics() const override { | 
| Johannes Doerfert | 169af99 | 2019-08-20 06:09:56 +0000 | [diff] [blame] | 2359 | STATS_DECLTRACK_ARG_ATTR(dereferenceable) | 
|  | 2360 | } | 
| Hideto Ueno | 19c07af | 2019-07-23 08:16:17 +0000 | [diff] [blame] | 2361 | }; | 
|  | 2362 |  | 
| Hideto Ueno | 19c07af | 2019-07-23 08:16:17 +0000 | [diff] [blame] | 2363 | /// Dereferenceable attribute for a call site argument. | 
| Johannes Doerfert | cfcca1a | 2019-08-20 06:08:35 +0000 | [diff] [blame] | 2364 | struct AADereferenceableCallSiteArgument final : AADereferenceableFloating { | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 2365 | AADereferenceableCallSiteArgument(const IRPosition &IRP) | 
| Johannes Doerfert | cfcca1a | 2019-08-20 06:08:35 +0000 | [diff] [blame] | 2366 | : AADereferenceableFloating(IRP) {} | 
| Johannes Doerfert | d1b79e0 | 2019-08-07 22:46:11 +0000 | [diff] [blame] | 2367 |  | 
|  | 2368 | /// See AbstractAttribute::trackStatistics() | 
|  | 2369 | void trackStatistics() const override { | 
| Johannes Doerfert | 17b578b | 2019-08-14 21:46:25 +0000 | [diff] [blame] | 2370 | STATS_DECLTRACK_CSARG_ATTR(dereferenceable) | 
| Johannes Doerfert | d1b79e0 | 2019-08-07 22:46:11 +0000 | [diff] [blame] | 2371 | } | 
| Hideto Ueno | 19c07af | 2019-07-23 08:16:17 +0000 | [diff] [blame] | 2372 | }; | 
|  | 2373 |  | 
| Johannes Doerfert | 66cf87e | 2019-08-16 19:49:00 +0000 | [diff] [blame] | 2374 | /// Dereferenceable attribute deduction for a call site return value. | 
| Johannes Doerfert | 3fac668 | 2019-08-30 15:24:52 +0000 | [diff] [blame] | 2375 | struct AADereferenceableCallSiteReturned final : AADereferenceableImpl { | 
|  | 2376 | AADereferenceableCallSiteReturned(const IRPosition &IRP) | 
|  | 2377 | : AADereferenceableImpl(IRP) {} | 
|  | 2378 |  | 
|  | 2379 | /// See AbstractAttribute::initialize(...). | 
|  | 2380 | void initialize(Attributor &A) override { | 
|  | 2381 | AADereferenceableImpl::initialize(A); | 
|  | 2382 | Function *F = getAssociatedFunction(); | 
| Johannes Doerfert | b0412e4 | 2019-09-04 16:16:13 +0000 | [diff] [blame] | 2383 | if (!F) | 
| Johannes Doerfert | 3fac668 | 2019-08-30 15:24:52 +0000 | [diff] [blame] | 2384 | indicatePessimisticFixpoint(); | 
|  | 2385 | } | 
|  | 2386 |  | 
|  | 2387 | /// See AbstractAttribute::updateImpl(...). | 
|  | 2388 | ChangeStatus updateImpl(Attributor &A) override { | 
|  | 2389 | // TODO: Once we have call site specific value information we can provide | 
|  | 2390 | //       call site specific liveness information and then it makes | 
|  | 2391 | //       sense to specialize attributes for call sites arguments instead of | 
|  | 2392 | //       redirecting requests to the callee argument. | 
|  | 2393 | Function *F = getAssociatedFunction(); | 
|  | 2394 | const IRPosition &FnPos = IRPosition::returned(*F); | 
|  | 2395 | auto &FnAA = A.getAAFor<AADereferenceable>(*this, FnPos); | 
|  | 2396 | return clampStateAndIndicateChange( | 
|  | 2397 | getState(), static_cast<const DerefState &>(FnAA.getState())); | 
|  | 2398 | } | 
|  | 2399 |  | 
|  | 2400 | /// See AbstractAttribute::trackStatistics() | 
|  | 2401 | void trackStatistics() const override { | 
|  | 2402 | STATS_DECLTRACK_CS_ATTR(dereferenceable); | 
|  | 2403 | } | 
|  | 2404 | }; | 
| Johannes Doerfert | 66cf87e | 2019-08-16 19:49:00 +0000 | [diff] [blame] | 2405 |  | 
| Hideto Ueno | e7bea9b | 2019-07-28 07:04:01 +0000 | [diff] [blame] | 2406 | // ------------------------ Align Argument Attribute ------------------------ | 
|  | 2407 |  | 
| Johannes Doerfert | 344d038 | 2019-08-07 22:34:26 +0000 | [diff] [blame] | 2408 | struct AAAlignImpl : AAAlign { | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 2409 | AAAlignImpl(const IRPosition &IRP) : AAAlign(IRP) {} | 
| Hideto Ueno | e7bea9b | 2019-07-28 07:04:01 +0000 | [diff] [blame] | 2410 |  | 
|  | 2411 | // Max alignemnt value allowed in IR | 
|  | 2412 | static const unsigned MAX_ALIGN = 1U << 29; | 
|  | 2413 |  | 
| Johannes Doerfert | 234eda5 | 2019-08-16 19:51:23 +0000 | [diff] [blame] | 2414 | /// See AbstractAttribute::initialize(...). | 
| Johannes Doerfert | ece8190 | 2019-08-12 22:05:53 +0000 | [diff] [blame] | 2415 | void initialize(Attributor &A) override { | 
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 2416 | takeAssumedMinimum(MAX_ALIGN); | 
|  | 2417 |  | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 2418 | SmallVector<Attribute, 4> Attrs; | 
|  | 2419 | getAttrs({Attribute::Alignment}, Attrs); | 
|  | 2420 | for (const Attribute &Attr : Attrs) | 
|  | 2421 | takeKnownMaximum(Attr.getValueAsInt()); | 
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 2422 |  | 
|  | 2423 | if (getIRPosition().isFnInterfaceKind() && | 
|  | 2424 | (!getAssociatedFunction() || | 
|  | 2425 | !getAssociatedFunction()->hasExactDefinition())) | 
|  | 2426 | indicatePessimisticFixpoint(); | 
| Hideto Ueno | e7bea9b | 2019-07-28 07:04:01 +0000 | [diff] [blame] | 2427 | } | 
|  | 2428 |  | 
| Johannes Doerfert | 5a5a139 | 2019-08-23 20:20:10 +0000 | [diff] [blame] | 2429 | /// See AbstractAttribute::manifest(...). | 
|  | 2430 | ChangeStatus manifest(Attributor &A) override { | 
|  | 2431 | ChangeStatus Changed = ChangeStatus::UNCHANGED; | 
|  | 2432 |  | 
|  | 2433 | // Check for users that allow alignment annotations. | 
|  | 2434 | Value &AnchorVal = getIRPosition().getAnchorValue(); | 
|  | 2435 | for (const Use &U : AnchorVal.uses()) { | 
|  | 2436 | if (auto *SI = dyn_cast<StoreInst>(U.getUser())) { | 
|  | 2437 | if (SI->getPointerOperand() == &AnchorVal) | 
|  | 2438 | if (SI->getAlignment() < getAssumedAlign()) { | 
|  | 2439 | STATS_DECLTRACK(AAAlign, Store, | 
|  | 2440 | "Number of times alignemnt added to a store"); | 
|  | 2441 | SI->setAlignment(getAssumedAlign()); | 
|  | 2442 | Changed = ChangeStatus::CHANGED; | 
|  | 2443 | } | 
|  | 2444 | } else if (auto *LI = dyn_cast<LoadInst>(U.getUser())) { | 
|  | 2445 | if (LI->getPointerOperand() == &AnchorVal) | 
|  | 2446 | if (LI->getAlignment() < getAssumedAlign()) { | 
|  | 2447 | LI->setAlignment(getAssumedAlign()); | 
|  | 2448 | STATS_DECLTRACK(AAAlign, Load, | 
|  | 2449 | "Number of times alignemnt added to a load"); | 
|  | 2450 | Changed = ChangeStatus::CHANGED; | 
|  | 2451 | } | 
|  | 2452 | } | 
|  | 2453 | } | 
|  | 2454 |  | 
| Johannes Doerfert | 81df452 | 2019-08-30 15:22:28 +0000 | [diff] [blame] | 2455 | return AAAlign::manifest(A) | Changed; | 
| Johannes Doerfert | 5a5a139 | 2019-08-23 20:20:10 +0000 | [diff] [blame] | 2456 | } | 
|  | 2457 |  | 
| Johannes Doerfert | 81df452 | 2019-08-30 15:22:28 +0000 | [diff] [blame] | 2458 | // TODO: Provide a helper to determine the implied ABI alignment and check in | 
|  | 2459 | //       the existing manifest method and a new one for AAAlignImpl that value | 
|  | 2460 | //       to avoid making the alignment explicit if it did not improve. | 
|  | 2461 |  | 
|  | 2462 | /// See AbstractAttribute::getDeducedAttributes | 
|  | 2463 | virtual void | 
|  | 2464 | getDeducedAttributes(LLVMContext &Ctx, | 
|  | 2465 | SmallVectorImpl<Attribute> &Attrs) const override { | 
|  | 2466 | if (getAssumedAlign() > 1) | 
|  | 2467 | Attrs.emplace_back(Attribute::getWithAlignment(Ctx, getAssumedAlign())); | 
|  | 2468 | } | 
|  | 2469 |  | 
|  | 2470 | /// See AbstractAttribute::getAsStr(). | 
|  | 2471 | const std::string getAsStr() const override { | 
|  | 2472 | return getAssumedAlign() ? ("align<" + std::to_string(getKnownAlign()) + | 
|  | 2473 | "-" + std::to_string(getAssumedAlign()) + ">") | 
|  | 2474 | : "unknown-align"; | 
|  | 2475 | } | 
|  | 2476 | }; | 
|  | 2477 |  | 
|  | 2478 | /// Align attribute for a floating value. | 
|  | 2479 | struct AAAlignFloating : AAAlignImpl { | 
|  | 2480 | AAAlignFloating(const IRPosition &IRP) : AAAlignImpl(IRP) {} | 
|  | 2481 |  | 
| Hideto Ueno | e7bea9b | 2019-07-28 07:04:01 +0000 | [diff] [blame] | 2482 | /// See AbstractAttribute::updateImpl(...). | 
| Johannes Doerfert | 234eda5 | 2019-08-16 19:51:23 +0000 | [diff] [blame] | 2483 | ChangeStatus updateImpl(Attributor &A) override { | 
|  | 2484 | const DataLayout &DL = A.getDataLayout(); | 
|  | 2485 |  | 
| Johannes Doerfert | b9b8791 | 2019-08-20 06:02:39 +0000 | [diff] [blame] | 2486 | auto VisitValueCB = [&](Value &V, AAAlign::StateType &T, | 
|  | 2487 | bool Stripped) -> bool { | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 2488 | const auto &AA = A.getAAFor<AAAlign>(*this, IRPosition::value(V)); | 
|  | 2489 | if (!Stripped && this == &AA) { | 
| Johannes Doerfert | 234eda5 | 2019-08-16 19:51:23 +0000 | [diff] [blame] | 2490 | // Use only IR information if we did not strip anything. | 
|  | 2491 | T.takeKnownMaximum(V.getPointerAlignment(DL)); | 
|  | 2492 | T.indicatePessimisticFixpoint(); | 
| Johannes Doerfert | 234eda5 | 2019-08-16 19:51:23 +0000 | [diff] [blame] | 2493 | } else { | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 2494 | // Use abstract attribute information. | 
|  | 2495 | const AAAlign::StateType &DS = | 
|  | 2496 | static_cast<const AAAlign::StateType &>(AA.getState()); | 
|  | 2497 | T ^= DS; | 
| Johannes Doerfert | 234eda5 | 2019-08-16 19:51:23 +0000 | [diff] [blame] | 2498 | } | 
| Johannes Doerfert | b9b8791 | 2019-08-20 06:02:39 +0000 | [diff] [blame] | 2499 | return T.isValidState(); | 
| Johannes Doerfert | 234eda5 | 2019-08-16 19:51:23 +0000 | [diff] [blame] | 2500 | }; | 
|  | 2501 |  | 
|  | 2502 | StateType T; | 
|  | 2503 | if (!genericValueTraversal<AAAlign, StateType>(A, getIRPosition(), *this, T, | 
|  | 2504 | VisitValueCB)) | 
| Johannes Doerfert | cfcca1a | 2019-08-20 06:08:35 +0000 | [diff] [blame] | 2505 | return indicatePessimisticFixpoint(); | 
| Johannes Doerfert | 234eda5 | 2019-08-16 19:51:23 +0000 | [diff] [blame] | 2506 |  | 
| Johannes Doerfert | 028b2aa | 2019-08-20 05:57:01 +0000 | [diff] [blame] | 2507 | // TODO: If we know we visited all incoming values, thus no are assumed | 
|  | 2508 | // dead, we can take the known information from the state T. | 
| Johannes Doerfert | 234eda5 | 2019-08-16 19:51:23 +0000 | [diff] [blame] | 2509 | return clampStateAndIndicateChange(getState(), T); | 
|  | 2510 | } | 
|  | 2511 |  | 
|  | 2512 | /// See AbstractAttribute::trackStatistics() | 
|  | 2513 | void trackStatistics() const override { STATS_DECLTRACK_FLOATING_ATTR(align) } | 
|  | 2514 | }; | 
|  | 2515 |  | 
|  | 2516 | /// Align attribute for function return value. | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 2517 | struct AAAlignReturned final | 
|  | 2518 | : AAReturnedFromReturnedValues<AAAlign, AAAlignImpl> { | 
| Johannes Doerfert | 234eda5 | 2019-08-16 19:51:23 +0000 | [diff] [blame] | 2519 | AAAlignReturned(const IRPosition &IRP) | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 2520 | : AAReturnedFromReturnedValues<AAAlign, AAAlignImpl>(IRP) {} | 
| Johannes Doerfert | d1b79e0 | 2019-08-07 22:46:11 +0000 | [diff] [blame] | 2521 |  | 
|  | 2522 | /// See AbstractAttribute::trackStatistics() | 
| Johannes Doerfert | 17b578b | 2019-08-14 21:46:25 +0000 | [diff] [blame] | 2523 | void trackStatistics() const override { STATS_DECLTRACK_FNRET_ATTR(aligned) } | 
| Hideto Ueno | e7bea9b | 2019-07-28 07:04:01 +0000 | [diff] [blame] | 2524 | }; | 
|  | 2525 |  | 
| Hideto Ueno | e7bea9b | 2019-07-28 07:04:01 +0000 | [diff] [blame] | 2526 | /// Align attribute for function argument. | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 2527 | struct AAAlignArgument final | 
|  | 2528 | : AAArgumentFromCallSiteArguments<AAAlign, AAAlignImpl> { | 
| Johannes Doerfert | 234eda5 | 2019-08-16 19:51:23 +0000 | [diff] [blame] | 2529 | AAAlignArgument(const IRPosition &IRP) | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 2530 | : AAArgumentFromCallSiteArguments<AAAlign, AAAlignImpl>(IRP) {} | 
| Johannes Doerfert | d1b79e0 | 2019-08-07 22:46:11 +0000 | [diff] [blame] | 2531 |  | 
|  | 2532 | /// See AbstractAttribute::trackStatistics() | 
| Johannes Doerfert | 169af99 | 2019-08-20 06:09:56 +0000 | [diff] [blame] | 2533 | void trackStatistics() const override { STATS_DECLTRACK_ARG_ATTR(aligned) } | 
| Hideto Ueno | e7bea9b | 2019-07-28 07:04:01 +0000 | [diff] [blame] | 2534 | }; | 
|  | 2535 |  | 
| Johannes Doerfert | 234eda5 | 2019-08-16 19:51:23 +0000 | [diff] [blame] | 2536 | struct AAAlignCallSiteArgument final : AAAlignFloating { | 
|  | 2537 | AAAlignCallSiteArgument(const IRPosition &IRP) : AAAlignFloating(IRP) {} | 
| Johannes Doerfert | d1b79e0 | 2019-08-07 22:46:11 +0000 | [diff] [blame] | 2538 |  | 
| Johannes Doerfert | 5a5a139 | 2019-08-23 20:20:10 +0000 | [diff] [blame] | 2539 | /// See AbstractAttribute::manifest(...). | 
|  | 2540 | ChangeStatus manifest(Attributor &A) override { | 
|  | 2541 | return AAAlignImpl::manifest(A); | 
|  | 2542 | } | 
|  | 2543 |  | 
| Johannes Doerfert | d1b79e0 | 2019-08-07 22:46:11 +0000 | [diff] [blame] | 2544 | /// See AbstractAttribute::trackStatistics() | 
| Johannes Doerfert | 17b578b | 2019-08-14 21:46:25 +0000 | [diff] [blame] | 2545 | void trackStatistics() const override { STATS_DECLTRACK_CSARG_ATTR(aligned) } | 
| Hideto Ueno | e7bea9b | 2019-07-28 07:04:01 +0000 | [diff] [blame] | 2546 | }; | 
|  | 2547 |  | 
| Johannes Doerfert | 66cf87e | 2019-08-16 19:49:00 +0000 | [diff] [blame] | 2548 | /// Align attribute deduction for a call site return value. | 
| Johannes Doerfert | 3fac668 | 2019-08-30 15:24:52 +0000 | [diff] [blame] | 2549 | struct AAAlignCallSiteReturned final : AAAlignImpl { | 
|  | 2550 | AAAlignCallSiteReturned(const IRPosition &IRP) : AAAlignImpl(IRP) {} | 
|  | 2551 |  | 
|  | 2552 | /// See AbstractAttribute::initialize(...). | 
|  | 2553 | void initialize(Attributor &A) override { | 
|  | 2554 | AAAlignImpl::initialize(A); | 
|  | 2555 | Function *F = getAssociatedFunction(); | 
| Johannes Doerfert | b0412e4 | 2019-09-04 16:16:13 +0000 | [diff] [blame] | 2556 | if (!F) | 
| Johannes Doerfert | 3fac668 | 2019-08-30 15:24:52 +0000 | [diff] [blame] | 2557 | indicatePessimisticFixpoint(); | 
|  | 2558 | } | 
|  | 2559 |  | 
|  | 2560 | /// See AbstractAttribute::updateImpl(...). | 
|  | 2561 | ChangeStatus updateImpl(Attributor &A) override { | 
|  | 2562 | // TODO: Once we have call site specific value information we can provide | 
|  | 2563 | //       call site specific liveness information and then it makes | 
|  | 2564 | //       sense to specialize attributes for call sites arguments instead of | 
|  | 2565 | //       redirecting requests to the callee argument. | 
|  | 2566 | Function *F = getAssociatedFunction(); | 
|  | 2567 | const IRPosition &FnPos = IRPosition::returned(*F); | 
|  | 2568 | auto &FnAA = A.getAAFor<AAAlign>(*this, FnPos); | 
|  | 2569 | return clampStateAndIndicateChange( | 
|  | 2570 | getState(), static_cast<const AAAlign::StateType &>(FnAA.getState())); | 
|  | 2571 | } | 
|  | 2572 |  | 
|  | 2573 | /// See AbstractAttribute::trackStatistics() | 
|  | 2574 | void trackStatistics() const override { STATS_DECLTRACK_CS_ATTR(align); } | 
|  | 2575 | }; | 
| Johannes Doerfert | 66cf87e | 2019-08-16 19:49:00 +0000 | [diff] [blame] | 2576 |  | 
| Johannes Doerfert | e83f303 | 2019-08-05 23:22:05 +0000 | [diff] [blame] | 2577 | /// ------------------ Function No-Return Attribute ---------------------------- | 
| Johannes Doerfert | 344d038 | 2019-08-07 22:34:26 +0000 | [diff] [blame] | 2578 | struct AANoReturnImpl : public AANoReturn { | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 2579 | AANoReturnImpl(const IRPosition &IRP) : AANoReturn(IRP) {} | 
| Johannes Doerfert | e83f303 | 2019-08-05 23:22:05 +0000 | [diff] [blame] | 2580 |  | 
| Johannes Doerfert | e83f303 | 2019-08-05 23:22:05 +0000 | [diff] [blame] | 2581 | /// See AbstractAttribute::getAsStr(). | 
|  | 2582 | const std::string getAsStr() const override { | 
|  | 2583 | return getAssumed() ? "noreturn" : "may-return"; | 
|  | 2584 | } | 
|  | 2585 |  | 
| Johannes Doerfert | e83f303 | 2019-08-05 23:22:05 +0000 | [diff] [blame] | 2586 | /// See AbstractAttribute::updateImpl(Attributor &A). | 
| Johannes Doerfert | ece8190 | 2019-08-12 22:05:53 +0000 | [diff] [blame] | 2587 | virtual ChangeStatus updateImpl(Attributor &A) override { | 
| Johannes Doerfert | d0f6400 | 2019-08-06 00:32:43 +0000 | [diff] [blame] | 2588 | auto CheckForNoReturn = [](Instruction &) { return false; }; | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 2589 | if (!A.checkForAllInstructions(CheckForNoReturn, *this, | 
| Johannes Doerfert | d0f6400 | 2019-08-06 00:32:43 +0000 | [diff] [blame] | 2590 | {(unsigned)Instruction::Ret})) | 
| Johannes Doerfert | e83f303 | 2019-08-05 23:22:05 +0000 | [diff] [blame] | 2591 | return indicatePessimisticFixpoint(); | 
| Johannes Doerfert | e83f303 | 2019-08-05 23:22:05 +0000 | [diff] [blame] | 2592 | return ChangeStatus::UNCHANGED; | 
|  | 2593 | } | 
|  | 2594 | }; | 
|  | 2595 |  | 
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 2596 | struct AANoReturnFunction final : AANoReturnImpl { | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 2597 | AANoReturnFunction(const IRPosition &IRP) : AANoReturnImpl(IRP) {} | 
| Johannes Doerfert | d1b79e0 | 2019-08-07 22:46:11 +0000 | [diff] [blame] | 2598 |  | 
|  | 2599 | /// See AbstractAttribute::trackStatistics() | 
| Johannes Doerfert | 17b578b | 2019-08-14 21:46:25 +0000 | [diff] [blame] | 2600 | void trackStatistics() const override { STATS_DECLTRACK_FN_ATTR(noreturn) } | 
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 2601 | }; | 
|  | 2602 |  | 
| Johannes Doerfert | 66cf87e | 2019-08-16 19:49:00 +0000 | [diff] [blame] | 2603 | /// NoReturn attribute deduction for a call sites. | 
| Johannes Doerfert | 3fac668 | 2019-08-30 15:24:52 +0000 | [diff] [blame] | 2604 | struct AANoReturnCallSite final : AANoReturnImpl { | 
|  | 2605 | AANoReturnCallSite(const IRPosition &IRP) : AANoReturnImpl(IRP) {} | 
|  | 2606 |  | 
|  | 2607 | /// See AbstractAttribute::initialize(...). | 
|  | 2608 | void initialize(Attributor &A) override { | 
|  | 2609 | AANoReturnImpl::initialize(A); | 
|  | 2610 | Function *F = getAssociatedFunction(); | 
| Johannes Doerfert | b0412e4 | 2019-09-04 16:16:13 +0000 | [diff] [blame] | 2611 | if (!F) | 
| Johannes Doerfert | 3fac668 | 2019-08-30 15:24:52 +0000 | [diff] [blame] | 2612 | indicatePessimisticFixpoint(); | 
|  | 2613 | } | 
|  | 2614 |  | 
|  | 2615 | /// See AbstractAttribute::updateImpl(...). | 
|  | 2616 | ChangeStatus updateImpl(Attributor &A) override { | 
|  | 2617 | // TODO: Once we have call site specific value information we can provide | 
|  | 2618 | //       call site specific liveness information and then it makes | 
|  | 2619 | //       sense to specialize attributes for call sites arguments instead of | 
|  | 2620 | //       redirecting requests to the callee argument. | 
|  | 2621 | Function *F = getAssociatedFunction(); | 
|  | 2622 | const IRPosition &FnPos = IRPosition::function(*F); | 
|  | 2623 | auto &FnAA = A.getAAFor<AANoReturn>(*this, FnPos); | 
|  | 2624 | return clampStateAndIndicateChange( | 
|  | 2625 | getState(), | 
|  | 2626 | static_cast<const AANoReturn::StateType &>(FnAA.getState())); | 
|  | 2627 | } | 
|  | 2628 |  | 
|  | 2629 | /// See AbstractAttribute::trackStatistics() | 
|  | 2630 | void trackStatistics() const override { STATS_DECLTRACK_CS_ATTR(noreturn); } | 
|  | 2631 | }; | 
| Johannes Doerfert | 66cf87e | 2019-08-16 19:49:00 +0000 | [diff] [blame] | 2632 |  | 
| Johannes Doerfert | 7516a5e | 2019-09-03 20:37:24 +0000 | [diff] [blame] | 2633 | /// ----------------------- Variable Capturing --------------------------------- | 
|  | 2634 |  | 
|  | 2635 | /// A class to hold the state of for no-capture attributes. | 
|  | 2636 | struct AANoCaptureImpl : public AANoCapture { | 
|  | 2637 | AANoCaptureImpl(const IRPosition &IRP) : AANoCapture(IRP) {} | 
|  | 2638 |  | 
|  | 2639 | /// See AbstractAttribute::initialize(...). | 
|  | 2640 | void initialize(Attributor &A) override { | 
| Johannes Doerfert | b0412e4 | 2019-09-04 16:16:13 +0000 | [diff] [blame] | 2641 | AANoCapture::initialize(A); | 
| Johannes Doerfert | 7516a5e | 2019-09-03 20:37:24 +0000 | [diff] [blame] | 2642 |  | 
|  | 2643 | const IRPosition &IRP = getIRPosition(); | 
|  | 2644 | const Function *F = | 
|  | 2645 | getArgNo() >= 0 ? IRP.getAssociatedFunction() : IRP.getAnchorScope(); | 
|  | 2646 |  | 
|  | 2647 | // Check what state the associated function can actually capture. | 
|  | 2648 | if (F) | 
|  | 2649 | determineFunctionCaptureCapabilities(*F, *this); | 
| Johannes Doerfert | b0412e4 | 2019-09-04 16:16:13 +0000 | [diff] [blame] | 2650 | else | 
| Johannes Doerfert | 7516a5e | 2019-09-03 20:37:24 +0000 | [diff] [blame] | 2651 | indicatePessimisticFixpoint(); | 
|  | 2652 | } | 
|  | 2653 |  | 
|  | 2654 | /// See AbstractAttribute::updateImpl(...). | 
|  | 2655 | ChangeStatus updateImpl(Attributor &A) override; | 
|  | 2656 |  | 
|  | 2657 | /// see AbstractAttribute::isAssumedNoCaptureMaybeReturned(...). | 
|  | 2658 | virtual void | 
|  | 2659 | getDeducedAttributes(LLVMContext &Ctx, | 
|  | 2660 | SmallVectorImpl<Attribute> &Attrs) const override { | 
|  | 2661 | if (!isAssumedNoCaptureMaybeReturned()) | 
|  | 2662 | return; | 
|  | 2663 |  | 
| Hideto Ueno | 3736764 | 2019-09-11 06:52:11 +0000 | [diff] [blame] | 2664 | if (getArgNo() >= 0) { | 
|  | 2665 | if (isAssumedNoCapture()) | 
|  | 2666 | Attrs.emplace_back(Attribute::get(Ctx, Attribute::NoCapture)); | 
|  | 2667 | else if (ManifestInternal) | 
|  | 2668 | Attrs.emplace_back(Attribute::get(Ctx, "no-capture-maybe-returned")); | 
|  | 2669 | } | 
| Johannes Doerfert | 7516a5e | 2019-09-03 20:37:24 +0000 | [diff] [blame] | 2670 | } | 
|  | 2671 |  | 
|  | 2672 | /// Set the NOT_CAPTURED_IN_MEM and NOT_CAPTURED_IN_RET bits in \p Known | 
|  | 2673 | /// depending on the ability of the function associated with \p IRP to capture | 
|  | 2674 | /// state in memory and through "returning/throwing", respectively. | 
|  | 2675 | static void determineFunctionCaptureCapabilities(const Function &F, | 
|  | 2676 | IntegerState &State) { | 
|  | 2677 | // TODO: Once we have memory behavior attributes we should use them here. | 
|  | 2678 |  | 
|  | 2679 | // If we know we cannot communicate or write to memory, we do not care about | 
|  | 2680 | // ptr2int anymore. | 
|  | 2681 | if (F.onlyReadsMemory() && F.doesNotThrow() && | 
|  | 2682 | F.getReturnType()->isVoidTy()) { | 
|  | 2683 | State.addKnownBits(NO_CAPTURE); | 
|  | 2684 | return; | 
|  | 2685 | } | 
|  | 2686 |  | 
|  | 2687 | // A function cannot capture state in memory if it only reads memory, it can | 
|  | 2688 | // however return/throw state and the state might be influenced by the | 
|  | 2689 | // pointer value, e.g., loading from a returned pointer might reveal a bit. | 
|  | 2690 | if (F.onlyReadsMemory()) | 
|  | 2691 | State.addKnownBits(NOT_CAPTURED_IN_MEM); | 
|  | 2692 |  | 
|  | 2693 | // A function cannot communicate state back if it does not through | 
|  | 2694 | // exceptions and doesn not return values. | 
|  | 2695 | if (F.doesNotThrow() && F.getReturnType()->isVoidTy()) | 
|  | 2696 | State.addKnownBits(NOT_CAPTURED_IN_RET); | 
|  | 2697 | } | 
|  | 2698 |  | 
|  | 2699 | /// See AbstractState::getAsStr(). | 
|  | 2700 | const std::string getAsStr() const override { | 
|  | 2701 | if (isKnownNoCapture()) | 
|  | 2702 | return "known not-captured"; | 
|  | 2703 | if (isAssumedNoCapture()) | 
|  | 2704 | return "assumed not-captured"; | 
|  | 2705 | if (isKnownNoCaptureMaybeReturned()) | 
|  | 2706 | return "known not-captured-maybe-returned"; | 
|  | 2707 | if (isAssumedNoCaptureMaybeReturned()) | 
|  | 2708 | return "assumed not-captured-maybe-returned"; | 
|  | 2709 | return "assumed-captured"; | 
|  | 2710 | } | 
|  | 2711 | }; | 
|  | 2712 |  | 
|  | 2713 | /// Attributor-aware capture tracker. | 
|  | 2714 | struct AACaptureUseTracker final : public CaptureTracker { | 
|  | 2715 |  | 
|  | 2716 | /// Create a capture tracker that can lookup in-flight abstract attributes | 
|  | 2717 | /// through the Attributor \p A. | 
|  | 2718 | /// | 
|  | 2719 | /// If a use leads to a potential capture, \p CapturedInMemory is set and the | 
|  | 2720 | /// search is stopped. If a use leads to a return instruction, | 
|  | 2721 | /// \p CommunicatedBack is set to true and \p CapturedInMemory is not changed. | 
|  | 2722 | /// If a use leads to a ptr2int which may capture the value, | 
|  | 2723 | /// \p CapturedInInteger is set. If a use is found that is currently assumed | 
|  | 2724 | /// "no-capture-maybe-returned", the user is added to the \p PotentialCopies | 
|  | 2725 | /// set. All values in \p PotentialCopies are later tracked as well. For every | 
|  | 2726 | /// explored use we decrement \p RemainingUsesToExplore. Once it reaches 0, | 
|  | 2727 | /// the search is stopped with \p CapturedInMemory and \p CapturedInInteger | 
|  | 2728 | /// conservatively set to true. | 
|  | 2729 | AACaptureUseTracker(Attributor &A, AANoCapture &NoCaptureAA, | 
|  | 2730 | const AAIsDead &IsDeadAA, IntegerState &State, | 
|  | 2731 | SmallVectorImpl<const Value *> &PotentialCopies, | 
|  | 2732 | unsigned &RemainingUsesToExplore) | 
|  | 2733 | : A(A), NoCaptureAA(NoCaptureAA), IsDeadAA(IsDeadAA), State(State), | 
|  | 2734 | PotentialCopies(PotentialCopies), | 
|  | 2735 | RemainingUsesToExplore(RemainingUsesToExplore) {} | 
|  | 2736 |  | 
|  | 2737 | /// Determine if \p V maybe captured. *Also updates the state!* | 
|  | 2738 | bool valueMayBeCaptured(const Value *V) { | 
|  | 2739 | if (V->getType()->isPointerTy()) { | 
|  | 2740 | PointerMayBeCaptured(V, this); | 
|  | 2741 | } else { | 
|  | 2742 | State.indicatePessimisticFixpoint(); | 
|  | 2743 | } | 
|  | 2744 | return State.isAssumed(AANoCapture::NO_CAPTURE_MAYBE_RETURNED); | 
|  | 2745 | } | 
|  | 2746 |  | 
|  | 2747 | /// See CaptureTracker::tooManyUses(). | 
|  | 2748 | void tooManyUses() override { | 
|  | 2749 | State.removeAssumedBits(AANoCapture::NO_CAPTURE); | 
|  | 2750 | } | 
|  | 2751 |  | 
|  | 2752 | bool isDereferenceableOrNull(Value *O, const DataLayout &DL) override { | 
|  | 2753 | if (CaptureTracker::isDereferenceableOrNull(O, DL)) | 
|  | 2754 | return true; | 
|  | 2755 | const auto &DerefAA = | 
|  | 2756 | A.getAAFor<AADereferenceable>(NoCaptureAA, IRPosition::value(*O)); | 
|  | 2757 | return DerefAA.getAssumedDereferenceableBytes(); | 
|  | 2758 | } | 
|  | 2759 |  | 
|  | 2760 | /// See CaptureTracker::captured(...). | 
|  | 2761 | bool captured(const Use *U) override { | 
|  | 2762 | Instruction *UInst = cast<Instruction>(U->getUser()); | 
|  | 2763 | LLVM_DEBUG(dbgs() << "Check use: " << *U->get() << " in " << *UInst | 
|  | 2764 | << "\n"); | 
|  | 2765 |  | 
|  | 2766 | // Because we may reuse the tracker multiple times we keep track of the | 
|  | 2767 | // number of explored uses ourselves as well. | 
|  | 2768 | if (RemainingUsesToExplore-- == 0) { | 
|  | 2769 | LLVM_DEBUG(dbgs() << " - too many uses to explore!\n"); | 
|  | 2770 | return isCapturedIn(/* Memory */ true, /* Integer */ true, | 
|  | 2771 | /* Return */ true); | 
|  | 2772 | } | 
|  | 2773 |  | 
|  | 2774 | // Deal with ptr2int by following uses. | 
|  | 2775 | if (isa<PtrToIntInst>(UInst)) { | 
|  | 2776 | LLVM_DEBUG(dbgs() << " - ptr2int assume the worst!\n"); | 
|  | 2777 | return valueMayBeCaptured(UInst); | 
|  | 2778 | } | 
|  | 2779 |  | 
|  | 2780 | // Explicitly catch return instructions. | 
|  | 2781 | if (isa<ReturnInst>(UInst)) | 
|  | 2782 | return isCapturedIn(/* Memory */ false, /* Integer */ false, | 
|  | 2783 | /* Return */ true); | 
|  | 2784 |  | 
|  | 2785 | // For now we only use special logic for call sites. However, the tracker | 
|  | 2786 | // itself knows about a lot of other non-capturing cases already. | 
|  | 2787 | CallSite CS(UInst); | 
|  | 2788 | if (!CS || !CS.isArgOperand(U)) | 
|  | 2789 | return isCapturedIn(/* Memory */ true, /* Integer */ true, | 
|  | 2790 | /* Return */ true); | 
|  | 2791 |  | 
|  | 2792 | unsigned ArgNo = CS.getArgumentNo(U); | 
|  | 2793 | const IRPosition &CSArgPos = IRPosition::callsite_argument(CS, ArgNo); | 
|  | 2794 | // If we have a abstract no-capture attribute for the argument we can use | 
|  | 2795 | // it to justify a non-capture attribute here. This allows recursion! | 
|  | 2796 | auto &ArgNoCaptureAA = A.getAAFor<AANoCapture>(NoCaptureAA, CSArgPos); | 
|  | 2797 | if (ArgNoCaptureAA.isAssumedNoCapture()) | 
|  | 2798 | return isCapturedIn(/* Memory */ false, /* Integer */ false, | 
|  | 2799 | /* Return */ false); | 
|  | 2800 | if (ArgNoCaptureAA.isAssumedNoCaptureMaybeReturned()) { | 
|  | 2801 | addPotentialCopy(CS); | 
|  | 2802 | return isCapturedIn(/* Memory */ false, /* Integer */ false, | 
|  | 2803 | /* Return */ false); | 
|  | 2804 | } | 
|  | 2805 |  | 
|  | 2806 | // Lastly, we could not find a reason no-capture can be assumed so we don't. | 
|  | 2807 | return isCapturedIn(/* Memory */ true, /* Integer */ true, | 
|  | 2808 | /* Return */ true); | 
|  | 2809 | } | 
|  | 2810 |  | 
|  | 2811 | /// Register \p CS as potential copy of the value we are checking. | 
|  | 2812 | void addPotentialCopy(CallSite CS) { | 
|  | 2813 | PotentialCopies.push_back(CS.getInstruction()); | 
|  | 2814 | } | 
|  | 2815 |  | 
|  | 2816 | /// See CaptureTracker::shouldExplore(...). | 
|  | 2817 | bool shouldExplore(const Use *U) override { | 
|  | 2818 | // Check liveness. | 
|  | 2819 | return !IsDeadAA.isAssumedDead(cast<Instruction>(U->getUser())); | 
|  | 2820 | } | 
|  | 2821 |  | 
|  | 2822 | /// Update the state according to \p CapturedInMem, \p CapturedInInt, and | 
|  | 2823 | /// \p CapturedInRet, then return the appropriate value for use in the | 
|  | 2824 | /// CaptureTracker::captured() interface. | 
|  | 2825 | bool isCapturedIn(bool CapturedInMem, bool CapturedInInt, | 
|  | 2826 | bool CapturedInRet) { | 
|  | 2827 | LLVM_DEBUG(dbgs() << " - captures [Mem " << CapturedInMem << "|Int " | 
|  | 2828 | << CapturedInInt << "|Ret " << CapturedInRet << "]\n"); | 
|  | 2829 | if (CapturedInMem) | 
|  | 2830 | State.removeAssumedBits(AANoCapture::NOT_CAPTURED_IN_MEM); | 
|  | 2831 | if (CapturedInInt) | 
|  | 2832 | State.removeAssumedBits(AANoCapture::NOT_CAPTURED_IN_INT); | 
|  | 2833 | if (CapturedInRet) | 
|  | 2834 | State.removeAssumedBits(AANoCapture::NOT_CAPTURED_IN_RET); | 
|  | 2835 | return !State.isAssumed(AANoCapture::NO_CAPTURE_MAYBE_RETURNED); | 
|  | 2836 | } | 
|  | 2837 |  | 
|  | 2838 | private: | 
|  | 2839 | /// The attributor providing in-flight abstract attributes. | 
|  | 2840 | Attributor &A; | 
|  | 2841 |  | 
|  | 2842 | /// The abstract attribute currently updated. | 
|  | 2843 | AANoCapture &NoCaptureAA; | 
|  | 2844 |  | 
|  | 2845 | /// The abstract liveness state. | 
|  | 2846 | const AAIsDead &IsDeadAA; | 
|  | 2847 |  | 
|  | 2848 | /// The state currently updated. | 
|  | 2849 | IntegerState &State; | 
|  | 2850 |  | 
|  | 2851 | /// Set of potential copies of the tracked value. | 
|  | 2852 | SmallVectorImpl<const Value *> &PotentialCopies; | 
|  | 2853 |  | 
|  | 2854 | /// Global counter to limit the number of explored uses. | 
|  | 2855 | unsigned &RemainingUsesToExplore; | 
|  | 2856 | }; | 
|  | 2857 |  | 
|  | 2858 | ChangeStatus AANoCaptureImpl::updateImpl(Attributor &A) { | 
|  | 2859 | const IRPosition &IRP = getIRPosition(); | 
|  | 2860 | const Value *V = | 
|  | 2861 | getArgNo() >= 0 ? IRP.getAssociatedArgument() : &IRP.getAssociatedValue(); | 
|  | 2862 | if (!V) | 
|  | 2863 | return indicatePessimisticFixpoint(); | 
|  | 2864 |  | 
|  | 2865 | const Function *F = | 
|  | 2866 | getArgNo() >= 0 ? IRP.getAssociatedFunction() : IRP.getAnchorScope(); | 
|  | 2867 | assert(F && "Expected a function!"); | 
|  | 2868 | const auto &IsDeadAA = A.getAAFor<AAIsDead>(*this, IRPosition::function(*F)); | 
|  | 2869 |  | 
|  | 2870 | AANoCapture::StateType T; | 
|  | 2871 | // TODO: Once we have memory behavior attributes we should use them here | 
|  | 2872 | // similar to the reasoning in | 
|  | 2873 | // AANoCaptureImpl::determineFunctionCaptureCapabilities(...). | 
|  | 2874 |  | 
|  | 2875 | // TODO: Use the AAReturnedValues to learn if the argument can return or | 
|  | 2876 | // not. | 
|  | 2877 |  | 
|  | 2878 | // Use the CaptureTracker interface and logic with the specialized tracker, | 
|  | 2879 | // defined in AACaptureUseTracker, that can look at in-flight abstract | 
|  | 2880 | // attributes and directly updates the assumed state. | 
|  | 2881 | SmallVector<const Value *, 4> PotentialCopies; | 
|  | 2882 | unsigned RemainingUsesToExplore = DefaultMaxUsesToExplore; | 
|  | 2883 | AACaptureUseTracker Tracker(A, *this, IsDeadAA, T, PotentialCopies, | 
|  | 2884 | RemainingUsesToExplore); | 
|  | 2885 |  | 
|  | 2886 | // Check all potential copies of the associated value until we can assume | 
|  | 2887 | // none will be captured or we have to assume at least one might be. | 
|  | 2888 | unsigned Idx = 0; | 
|  | 2889 | PotentialCopies.push_back(V); | 
|  | 2890 | while (T.isAssumed(NO_CAPTURE_MAYBE_RETURNED) && Idx < PotentialCopies.size()) | 
|  | 2891 | Tracker.valueMayBeCaptured(PotentialCopies[Idx++]); | 
|  | 2892 |  | 
|  | 2893 | AAAlign::StateType &S = getState(); | 
|  | 2894 | auto Assumed = S.getAssumed(); | 
|  | 2895 | S.intersectAssumedBits(T.getAssumed()); | 
|  | 2896 | return Assumed == S.getAssumed() ? ChangeStatus::UNCHANGED | 
|  | 2897 | : ChangeStatus::CHANGED; | 
|  | 2898 | } | 
|  | 2899 |  | 
|  | 2900 | /// NoCapture attribute for function arguments. | 
|  | 2901 | struct AANoCaptureArgument final : AANoCaptureImpl { | 
|  | 2902 | AANoCaptureArgument(const IRPosition &IRP) : AANoCaptureImpl(IRP) {} | 
|  | 2903 |  | 
|  | 2904 | /// See AbstractAttribute::trackStatistics() | 
|  | 2905 | void trackStatistics() const override { STATS_DECLTRACK_ARG_ATTR(nocapture) } | 
|  | 2906 | }; | 
|  | 2907 |  | 
|  | 2908 | /// NoCapture attribute for call site arguments. | 
|  | 2909 | struct AANoCaptureCallSiteArgument final : AANoCaptureImpl { | 
|  | 2910 | AANoCaptureCallSiteArgument(const IRPosition &IRP) : AANoCaptureImpl(IRP) {} | 
|  | 2911 |  | 
|  | 2912 | /// See AbstractAttribute::updateImpl(...). | 
|  | 2913 | ChangeStatus updateImpl(Attributor &A) override { | 
|  | 2914 | // TODO: Once we have call site specific value information we can provide | 
|  | 2915 | //       call site specific liveness information and then it makes | 
|  | 2916 | //       sense to specialize attributes for call sites arguments instead of | 
|  | 2917 | //       redirecting requests to the callee argument. | 
|  | 2918 | Argument *Arg = getAssociatedArgument(); | 
|  | 2919 | if (!Arg) | 
|  | 2920 | return indicatePessimisticFixpoint(); | 
|  | 2921 | const IRPosition &ArgPos = IRPosition::argument(*Arg); | 
|  | 2922 | auto &ArgAA = A.getAAFor<AANoCapture>(*this, ArgPos); | 
|  | 2923 | return clampStateAndIndicateChange( | 
|  | 2924 | getState(), | 
|  | 2925 | static_cast<const AANoCapture::StateType &>(ArgAA.getState())); | 
|  | 2926 | } | 
|  | 2927 |  | 
|  | 2928 | /// See AbstractAttribute::trackStatistics() | 
|  | 2929 | void trackStatistics() const override{STATS_DECLTRACK_CSARG_ATTR(nocapture)}; | 
|  | 2930 | }; | 
|  | 2931 |  | 
|  | 2932 | /// NoCapture attribute for floating values. | 
|  | 2933 | struct AANoCaptureFloating final : AANoCaptureImpl { | 
|  | 2934 | AANoCaptureFloating(const IRPosition &IRP) : AANoCaptureImpl(IRP) {} | 
|  | 2935 |  | 
|  | 2936 | /// See AbstractAttribute::trackStatistics() | 
|  | 2937 | void trackStatistics() const override { | 
|  | 2938 | STATS_DECLTRACK_FLOATING_ATTR(nocapture) | 
|  | 2939 | } | 
|  | 2940 | }; | 
|  | 2941 |  | 
|  | 2942 | /// NoCapture attribute for function return value. | 
|  | 2943 | struct AANoCaptureReturned final : AANoCaptureImpl { | 
|  | 2944 | AANoCaptureReturned(const IRPosition &IRP) : AANoCaptureImpl(IRP) { | 
|  | 2945 | llvm_unreachable("NoCapture is not applicable to function returns!"); | 
|  | 2946 | } | 
|  | 2947 |  | 
|  | 2948 | /// See AbstractAttribute::initialize(...). | 
|  | 2949 | void initialize(Attributor &A) override { | 
|  | 2950 | llvm_unreachable("NoCapture is not applicable to function returns!"); | 
|  | 2951 | } | 
|  | 2952 |  | 
|  | 2953 | /// See AbstractAttribute::updateImpl(...). | 
|  | 2954 | ChangeStatus updateImpl(Attributor &A) override { | 
|  | 2955 | llvm_unreachable("NoCapture is not applicable to function returns!"); | 
|  | 2956 | } | 
|  | 2957 |  | 
|  | 2958 | /// See AbstractAttribute::trackStatistics() | 
|  | 2959 | void trackStatistics() const override {} | 
|  | 2960 | }; | 
|  | 2961 |  | 
|  | 2962 | /// NoCapture attribute deduction for a call site return value. | 
|  | 2963 | struct AANoCaptureCallSiteReturned final : AANoCaptureImpl { | 
|  | 2964 | AANoCaptureCallSiteReturned(const IRPosition &IRP) : AANoCaptureImpl(IRP) {} | 
|  | 2965 |  | 
|  | 2966 | /// See AbstractAttribute::trackStatistics() | 
|  | 2967 | void trackStatistics() const override { | 
|  | 2968 | STATS_DECLTRACK_CSRET_ATTR(nocapture) | 
|  | 2969 | } | 
|  | 2970 | }; | 
|  | 2971 |  | 
| Hideto Ueno | f2b9dc4 | 2019-09-07 07:03:05 +0000 | [diff] [blame] | 2972 | /// ------------------ Value Simplify Attribute ---------------------------- | 
|  | 2973 | struct AAValueSimplifyImpl : AAValueSimplify { | 
|  | 2974 | AAValueSimplifyImpl(const IRPosition &IRP) : AAValueSimplify(IRP) {} | 
|  | 2975 |  | 
|  | 2976 | /// See AbstractAttribute::getAsStr(). | 
|  | 2977 | const std::string getAsStr() const override { | 
|  | 2978 | return getAssumed() ? (getKnown() ? "simplified" : "maybe-simple") | 
|  | 2979 | : "not-simple"; | 
|  | 2980 | } | 
|  | 2981 |  | 
|  | 2982 | /// See AbstractAttribute::trackStatistics() | 
|  | 2983 | void trackStatistics() const override {} | 
|  | 2984 |  | 
|  | 2985 | /// See AAValueSimplify::getAssumedSimplifiedValue() | 
|  | 2986 | Optional<Value *> getAssumedSimplifiedValue(Attributor &A) const override { | 
|  | 2987 | if (!getAssumed()) | 
|  | 2988 | return const_cast<Value *>(&getAssociatedValue()); | 
|  | 2989 | return SimplifiedAssociatedValue; | 
|  | 2990 | } | 
|  | 2991 | void initialize(Attributor &A) override {} | 
|  | 2992 |  | 
|  | 2993 | /// Helper function for querying AAValueSimplify and updating candicate. | 
|  | 2994 | /// \param QueryingValue Value trying to unify with SimplifiedValue | 
|  | 2995 | /// \param AccumulatedSimplifiedValue Current simplification result. | 
|  | 2996 | static bool checkAndUpdate(Attributor &A, const AbstractAttribute &QueryingAA, | 
|  | 2997 | Value &QueryingValue, | 
|  | 2998 | Optional<Value *> &AccumulatedSimplifiedValue) { | 
|  | 2999 | // FIXME: Add a typecast support. | 
|  | 3000 |  | 
|  | 3001 | auto &ValueSimpifyAA = A.getAAFor<AAValueSimplify>( | 
|  | 3002 | QueryingAA, IRPosition::value(QueryingValue)); | 
|  | 3003 |  | 
|  | 3004 | Optional<Value *> QueryingValueSimplified = | 
|  | 3005 | ValueSimpifyAA.getAssumedSimplifiedValue(A); | 
|  | 3006 |  | 
|  | 3007 | if (!QueryingValueSimplified.hasValue()) | 
|  | 3008 | return true; | 
|  | 3009 |  | 
|  | 3010 | if (!QueryingValueSimplified.getValue()) | 
|  | 3011 | return false; | 
|  | 3012 |  | 
|  | 3013 | Value &QueryingValueSimplifiedUnwrapped = | 
|  | 3014 | *QueryingValueSimplified.getValue(); | 
|  | 3015 |  | 
|  | 3016 | if (isa<UndefValue>(QueryingValueSimplifiedUnwrapped)) | 
|  | 3017 | return true; | 
|  | 3018 |  | 
|  | 3019 | if (AccumulatedSimplifiedValue.hasValue()) | 
|  | 3020 | return AccumulatedSimplifiedValue == QueryingValueSimplified; | 
|  | 3021 |  | 
|  | 3022 | LLVM_DEBUG(dbgs() << "[Attributor][ValueSimplify] " << QueryingValue | 
|  | 3023 | << " is assumed to be " | 
|  | 3024 | << QueryingValueSimplifiedUnwrapped << "\n"); | 
|  | 3025 |  | 
|  | 3026 | AccumulatedSimplifiedValue = QueryingValueSimplified; | 
|  | 3027 | return true; | 
|  | 3028 | } | 
|  | 3029 |  | 
|  | 3030 | /// See AbstractAttribute::manifest(...). | 
|  | 3031 | ChangeStatus manifest(Attributor &A) override { | 
|  | 3032 | ChangeStatus Changed = ChangeStatus::UNCHANGED; | 
|  | 3033 |  | 
|  | 3034 | if (!SimplifiedAssociatedValue.hasValue() || | 
|  | 3035 | !SimplifiedAssociatedValue.getValue()) | 
|  | 3036 | return Changed; | 
|  | 3037 |  | 
|  | 3038 | if (auto *C = dyn_cast<Constant>(SimplifiedAssociatedValue.getValue())) { | 
|  | 3039 | // We can replace the AssociatedValue with the constant. | 
|  | 3040 | Value &V = getAssociatedValue(); | 
|  | 3041 | if (!V.user_empty() && &V != C && V.getType() == C->getType()) { | 
|  | 3042 | LLVM_DEBUG(dbgs() << "[Attributor][ValueSimplify] " << V << " -> " << *C | 
|  | 3043 | << "\n"); | 
|  | 3044 | V.replaceAllUsesWith(C); | 
|  | 3045 | Changed = ChangeStatus::CHANGED; | 
|  | 3046 | } | 
|  | 3047 | } | 
|  | 3048 |  | 
|  | 3049 | return Changed | AAValueSimplify::manifest(A); | 
|  | 3050 | } | 
|  | 3051 |  | 
|  | 3052 | protected: | 
|  | 3053 | // An assumed simplified value. Initially, it is set to Optional::None, which | 
|  | 3054 | // means that the value is not clear under current assumption. If in the | 
|  | 3055 | // pessimistic state, getAssumedSimplifiedValue doesn't return this value but | 
|  | 3056 | // returns orignal associated value. | 
|  | 3057 | Optional<Value *> SimplifiedAssociatedValue; | 
|  | 3058 | }; | 
|  | 3059 |  | 
|  | 3060 | struct AAValueSimplifyArgument final : AAValueSimplifyImpl { | 
|  | 3061 | AAValueSimplifyArgument(const IRPosition &IRP) : AAValueSimplifyImpl(IRP) {} | 
|  | 3062 |  | 
|  | 3063 | /// See AbstractAttribute::updateImpl(...). | 
|  | 3064 | ChangeStatus updateImpl(Attributor &A) override { | 
|  | 3065 | bool HasValueBefore = SimplifiedAssociatedValue.hasValue(); | 
|  | 3066 |  | 
|  | 3067 | auto PredForCallSite = [&](CallSite CS) { | 
|  | 3068 | return checkAndUpdate(A, *this, *CS.getArgOperand(getArgNo()), | 
|  | 3069 | SimplifiedAssociatedValue); | 
|  | 3070 | }; | 
|  | 3071 |  | 
|  | 3072 | if (!A.checkForAllCallSites(PredForCallSite, *this, true)) | 
|  | 3073 | return indicatePessimisticFixpoint(); | 
|  | 3074 |  | 
|  | 3075 | // If a candicate was found in this update, return CHANGED. | 
|  | 3076 | return HasValueBefore == SimplifiedAssociatedValue.hasValue() | 
|  | 3077 | ? ChangeStatus::UNCHANGED | 
|  | 3078 | : ChangeStatus ::CHANGED; | 
|  | 3079 | } | 
|  | 3080 |  | 
|  | 3081 | /// See AbstractAttribute::trackStatistics() | 
|  | 3082 | void trackStatistics() const override { | 
|  | 3083 | STATS_DECLTRACK_ARG_ATTR(value_simplify) | 
|  | 3084 | } | 
|  | 3085 | }; | 
|  | 3086 |  | 
|  | 3087 | struct AAValueSimplifyReturned : AAValueSimplifyImpl { | 
|  | 3088 | AAValueSimplifyReturned(const IRPosition &IRP) : AAValueSimplifyImpl(IRP) {} | 
|  | 3089 |  | 
|  | 3090 | /// See AbstractAttribute::updateImpl(...). | 
|  | 3091 | ChangeStatus updateImpl(Attributor &A) override { | 
|  | 3092 | bool HasValueBefore = SimplifiedAssociatedValue.hasValue(); | 
|  | 3093 |  | 
|  | 3094 | auto PredForReturned = [&](Value &V) { | 
|  | 3095 | return checkAndUpdate(A, *this, V, SimplifiedAssociatedValue); | 
|  | 3096 | }; | 
|  | 3097 |  | 
|  | 3098 | if (!A.checkForAllReturnedValues(PredForReturned, *this)) | 
|  | 3099 | return indicatePessimisticFixpoint(); | 
|  | 3100 |  | 
|  | 3101 | // If a candicate was found in this update, return CHANGED. | 
|  | 3102 | return HasValueBefore == SimplifiedAssociatedValue.hasValue() | 
|  | 3103 | ? ChangeStatus::UNCHANGED | 
|  | 3104 | : ChangeStatus ::CHANGED; | 
|  | 3105 | } | 
|  | 3106 | /// See AbstractAttribute::trackStatistics() | 
|  | 3107 | void trackStatistics() const override { | 
|  | 3108 | STATS_DECLTRACK_FNRET_ATTR(value_simplify) | 
|  | 3109 | } | 
|  | 3110 | }; | 
|  | 3111 |  | 
|  | 3112 | struct AAValueSimplifyFloating : AAValueSimplifyImpl { | 
|  | 3113 | AAValueSimplifyFloating(const IRPosition &IRP) : AAValueSimplifyImpl(IRP) {} | 
|  | 3114 |  | 
|  | 3115 | /// See AbstractAttribute::initialize(...). | 
|  | 3116 | void initialize(Attributor &A) override { | 
|  | 3117 | Value &V = getAnchorValue(); | 
|  | 3118 |  | 
|  | 3119 | // TODO: add other stuffs | 
|  | 3120 | if (isa<Constant>(V) || isa<UndefValue>(V)) | 
|  | 3121 | indicatePessimisticFixpoint(); | 
|  | 3122 | } | 
|  | 3123 |  | 
|  | 3124 | /// See AbstractAttribute::updateImpl(...). | 
|  | 3125 | ChangeStatus updateImpl(Attributor &A) override { | 
|  | 3126 | bool HasValueBefore = SimplifiedAssociatedValue.hasValue(); | 
|  | 3127 |  | 
|  | 3128 | auto VisitValueCB = [&](Value &V, BooleanState, bool Stripped) -> bool { | 
|  | 3129 | auto &AA = A.getAAFor<AAValueSimplify>(*this, IRPosition::value(V)); | 
|  | 3130 | if (!Stripped && this == &AA) { | 
|  | 3131 | // TODO: Look the instruction and check recursively. | 
|  | 3132 | LLVM_DEBUG( | 
|  | 3133 | dbgs() << "[Attributor][ValueSimplify] Can't be stripped more : " | 
|  | 3134 | << V << "\n"); | 
|  | 3135 | indicatePessimisticFixpoint(); | 
|  | 3136 | return false; | 
|  | 3137 | } | 
|  | 3138 | return checkAndUpdate(A, *this, V, SimplifiedAssociatedValue); | 
|  | 3139 | }; | 
|  | 3140 |  | 
|  | 3141 | if (!genericValueTraversal<AAValueSimplify, BooleanState>( | 
|  | 3142 | A, getIRPosition(), *this, static_cast<BooleanState &>(*this), | 
|  | 3143 | VisitValueCB)) | 
|  | 3144 | return indicatePessimisticFixpoint(); | 
|  | 3145 |  | 
|  | 3146 | // If a candicate was found in this update, return CHANGED. | 
|  | 3147 |  | 
|  | 3148 | return HasValueBefore == SimplifiedAssociatedValue.hasValue() | 
|  | 3149 | ? ChangeStatus::UNCHANGED | 
|  | 3150 | : ChangeStatus ::CHANGED; | 
|  | 3151 | } | 
|  | 3152 |  | 
|  | 3153 | /// See AbstractAttribute::trackStatistics() | 
|  | 3154 | void trackStatistics() const override { | 
|  | 3155 | STATS_DECLTRACK_FLOATING_ATTR(value_simplify) | 
|  | 3156 | } | 
|  | 3157 | }; | 
|  | 3158 |  | 
|  | 3159 | struct AAValueSimplifyFunction : AAValueSimplifyImpl { | 
|  | 3160 | AAValueSimplifyFunction(const IRPosition &IRP) : AAValueSimplifyImpl(IRP) {} | 
|  | 3161 |  | 
|  | 3162 | /// See AbstractAttribute::initialize(...). | 
|  | 3163 | void initialize(Attributor &A) override { | 
|  | 3164 | SimplifiedAssociatedValue = &getAnchorValue(); | 
|  | 3165 | indicateOptimisticFixpoint(); | 
|  | 3166 | } | 
|  | 3167 | /// See AbstractAttribute::initialize(...). | 
|  | 3168 | ChangeStatus updateImpl(Attributor &A) override { | 
|  | 3169 | llvm_unreachable( | 
|  | 3170 | "AAValueSimplify(Function|CallSite)::updateImpl will not be called"); | 
|  | 3171 | } | 
|  | 3172 | /// See AbstractAttribute::trackStatistics() | 
|  | 3173 | void trackStatistics() const override { | 
|  | 3174 | STATS_DECLTRACK_FN_ATTR(value_simplify) | 
|  | 3175 | } | 
|  | 3176 | }; | 
|  | 3177 |  | 
|  | 3178 | struct AAValueSimplifyCallSite : AAValueSimplifyFunction { | 
|  | 3179 | AAValueSimplifyCallSite(const IRPosition &IRP) | 
|  | 3180 | : AAValueSimplifyFunction(IRP) {} | 
|  | 3181 | /// See AbstractAttribute::trackStatistics() | 
|  | 3182 | void trackStatistics() const override { | 
|  | 3183 | STATS_DECLTRACK_CS_ATTR(value_simplify) | 
|  | 3184 | } | 
|  | 3185 | }; | 
|  | 3186 |  | 
|  | 3187 | struct AAValueSimplifyCallSiteReturned : AAValueSimplifyReturned { | 
|  | 3188 | AAValueSimplifyCallSiteReturned(const IRPosition &IRP) | 
|  | 3189 | : AAValueSimplifyReturned(IRP) {} | 
|  | 3190 |  | 
|  | 3191 | void trackStatistics() const override { | 
|  | 3192 | STATS_DECLTRACK_CSRET_ATTR(value_simplify) | 
|  | 3193 | } | 
|  | 3194 | }; | 
|  | 3195 | struct AAValueSimplifyCallSiteArgument : AAValueSimplifyFloating { | 
|  | 3196 | AAValueSimplifyCallSiteArgument(const IRPosition &IRP) | 
|  | 3197 | : AAValueSimplifyFloating(IRP) {} | 
|  | 3198 |  | 
|  | 3199 | void trackStatistics() const override { | 
|  | 3200 | STATS_DECLTRACK_CSARG_ATTR(value_simplify) | 
|  | 3201 | } | 
|  | 3202 | }; | 
|  | 3203 |  | 
| Stefan Stipanovic | 431141c | 2019-09-15 21:47:41 +0000 | [diff] [blame] | 3204 | /// ----------------------- Heap-To-Stack Conversion --------------------------- | 
|  | 3205 | struct AAHeapToStackImpl : public AAHeapToStack { | 
|  | 3206 | AAHeapToStackImpl(const IRPosition &IRP) : AAHeapToStack(IRP) {} | 
|  | 3207 |  | 
|  | 3208 | const std::string getAsStr() const override { | 
|  | 3209 | return "[H2S] Mallocs: " + std::to_string(MallocCalls.size()); | 
|  | 3210 | } | 
|  | 3211 |  | 
|  | 3212 | ChangeStatus manifest(Attributor &A) override { | 
|  | 3213 | assert(getState().isValidState() && | 
|  | 3214 | "Attempted to manifest an invalid state!"); | 
|  | 3215 |  | 
|  | 3216 | ChangeStatus HasChanged = ChangeStatus::UNCHANGED; | 
|  | 3217 | Function *F = getAssociatedFunction(); | 
|  | 3218 | const auto *TLI = A.getInfoCache().getTargetLibraryInfoForFunction(*F); | 
|  | 3219 |  | 
|  | 3220 | for (Instruction *MallocCall : MallocCalls) { | 
|  | 3221 | // This malloc cannot be replaced. | 
|  | 3222 | if (BadMallocCalls.count(MallocCall)) | 
|  | 3223 | continue; | 
|  | 3224 |  | 
|  | 3225 | for (Instruction *FreeCall : FreesForMalloc[MallocCall]) { | 
|  | 3226 | LLVM_DEBUG(dbgs() << "H2S: Removing free call: " << *FreeCall << "\n"); | 
|  | 3227 | A.deleteAfterManifest(*FreeCall); | 
|  | 3228 | HasChanged = ChangeStatus::CHANGED; | 
|  | 3229 | } | 
|  | 3230 |  | 
|  | 3231 | LLVM_DEBUG(dbgs() << "H2S: Removing malloc call: " << *MallocCall | 
|  | 3232 | << "\n"); | 
|  | 3233 |  | 
|  | 3234 | Constant *Size; | 
|  | 3235 | if (isCallocLikeFn(MallocCall, TLI)) { | 
|  | 3236 | auto *Num = cast<ConstantInt>(MallocCall->getOperand(0)); | 
|  | 3237 | auto *SizeT = dyn_cast<ConstantInt>(MallocCall->getOperand(1)); | 
|  | 3238 | APInt TotalSize = SizeT->getValue() * Num->getValue(); | 
|  | 3239 | Size = | 
|  | 3240 | ConstantInt::get(MallocCall->getOperand(0)->getType(), TotalSize); | 
|  | 3241 | } else { | 
|  | 3242 | Size = cast<ConstantInt>(MallocCall->getOperand(0)); | 
|  | 3243 | } | 
|  | 3244 |  | 
|  | 3245 | unsigned AS = cast<PointerType>(MallocCall->getType())->getAddressSpace(); | 
|  | 3246 | Instruction *AI = new AllocaInst(Type::getInt8Ty(F->getContext()), AS, | 
|  | 3247 | Size, "", MallocCall->getNextNode()); | 
|  | 3248 |  | 
|  | 3249 | if (AI->getType() != MallocCall->getType()) | 
|  | 3250 | AI = new BitCastInst(AI, MallocCall->getType(), "malloc_bc", | 
|  | 3251 | AI->getNextNode()); | 
|  | 3252 |  | 
|  | 3253 | MallocCall->replaceAllUsesWith(AI); | 
|  | 3254 |  | 
|  | 3255 | if (auto *II = dyn_cast<InvokeInst>(MallocCall)) { | 
|  | 3256 | auto *NBB = II->getNormalDest(); | 
|  | 3257 | BranchInst::Create(NBB, MallocCall->getParent()); | 
|  | 3258 | A.deleteAfterManifest(*MallocCall); | 
|  | 3259 | } else { | 
|  | 3260 | A.deleteAfterManifest(*MallocCall); | 
|  | 3261 | } | 
|  | 3262 |  | 
|  | 3263 | if (isCallocLikeFn(MallocCall, TLI)) { | 
|  | 3264 | auto *BI = new BitCastInst(AI, MallocCall->getType(), "calloc_bc", | 
|  | 3265 | AI->getNextNode()); | 
|  | 3266 | Value *Ops[] = { | 
|  | 3267 | BI, ConstantInt::get(F->getContext(), APInt(8, 0, false)), Size, | 
|  | 3268 | ConstantInt::get(Type::getInt1Ty(F->getContext()), false)}; | 
|  | 3269 |  | 
|  | 3270 | Type *Tys[] = {BI->getType(), MallocCall->getOperand(0)->getType()}; | 
|  | 3271 | Module *M = F->getParent(); | 
|  | 3272 | Function *Fn = Intrinsic::getDeclaration(M, Intrinsic::memset, Tys); | 
|  | 3273 | CallInst::Create(Fn, Ops, "", BI->getNextNode()); | 
|  | 3274 | } | 
|  | 3275 | HasChanged = ChangeStatus::CHANGED; | 
|  | 3276 | } | 
|  | 3277 |  | 
|  | 3278 | return HasChanged; | 
|  | 3279 | } | 
|  | 3280 |  | 
|  | 3281 | /// Collection of all malloc calls in a function. | 
|  | 3282 | SmallSetVector<Instruction *, 4> MallocCalls; | 
|  | 3283 |  | 
|  | 3284 | /// Collection of malloc calls that cannot be converted. | 
|  | 3285 | DenseSet<const Instruction *> BadMallocCalls; | 
|  | 3286 |  | 
|  | 3287 | /// A map for each malloc call to the set of associated free calls. | 
|  | 3288 | DenseMap<Instruction *, SmallPtrSet<Instruction *, 4>> FreesForMalloc; | 
|  | 3289 |  | 
|  | 3290 | ChangeStatus updateImpl(Attributor &A) override; | 
|  | 3291 | }; | 
|  | 3292 |  | 
|  | 3293 | ChangeStatus AAHeapToStackImpl::updateImpl(Attributor &A) { | 
|  | 3294 | const Function *F = getAssociatedFunction(); | 
|  | 3295 | const auto *TLI = A.getInfoCache().getTargetLibraryInfoForFunction(*F); | 
|  | 3296 |  | 
|  | 3297 | auto UsesCheck = [&](Instruction &I) { | 
|  | 3298 | SmallPtrSet<const Use *, 8> Visited; | 
|  | 3299 | SmallVector<const Use *, 8> Worklist; | 
|  | 3300 |  | 
|  | 3301 | for (Use &U : I.uses()) | 
|  | 3302 | Worklist.push_back(&U); | 
|  | 3303 |  | 
|  | 3304 | while (!Worklist.empty()) { | 
|  | 3305 | const Use *U = Worklist.pop_back_val(); | 
|  | 3306 | if (!Visited.insert(U).second) | 
|  | 3307 | continue; | 
|  | 3308 |  | 
|  | 3309 | auto *UserI = U->getUser(); | 
|  | 3310 |  | 
|  | 3311 | if (isa<LoadInst>(UserI) || isa<StoreInst>(UserI)) | 
|  | 3312 | continue; | 
|  | 3313 |  | 
|  | 3314 | // NOTE: Right now, if a function that has malloc pointer as an argument | 
|  | 3315 | // frees memory, we assume that the malloc pointer is freed. | 
|  | 3316 |  | 
|  | 3317 | // TODO: Add nofree callsite argument attribute to indicate that pointer | 
|  | 3318 | // argument is not freed. | 
|  | 3319 | if (auto *CB = dyn_cast<CallBase>(UserI)) { | 
|  | 3320 | if (!CB->isArgOperand(U)) | 
|  | 3321 | continue; | 
|  | 3322 |  | 
|  | 3323 | if (CB->isLifetimeStartOrEnd()) | 
|  | 3324 | continue; | 
|  | 3325 |  | 
|  | 3326 | // Record malloc. | 
|  | 3327 | if (isFreeCall(UserI, TLI)) { | 
|  | 3328 | FreesForMalloc[&I].insert( | 
|  | 3329 | cast<Instruction>(const_cast<User *>(UserI))); | 
|  | 3330 | continue; | 
|  | 3331 | } | 
|  | 3332 |  | 
|  | 3333 | // If a function does not free memory we are fine | 
|  | 3334 | const auto &NoFreeAA = | 
|  | 3335 | A.getAAFor<AANoFree>(*this, IRPosition::callsite_function(*CB)); | 
|  | 3336 |  | 
|  | 3337 | unsigned ArgNo = U - CB->arg_begin(); | 
|  | 3338 | const auto &NoCaptureAA = A.getAAFor<AANoCapture>( | 
|  | 3339 | *this, IRPosition::callsite_argument(*CB, ArgNo)); | 
|  | 3340 |  | 
|  | 3341 | if (!NoCaptureAA.isAssumedNoCapture() || !NoFreeAA.isAssumedNoFree()) { | 
|  | 3342 | LLVM_DEBUG(dbgs() << "[H2S] Bad user: " << *UserI << "\n"); | 
|  | 3343 | return false; | 
|  | 3344 | } | 
|  | 3345 | continue; | 
|  | 3346 | } | 
|  | 3347 |  | 
|  | 3348 | if (isa<GetElementPtrInst>(UserI) || isa<BitCastInst>(UserI)) { | 
|  | 3349 | for (Use &U : UserI->uses()) | 
|  | 3350 | Worklist.push_back(&U); | 
|  | 3351 | continue; | 
|  | 3352 | } | 
|  | 3353 |  | 
|  | 3354 | // Unknown user. | 
|  | 3355 | LLVM_DEBUG(dbgs() << "[H2S] Unknown user: " << *UserI << "\n"); | 
|  | 3356 | return false; | 
|  | 3357 | } | 
|  | 3358 | return true; | 
|  | 3359 | }; | 
|  | 3360 |  | 
|  | 3361 | auto MallocCallocCheck = [&](Instruction &I) { | 
|  | 3362 | if (isMallocLikeFn(&I, TLI)) { | 
|  | 3363 | if (auto *Size = dyn_cast<ConstantInt>(I.getOperand(0))) | 
|  | 3364 | if (!Size->getValue().sle(MaxHeapToStackSize)) | 
|  | 3365 | return true; | 
|  | 3366 | } else if (isCallocLikeFn(&I, TLI)) { | 
|  | 3367 | bool Overflow = false; | 
|  | 3368 | if (auto *Num = dyn_cast<ConstantInt>(I.getOperand(0))) | 
|  | 3369 | if (auto *Size = dyn_cast<ConstantInt>(I.getOperand(1))) | 
|  | 3370 | if (!(Size->getValue().umul_ov(Num->getValue(), Overflow)) | 
|  | 3371 | .sle(MaxHeapToStackSize)) | 
|  | 3372 | if (!Overflow) | 
|  | 3373 | return true; | 
|  | 3374 | } else { | 
|  | 3375 | BadMallocCalls.insert(&I); | 
|  | 3376 | return true; | 
|  | 3377 | } | 
|  | 3378 |  | 
|  | 3379 | if (BadMallocCalls.count(&I)) | 
|  | 3380 | return true; | 
|  | 3381 |  | 
|  | 3382 | if (UsesCheck(I)) | 
|  | 3383 | MallocCalls.insert(&I); | 
|  | 3384 | else | 
|  | 3385 | BadMallocCalls.insert(&I); | 
|  | 3386 | return true; | 
|  | 3387 | }; | 
|  | 3388 |  | 
|  | 3389 | size_t NumBadMallocs = BadMallocCalls.size(); | 
|  | 3390 |  | 
|  | 3391 | A.checkForAllCallLikeInstructions(MallocCallocCheck, *this); | 
|  | 3392 |  | 
|  | 3393 | if (NumBadMallocs != BadMallocCalls.size()) | 
|  | 3394 | return ChangeStatus::CHANGED; | 
|  | 3395 |  | 
|  | 3396 | return ChangeStatus::UNCHANGED; | 
|  | 3397 | } | 
|  | 3398 |  | 
|  | 3399 | struct AAHeapToStackFunction final : public AAHeapToStackImpl { | 
|  | 3400 | AAHeapToStackFunction(const IRPosition &IRP) : AAHeapToStackImpl(IRP) {} | 
|  | 3401 |  | 
|  | 3402 | /// See AbstractAttribute::trackStatistics() | 
|  | 3403 | void trackStatistics() const override { | 
|  | 3404 | STATS_DECL(MallocCalls, Function, | 
|  | 3405 | "Number of MallocCalls converted to allocas"); | 
|  | 3406 | BUILD_STAT_NAME(MallocCalls, Function) += MallocCalls.size(); | 
|  | 3407 | } | 
|  | 3408 | }; | 
|  | 3409 |  | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 3410 | /// ---------------------------------------------------------------------------- | 
|  | 3411 | ///                               Attributor | 
|  | 3412 | /// ---------------------------------------------------------------------------- | 
|  | 3413 |  | 
| Johannes Doerfert | 9a1a1f9 | 2019-08-14 21:25:08 +0000 | [diff] [blame] | 3414 | bool Attributor::isAssumedDead(const AbstractAttribute &AA, | 
|  | 3415 | const AAIsDead *LivenessAA) { | 
|  | 3416 | const Instruction *CtxI = AA.getIRPosition().getCtxI(); | 
|  | 3417 | if (!CtxI) | 
|  | 3418 | return false; | 
|  | 3419 |  | 
|  | 3420 | if (!LivenessAA) | 
|  | 3421 | LivenessAA = | 
| Johannes Doerfert | 19b0043 | 2019-08-26 17:48:05 +0000 | [diff] [blame] | 3422 | &getAAFor<AAIsDead>(AA, IRPosition::function(*CtxI->getFunction()), | 
|  | 3423 | /* TrackDependence */ false); | 
| Stefan Stipanovic | 26121ae | 2019-08-20 23:16:57 +0000 | [diff] [blame] | 3424 |  | 
|  | 3425 | // Don't check liveness for AAIsDead. | 
|  | 3426 | if (&AA == LivenessAA) | 
|  | 3427 | return false; | 
|  | 3428 |  | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 3429 | if (!LivenessAA->isAssumedDead(CtxI)) | 
| Johannes Doerfert | 9a1a1f9 | 2019-08-14 21:25:08 +0000 | [diff] [blame] | 3430 | return false; | 
|  | 3431 |  | 
| Johannes Doerfert | 19b0043 | 2019-08-26 17:48:05 +0000 | [diff] [blame] | 3432 | // We actually used liveness information so we have to record a dependence. | 
|  | 3433 | recordDependence(*LivenessAA, AA); | 
|  | 3434 |  | 
| Johannes Doerfert | 9a1a1f9 | 2019-08-14 21:25:08 +0000 | [diff] [blame] | 3435 | return true; | 
|  | 3436 | } | 
|  | 3437 |  | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 3438 | bool Attributor::checkForAllCallSites(const function_ref<bool(CallSite)> &Pred, | 
| Johannes Doerfert | 14a0493 | 2019-08-07 22:27:24 +0000 | [diff] [blame] | 3439 | const AbstractAttribute &QueryingAA, | 
| Johannes Doerfert | d0f6400 | 2019-08-06 00:32:43 +0000 | [diff] [blame] | 3440 | bool RequireAllCallSites) { | 
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 3441 | // We can try to determine information from | 
|  | 3442 | // the call sites. However, this is only possible all call sites are known, | 
|  | 3443 | // hence the function has internal linkage. | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 3444 | const IRPosition &IRP = QueryingAA.getIRPosition(); | 
|  | 3445 | const Function *AssociatedFunction = IRP.getAssociatedFunction(); | 
|  | 3446 | if (!AssociatedFunction) | 
|  | 3447 | return false; | 
|  | 3448 |  | 
|  | 3449 | if (RequireAllCallSites && !AssociatedFunction->hasInternalLinkage()) { | 
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 3450 | LLVM_DEBUG( | 
|  | 3451 | dbgs() | 
| Johannes Doerfert | 5304b72 | 2019-08-14 22:04:28 +0000 | [diff] [blame] | 3452 | << "[Attributor] Function " << AssociatedFunction->getName() | 
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 3453 | << " has no internal linkage, hence not all call sites are known\n"); | 
|  | 3454 | return false; | 
|  | 3455 | } | 
|  | 3456 |  | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 3457 | for (const Use &U : AssociatedFunction->uses()) { | 
| Johannes Doerfert | d98f975 | 2019-08-21 21:48:56 +0000 | [diff] [blame] | 3458 | Instruction *I = dyn_cast<Instruction>(U.getUser()); | 
|  | 3459 | // TODO: Deal with abstract call sites here. | 
|  | 3460 | if (!I) | 
|  | 3461 | return false; | 
|  | 3462 |  | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 3463 | Function *Caller = I->getFunction(); | 
| Stefan Stipanovic | d021617 | 2019-08-02 21:31:22 +0000 | [diff] [blame] | 3464 |  | 
| Johannes Doerfert | 19b0043 | 2019-08-26 17:48:05 +0000 | [diff] [blame] | 3465 | const auto &LivenessAA = getAAFor<AAIsDead>( | 
|  | 3466 | QueryingAA, IRPosition::function(*Caller), /* TrackDependence */ false); | 
| Stefan Stipanovic | d021617 | 2019-08-02 21:31:22 +0000 | [diff] [blame] | 3467 |  | 
|  | 3468 | // Skip dead calls. | 
| Johannes Doerfert | 19b0043 | 2019-08-26 17:48:05 +0000 | [diff] [blame] | 3469 | if (LivenessAA.isAssumedDead(I)) { | 
|  | 3470 | // We actually used liveness information so we have to record a | 
|  | 3471 | // dependence. | 
|  | 3472 | recordDependence(LivenessAA, QueryingAA); | 
| Stefan Stipanovic | d021617 | 2019-08-02 21:31:22 +0000 | [diff] [blame] | 3473 | continue; | 
| Johannes Doerfert | 19b0043 | 2019-08-26 17:48:05 +0000 | [diff] [blame] | 3474 | } | 
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 3475 |  | 
|  | 3476 | CallSite CS(U.getUser()); | 
| Johannes Doerfert | b0412e4 | 2019-09-04 16:16:13 +0000 | [diff] [blame] | 3477 | if (!CS || !CS.isCallee(&U)) { | 
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 3478 | if (!RequireAllCallSites) | 
|  | 3479 | continue; | 
|  | 3480 |  | 
| Johannes Doerfert | 5304b72 | 2019-08-14 22:04:28 +0000 | [diff] [blame] | 3481 | LLVM_DEBUG(dbgs() << "[Attributor] User " << *U.getUser() | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 3482 | << " is an invalid use of " | 
|  | 3483 | << AssociatedFunction->getName() << "\n"); | 
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 3484 | return false; | 
|  | 3485 | } | 
|  | 3486 |  | 
|  | 3487 | if (Pred(CS)) | 
|  | 3488 | continue; | 
|  | 3489 |  | 
| Johannes Doerfert | 5304b72 | 2019-08-14 22:04:28 +0000 | [diff] [blame] | 3490 | LLVM_DEBUG(dbgs() << "[Attributor] Call site callback failed for " | 
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 3491 | << *CS.getInstruction() << "\n"); | 
|  | 3492 | return false; | 
|  | 3493 | } | 
|  | 3494 |  | 
|  | 3495 | return true; | 
|  | 3496 | } | 
|  | 3497 |  | 
| Johannes Doerfert | 14a0493 | 2019-08-07 22:27:24 +0000 | [diff] [blame] | 3498 | bool Attributor::checkForAllReturnedValuesAndReturnInsts( | 
| Johannes Doerfert | 695089e | 2019-08-23 15:23:49 +0000 | [diff] [blame] | 3499 | const function_ref<bool(Value &, const SmallSetVector<ReturnInst *, 4> &)> | 
| Johannes Doerfert | 14a0493 | 2019-08-07 22:27:24 +0000 | [diff] [blame] | 3500 | &Pred, | 
|  | 3501 | const AbstractAttribute &QueryingAA) { | 
|  | 3502 |  | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 3503 | const IRPosition &IRP = QueryingAA.getIRPosition(); | 
|  | 3504 | // Since we need to provide return instructions we have to have an exact | 
|  | 3505 | // definition. | 
|  | 3506 | const Function *AssociatedFunction = IRP.getAssociatedFunction(); | 
| Johannes Doerfert | b0412e4 | 2019-09-04 16:16:13 +0000 | [diff] [blame] | 3507 | if (!AssociatedFunction) | 
| Johannes Doerfert | 14a0493 | 2019-08-07 22:27:24 +0000 | [diff] [blame] | 3508 | return false; | 
|  | 3509 |  | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 3510 | // If this is a call site query we use the call site specific return values | 
|  | 3511 | // and liveness information. | 
| Johannes Doerfert | 07a5c12 | 2019-08-28 14:09:14 +0000 | [diff] [blame] | 3512 | // TODO: use the function scope once we have call site AAReturnedValues. | 
|  | 3513 | const IRPosition &QueryIRP = IRPosition::function(*AssociatedFunction); | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 3514 | const auto &AARetVal = getAAFor<AAReturnedValues>(QueryingAA, QueryIRP); | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 3515 | if (!AARetVal.getState().isValidState()) | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 3516 | return false; | 
|  | 3517 |  | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 3518 | return AARetVal.checkForAllReturnedValuesAndReturnInsts(Pred); | 
| Johannes Doerfert | 14a0493 | 2019-08-07 22:27:24 +0000 | [diff] [blame] | 3519 | } | 
|  | 3520 |  | 
|  | 3521 | bool Attributor::checkForAllReturnedValues( | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 3522 | const function_ref<bool(Value &)> &Pred, | 
| Johannes Doerfert | 14a0493 | 2019-08-07 22:27:24 +0000 | [diff] [blame] | 3523 | const AbstractAttribute &QueryingAA) { | 
|  | 3524 |  | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 3525 | const IRPosition &IRP = QueryingAA.getIRPosition(); | 
|  | 3526 | const Function *AssociatedFunction = IRP.getAssociatedFunction(); | 
| Johannes Doerfert | b0412e4 | 2019-09-04 16:16:13 +0000 | [diff] [blame] | 3527 | if (!AssociatedFunction) | 
| Johannes Doerfert | 14a0493 | 2019-08-07 22:27:24 +0000 | [diff] [blame] | 3528 | return false; | 
|  | 3529 |  | 
| Johannes Doerfert | 07a5c12 | 2019-08-28 14:09:14 +0000 | [diff] [blame] | 3530 | // TODO: use the function scope once we have call site AAReturnedValues. | 
|  | 3531 | const IRPosition &QueryIRP = IRPosition::function(*AssociatedFunction); | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 3532 | const auto &AARetVal = getAAFor<AAReturnedValues>(QueryingAA, QueryIRP); | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 3533 | if (!AARetVal.getState().isValidState()) | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 3534 | return false; | 
|  | 3535 |  | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 3536 | return AARetVal.checkForAllReturnedValuesAndReturnInsts( | 
| Johannes Doerfert | 695089e | 2019-08-23 15:23:49 +0000 | [diff] [blame] | 3537 | [&](Value &RV, const SmallSetVector<ReturnInst *, 4> &) { | 
| Johannes Doerfert | def9928 | 2019-08-14 21:29:37 +0000 | [diff] [blame] | 3538 | return Pred(RV); | 
|  | 3539 | }); | 
| Johannes Doerfert | 14a0493 | 2019-08-07 22:27:24 +0000 | [diff] [blame] | 3540 | } | 
|  | 3541 |  | 
| Johannes Doerfert | 3ab9e8b | 2019-09-17 10:52:41 +0000 | [diff] [blame^] | 3542 | static bool | 
|  | 3543 | checkForAllInstructionsImpl(InformationCache::OpcodeInstMapTy &OpcodeInstMap, | 
|  | 3544 | const function_ref<bool(Instruction &)> &Pred, | 
|  | 3545 | const AAIsDead *LivenessAA, bool &AnyDead, | 
|  | 3546 | const ArrayRef<unsigned> &Opcodes) { | 
|  | 3547 | for (unsigned Opcode : Opcodes) { | 
|  | 3548 | for (Instruction *I : OpcodeInstMap[Opcode]) { | 
|  | 3549 | // Skip dead instructions. | 
|  | 3550 | if (LivenessAA && LivenessAA->isAssumedDead(I)) { | 
|  | 3551 | AnyDead = true; | 
|  | 3552 | continue; | 
|  | 3553 | } | 
|  | 3554 |  | 
|  | 3555 | if (!Pred(*I)) | 
|  | 3556 | return false; | 
|  | 3557 | } | 
|  | 3558 | } | 
|  | 3559 | return true; | 
|  | 3560 | } | 
|  | 3561 |  | 
| Johannes Doerfert | d0f6400 | 2019-08-06 00:32:43 +0000 | [diff] [blame] | 3562 | bool Attributor::checkForAllInstructions( | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 3563 | const llvm::function_ref<bool(Instruction &)> &Pred, | 
| Johannes Doerfert | ece8190 | 2019-08-12 22:05:53 +0000 | [diff] [blame] | 3564 | const AbstractAttribute &QueryingAA, const ArrayRef<unsigned> &Opcodes) { | 
| Johannes Doerfert | d0f6400 | 2019-08-06 00:32:43 +0000 | [diff] [blame] | 3565 |  | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 3566 | const IRPosition &IRP = QueryingAA.getIRPosition(); | 
|  | 3567 | // Since we need to provide instructions we have to have an exact definition. | 
|  | 3568 | const Function *AssociatedFunction = IRP.getAssociatedFunction(); | 
| Johannes Doerfert | b0412e4 | 2019-09-04 16:16:13 +0000 | [diff] [blame] | 3569 | if (!AssociatedFunction) | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 3570 | return false; | 
| Johannes Doerfert | d0f6400 | 2019-08-06 00:32:43 +0000 | [diff] [blame] | 3571 |  | 
| Johannes Doerfert | 07a5c12 | 2019-08-28 14:09:14 +0000 | [diff] [blame] | 3572 | // TODO: use the function scope once we have call site AAReturnedValues. | 
|  | 3573 | const IRPosition &QueryIRP = IRPosition::function(*AssociatedFunction); | 
| Johannes Doerfert | 19b0043 | 2019-08-26 17:48:05 +0000 | [diff] [blame] | 3574 | const auto &LivenessAA = | 
|  | 3575 | getAAFor<AAIsDead>(QueryingAA, QueryIRP, /* TrackDependence */ false); | 
|  | 3576 | bool AnyDead = false; | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 3577 |  | 
|  | 3578 | auto &OpcodeInstMap = | 
|  | 3579 | InfoCache.getOpcodeInstMapForFunction(*AssociatedFunction); | 
| Johannes Doerfert | 3ab9e8b | 2019-09-17 10:52:41 +0000 | [diff] [blame^] | 3580 | if (!checkForAllInstructionsImpl(OpcodeInstMap, Pred, &LivenessAA, AnyDead, Opcodes)) | 
|  | 3581 | return false; | 
| Johannes Doerfert | d0f6400 | 2019-08-06 00:32:43 +0000 | [diff] [blame] | 3582 |  | 
| Johannes Doerfert | 19b0043 | 2019-08-26 17:48:05 +0000 | [diff] [blame] | 3583 | // If we actually used liveness information so we have to record a dependence. | 
|  | 3584 | if (AnyDead) | 
|  | 3585 | recordDependence(LivenessAA, QueryingAA); | 
|  | 3586 |  | 
| Johannes Doerfert | d0f6400 | 2019-08-06 00:32:43 +0000 | [diff] [blame] | 3587 | return true; | 
|  | 3588 | } | 
|  | 3589 |  | 
| Stefan Stipanovic | aaa5270 | 2019-08-07 18:26:02 +0000 | [diff] [blame] | 3590 | bool Attributor::checkForAllReadWriteInstructions( | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 3591 | const llvm::function_ref<bool(Instruction &)> &Pred, | 
| Johannes Doerfert | ece8190 | 2019-08-12 22:05:53 +0000 | [diff] [blame] | 3592 | AbstractAttribute &QueryingAA) { | 
| Stefan Stipanovic | aaa5270 | 2019-08-07 18:26:02 +0000 | [diff] [blame] | 3593 |  | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 3594 | const Function *AssociatedFunction = | 
|  | 3595 | QueryingAA.getIRPosition().getAssociatedFunction(); | 
|  | 3596 | if (!AssociatedFunction) | 
|  | 3597 | return false; | 
| Stefan Stipanovic | aaa5270 | 2019-08-07 18:26:02 +0000 | [diff] [blame] | 3598 |  | 
| Johannes Doerfert | 07a5c12 | 2019-08-28 14:09:14 +0000 | [diff] [blame] | 3599 | // TODO: use the function scope once we have call site AAReturnedValues. | 
|  | 3600 | const IRPosition &QueryIRP = IRPosition::function(*AssociatedFunction); | 
|  | 3601 | const auto &LivenessAA = | 
|  | 3602 | getAAFor<AAIsDead>(QueryingAA, QueryIRP, /* TrackDependence */ false); | 
| Johannes Doerfert | 19b0043 | 2019-08-26 17:48:05 +0000 | [diff] [blame] | 3603 | bool AnyDead = false; | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 3604 |  | 
|  | 3605 | for (Instruction *I : | 
|  | 3606 | InfoCache.getReadOrWriteInstsForFunction(*AssociatedFunction)) { | 
| Stefan Stipanovic | aaa5270 | 2019-08-07 18:26:02 +0000 | [diff] [blame] | 3607 | // Skip dead instructions. | 
| Johannes Doerfert | 19b0043 | 2019-08-26 17:48:05 +0000 | [diff] [blame] | 3608 | if (LivenessAA.isAssumedDead(I)) { | 
|  | 3609 | AnyDead = true; | 
| Stefan Stipanovic | aaa5270 | 2019-08-07 18:26:02 +0000 | [diff] [blame] | 3610 | continue; | 
| Johannes Doerfert | 19b0043 | 2019-08-26 17:48:05 +0000 | [diff] [blame] | 3611 | } | 
| Stefan Stipanovic | aaa5270 | 2019-08-07 18:26:02 +0000 | [diff] [blame] | 3612 |  | 
|  | 3613 | if (!Pred(*I)) | 
|  | 3614 | return false; | 
|  | 3615 | } | 
|  | 3616 |  | 
| Johannes Doerfert | 19b0043 | 2019-08-26 17:48:05 +0000 | [diff] [blame] | 3617 | // If we actually used liveness information so we have to record a dependence. | 
|  | 3618 | if (AnyDead) | 
|  | 3619 | recordDependence(LivenessAA, QueryingAA); | 
|  | 3620 |  | 
| Stefan Stipanovic | aaa5270 | 2019-08-07 18:26:02 +0000 | [diff] [blame] | 3621 | return true; | 
|  | 3622 | } | 
|  | 3623 |  | 
| Johannes Doerfert | 2f62206 | 2019-09-04 16:35:20 +0000 | [diff] [blame] | 3624 | ChangeStatus Attributor::run(Module &M) { | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 3625 | LLVM_DEBUG(dbgs() << "[Attributor] Identified and initialized " | 
|  | 3626 | << AllAbstractAttributes.size() | 
|  | 3627 | << " abstract attributes.\n"); | 
|  | 3628 |  | 
| Stefan Stipanovic | 5360589 | 2019-06-27 11:27:54 +0000 | [diff] [blame] | 3629 | // Now that all abstract attributes are collected and initialized we start | 
|  | 3630 | // the abstract analysis. | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 3631 |  | 
|  | 3632 | unsigned IterationCounter = 1; | 
|  | 3633 |  | 
|  | 3634 | SmallVector<AbstractAttribute *, 64> ChangedAAs; | 
|  | 3635 | SetVector<AbstractAttribute *> Worklist; | 
|  | 3636 | Worklist.insert(AllAbstractAttributes.begin(), AllAbstractAttributes.end()); | 
|  | 3637 |  | 
| Johannes Doerfert | f7ca0fe | 2019-08-28 16:58:52 +0000 | [diff] [blame] | 3638 | bool RecomputeDependences = false; | 
|  | 3639 |  | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 3640 | do { | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 3641 | // Remember the size to determine new attributes. | 
|  | 3642 | size_t NumAAs = AllAbstractAttributes.size(); | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 3643 | LLVM_DEBUG(dbgs() << "\n\n[Attributor] #Iteration: " << IterationCounter | 
|  | 3644 | << ", Worklist size: " << Worklist.size() << "\n"); | 
|  | 3645 |  | 
| Johannes Doerfert | f7ca0fe | 2019-08-28 16:58:52 +0000 | [diff] [blame] | 3646 | // If dependences (=QueryMap) are recomputed we have to look at all abstract | 
|  | 3647 | // attributes again, regardless of what changed in the last iteration. | 
|  | 3648 | if (RecomputeDependences) { | 
|  | 3649 | LLVM_DEBUG( | 
|  | 3650 | dbgs() << "[Attributor] Run all AAs to recompute dependences\n"); | 
|  | 3651 | QueryMap.clear(); | 
|  | 3652 | ChangedAAs.clear(); | 
|  | 3653 | Worklist.insert(AllAbstractAttributes.begin(), | 
|  | 3654 | AllAbstractAttributes.end()); | 
|  | 3655 | } | 
|  | 3656 |  | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 3657 | // Add all abstract attributes that are potentially dependent on one that | 
|  | 3658 | // changed to the work list. | 
|  | 3659 | for (AbstractAttribute *ChangedAA : ChangedAAs) { | 
|  | 3660 | auto &QuerriedAAs = QueryMap[ChangedAA]; | 
|  | 3661 | Worklist.insert(QuerriedAAs.begin(), QuerriedAAs.end()); | 
|  | 3662 | } | 
|  | 3663 |  | 
| Johannes Doerfert | b504eb8 | 2019-08-26 18:55:47 +0000 | [diff] [blame] | 3664 | LLVM_DEBUG(dbgs() << "[Attributor] #Iteration: " << IterationCounter | 
|  | 3665 | << ", Worklist+Dependent size: " << Worklist.size() | 
|  | 3666 | << "\n"); | 
|  | 3667 |  | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 3668 | // Reset the changed set. | 
|  | 3669 | ChangedAAs.clear(); | 
|  | 3670 |  | 
|  | 3671 | // Update all abstract attribute in the work list and record the ones that | 
|  | 3672 | // changed. | 
|  | 3673 | for (AbstractAttribute *AA : Worklist) | 
| Johannes Doerfert | 9a1a1f9 | 2019-08-14 21:25:08 +0000 | [diff] [blame] | 3674 | if (!isAssumedDead(*AA, nullptr)) | 
|  | 3675 | if (AA->update(*this) == ChangeStatus::CHANGED) | 
|  | 3676 | ChangedAAs.push_back(AA); | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 3677 |  | 
| Johannes Doerfert | f7ca0fe | 2019-08-28 16:58:52 +0000 | [diff] [blame] | 3678 | // Check if we recompute the dependences in the next iteration. | 
|  | 3679 | RecomputeDependences = (DepRecomputeInterval > 0 && | 
|  | 3680 | IterationCounter % DepRecomputeInterval == 0); | 
|  | 3681 |  | 
| Johannes Doerfert | 9543f14 | 2019-08-23 15:24:57 +0000 | [diff] [blame] | 3682 | // Add attributes to the changed set if they have been created in the last | 
|  | 3683 | // iteration. | 
|  | 3684 | ChangedAAs.append(AllAbstractAttributes.begin() + NumAAs, | 
|  | 3685 | AllAbstractAttributes.end()); | 
|  | 3686 |  | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 3687 | // Reset the work list and repopulate with the changed abstract attributes. | 
|  | 3688 | // Note that dependent ones are added above. | 
|  | 3689 | Worklist.clear(); | 
|  | 3690 | Worklist.insert(ChangedAAs.begin(), ChangedAAs.end()); | 
|  | 3691 |  | 
| Johannes Doerfert | bf11213 | 2019-08-29 01:29:44 +0000 | [diff] [blame] | 3692 | } while (!Worklist.empty() && (IterationCounter++ < MaxFixpointIterations || | 
|  | 3693 | VerifyMaxFixpointIterations)); | 
| Johannes Doerfert | f7ca0fe | 2019-08-28 16:58:52 +0000 | [diff] [blame] | 3694 |  | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 3695 | LLVM_DEBUG(dbgs() << "\n[Attributor] Fixpoint iteration done after: " | 
|  | 3696 | << IterationCounter << "/" << MaxFixpointIterations | 
|  | 3697 | << " iterations\n"); | 
|  | 3698 |  | 
| Johannes Doerfert | bf11213 | 2019-08-29 01:29:44 +0000 | [diff] [blame] | 3699 | size_t NumFinalAAs = AllAbstractAttributes.size(); | 
| Johannes Doerfert | b504eb8 | 2019-08-26 18:55:47 +0000 | [diff] [blame] | 3700 |  | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 3701 | bool FinishedAtFixpoint = Worklist.empty(); | 
|  | 3702 |  | 
|  | 3703 | // Reset abstract arguments not settled in a sound fixpoint by now. This | 
|  | 3704 | // happens when we stopped the fixpoint iteration early. Note that only the | 
|  | 3705 | // ones marked as "changed" *and* the ones transitively depending on them | 
|  | 3706 | // need to be reverted to a pessimistic state. Others might not be in a | 
|  | 3707 | // fixpoint state but we can use the optimistic results for them anyway. | 
|  | 3708 | SmallPtrSet<AbstractAttribute *, 32> Visited; | 
|  | 3709 | for (unsigned u = 0; u < ChangedAAs.size(); u++) { | 
|  | 3710 | AbstractAttribute *ChangedAA = ChangedAAs[u]; | 
|  | 3711 | if (!Visited.insert(ChangedAA).second) | 
|  | 3712 | continue; | 
|  | 3713 |  | 
|  | 3714 | AbstractState &State = ChangedAA->getState(); | 
|  | 3715 | if (!State.isAtFixpoint()) { | 
|  | 3716 | State.indicatePessimisticFixpoint(); | 
|  | 3717 |  | 
|  | 3718 | NumAttributesTimedOut++; | 
|  | 3719 | } | 
|  | 3720 |  | 
|  | 3721 | auto &QuerriedAAs = QueryMap[ChangedAA]; | 
|  | 3722 | ChangedAAs.append(QuerriedAAs.begin(), QuerriedAAs.end()); | 
|  | 3723 | } | 
|  | 3724 |  | 
|  | 3725 | LLVM_DEBUG({ | 
|  | 3726 | if (!Visited.empty()) | 
|  | 3727 | dbgs() << "\n[Attributor] Finalized " << Visited.size() | 
|  | 3728 | << " abstract attributes.\n"; | 
|  | 3729 | }); | 
|  | 3730 |  | 
|  | 3731 | unsigned NumManifested = 0; | 
|  | 3732 | unsigned NumAtFixpoint = 0; | 
|  | 3733 | ChangeStatus ManifestChange = ChangeStatus::UNCHANGED; | 
|  | 3734 | for (AbstractAttribute *AA : AllAbstractAttributes) { | 
|  | 3735 | AbstractState &State = AA->getState(); | 
|  | 3736 |  | 
|  | 3737 | // If there is not already a fixpoint reached, we can now take the | 
|  | 3738 | // optimistic state. This is correct because we enforced a pessimistic one | 
|  | 3739 | // on abstract attributes that were transitively dependent on a changed one | 
|  | 3740 | // already above. | 
|  | 3741 | if (!State.isAtFixpoint()) | 
|  | 3742 | State.indicateOptimisticFixpoint(); | 
|  | 3743 |  | 
|  | 3744 | // If the state is invalid, we do not try to manifest it. | 
|  | 3745 | if (!State.isValidState()) | 
|  | 3746 | continue; | 
|  | 3747 |  | 
| Johannes Doerfert | 9a1a1f9 | 2019-08-14 21:25:08 +0000 | [diff] [blame] | 3748 | // Skip dead code. | 
|  | 3749 | if (isAssumedDead(*AA, nullptr)) | 
|  | 3750 | continue; | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 3751 | // Manifest the state and record if we changed the IR. | 
|  | 3752 | ChangeStatus LocalChange = AA->manifest(*this); | 
| Johannes Doerfert | d1b79e0 | 2019-08-07 22:46:11 +0000 | [diff] [blame] | 3753 | if (LocalChange == ChangeStatus::CHANGED && AreStatisticsEnabled()) | 
|  | 3754 | AA->trackStatistics(); | 
|  | 3755 |  | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 3756 | ManifestChange = ManifestChange | LocalChange; | 
|  | 3757 |  | 
|  | 3758 | NumAtFixpoint++; | 
|  | 3759 | NumManifested += (LocalChange == ChangeStatus::CHANGED); | 
|  | 3760 | } | 
|  | 3761 |  | 
|  | 3762 | (void)NumManifested; | 
|  | 3763 | (void)NumAtFixpoint; | 
|  | 3764 | LLVM_DEBUG(dbgs() << "\n[Attributor] Manifested " << NumManifested | 
|  | 3765 | << " arguments while " << NumAtFixpoint | 
|  | 3766 | << " were in a valid fixpoint state\n"); | 
|  | 3767 |  | 
|  | 3768 | // If verification is requested, we finished this run at a fixpoint, and the | 
|  | 3769 | // IR was changed, we re-run the whole fixpoint analysis, starting at | 
|  | 3770 | // re-initialization of the arguments. This re-run should not result in an IR | 
|  | 3771 | // change. Though, the (virtual) state of attributes at the end of the re-run | 
|  | 3772 | // might be more optimistic than the known state or the IR state if the better | 
|  | 3773 | // state cannot be manifested. | 
|  | 3774 | if (VerifyAttributor && FinishedAtFixpoint && | 
|  | 3775 | ManifestChange == ChangeStatus::CHANGED) { | 
|  | 3776 | VerifyAttributor = false; | 
| Johannes Doerfert | 2f62206 | 2019-09-04 16:35:20 +0000 | [diff] [blame] | 3777 | ChangeStatus VerifyStatus = run(M); | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 3778 | if (VerifyStatus != ChangeStatus::UNCHANGED) | 
|  | 3779 | llvm_unreachable( | 
|  | 3780 | "Attributor verification failed, re-run did result in an IR change " | 
|  | 3781 | "even after a fixpoint was reached in the original run. (False " | 
|  | 3782 | "positives possible!)"); | 
|  | 3783 | VerifyAttributor = true; | 
|  | 3784 | } | 
|  | 3785 |  | 
|  | 3786 | NumAttributesManifested += NumManifested; | 
|  | 3787 | NumAttributesValidFixpoint += NumAtFixpoint; | 
|  | 3788 |  | 
| Fangrui Song | f182617 | 2019-08-20 07:21:43 +0000 | [diff] [blame] | 3789 | (void)NumFinalAAs; | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 3790 | assert( | 
|  | 3791 | NumFinalAAs == AllAbstractAttributes.size() && | 
|  | 3792 | "Expected the final number of abstract attributes to remain unchanged!"); | 
| Johannes Doerfert | 39681e7 | 2019-08-27 04:57:54 +0000 | [diff] [blame] | 3793 |  | 
|  | 3794 | // 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] | 3795 | { | 
|  | 3796 | LLVM_DEBUG(dbgs() << "\n[Attributor] Delete at least " | 
|  | 3797 | << ToBeDeletedFunctions.size() << " functions and " | 
|  | 3798 | << ToBeDeletedBlocks.size() << " blocks and " | 
|  | 3799 | << ToBeDeletedInsts.size() << " instructions\n"); | 
|  | 3800 | for (Instruction *I : ToBeDeletedInsts) { | 
|  | 3801 | if (!I->use_empty()) | 
|  | 3802 | I->replaceAllUsesWith(UndefValue::get(I->getType())); | 
|  | 3803 | I->eraseFromParent(); | 
|  | 3804 | } | 
| Johannes Doerfert | b19cd27 | 2019-09-03 20:42:16 +0000 | [diff] [blame] | 3805 |  | 
| Johannes Doerfert | 2f62206 | 2019-09-04 16:35:20 +0000 | [diff] [blame] | 3806 | if (unsigned NumDeadBlocks = ToBeDeletedBlocks.size()) { | 
|  | 3807 | SmallVector<BasicBlock *, 8> ToBeDeletedBBs; | 
|  | 3808 | ToBeDeletedBBs.reserve(NumDeadBlocks); | 
|  | 3809 | ToBeDeletedBBs.append(ToBeDeletedBlocks.begin(), ToBeDeletedBlocks.end()); | 
|  | 3810 | DeleteDeadBlocks(ToBeDeletedBBs); | 
|  | 3811 | STATS_DECLTRACK(AAIsDead, BasicBlock, | 
|  | 3812 | "Number of dead basic blocks deleted."); | 
|  | 3813 | } | 
| Johannes Doerfert | b19cd27 | 2019-09-03 20:42:16 +0000 | [diff] [blame] | 3814 |  | 
| Johannes Doerfert | 2f62206 | 2019-09-04 16:35:20 +0000 | [diff] [blame] | 3815 | STATS_DECL(AAIsDead, Function, "Number of dead functions deleted."); | 
|  | 3816 | for (Function *Fn : ToBeDeletedFunctions) { | 
|  | 3817 | Fn->replaceAllUsesWith(UndefValue::get(Fn->getType())); | 
|  | 3818 | Fn->eraseFromParent(); | 
|  | 3819 | STATS_TRACK(AAIsDead, Function); | 
|  | 3820 | } | 
|  | 3821 |  | 
|  | 3822 | // Identify dead internal functions and delete them. This happens outside | 
|  | 3823 | // the other fixpoint analysis as we might treat potentially dead functions | 
|  | 3824 | // as live to lower the number of iterations. If they happen to be dead, the | 
|  | 3825 | // below fixpoint loop will identify and eliminate them. | 
|  | 3826 | SmallVector<Function *, 8> InternalFns; | 
|  | 3827 | for (Function &F : M) | 
|  | 3828 | if (F.hasInternalLinkage()) | 
|  | 3829 | InternalFns.push_back(&F); | 
|  | 3830 |  | 
|  | 3831 | bool FoundDeadFn = true; | 
|  | 3832 | while (FoundDeadFn) { | 
|  | 3833 | FoundDeadFn = false; | 
|  | 3834 | for (unsigned u = 0, e = InternalFns.size(); u < e; ++u) { | 
|  | 3835 | Function *F = InternalFns[u]; | 
|  | 3836 | if (!F) | 
|  | 3837 | continue; | 
|  | 3838 |  | 
|  | 3839 | const auto *LivenessAA = | 
|  | 3840 | lookupAAFor<AAIsDead>(IRPosition::function(*F)); | 
|  | 3841 | if (LivenessAA && | 
|  | 3842 | !checkForAllCallSites([](CallSite CS) { return false; }, | 
|  | 3843 | *LivenessAA, true)) | 
|  | 3844 | continue; | 
|  | 3845 |  | 
|  | 3846 | STATS_TRACK(AAIsDead, Function); | 
|  | 3847 | F->replaceAllUsesWith(UndefValue::get(F->getType())); | 
|  | 3848 | F->eraseFromParent(); | 
|  | 3849 | InternalFns[u] = nullptr; | 
|  | 3850 | FoundDeadFn = true; | 
|  | 3851 | } | 
|  | 3852 | } | 
| Johannes Doerfert | 39681e7 | 2019-08-27 04:57:54 +0000 | [diff] [blame] | 3853 | } | 
|  | 3854 |  | 
| Johannes Doerfert | bf11213 | 2019-08-29 01:29:44 +0000 | [diff] [blame] | 3855 | if (VerifyMaxFixpointIterations && | 
|  | 3856 | IterationCounter != MaxFixpointIterations) { | 
|  | 3857 | errs() << "\n[Attributor] Fixpoint iteration done after: " | 
|  | 3858 | << IterationCounter << "/" << MaxFixpointIterations | 
|  | 3859 | << " iterations\n"; | 
|  | 3860 | llvm_unreachable("The fixpoint was not reached with exactly the number of " | 
|  | 3861 | "specified iterations!"); | 
|  | 3862 | } | 
|  | 3863 |  | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 3864 | return ManifestChange; | 
|  | 3865 | } | 
|  | 3866 |  | 
| Johannes Doerfert | 3ab9e8b | 2019-09-17 10:52:41 +0000 | [diff] [blame^] | 3867 | void Attributor::initializeInformationCache(Function &F) { | 
|  | 3868 |  | 
|  | 3869 | // Walk all instructions to find interesting instructions that might be | 
|  | 3870 | // queried by abstract attributes during their initialization or update. | 
|  | 3871 | // This has to happen before we create attributes. | 
|  | 3872 | auto &ReadOrWriteInsts = InfoCache.FuncRWInstsMap[&F]; | 
|  | 3873 | auto &InstOpcodeMap = InfoCache.FuncInstOpcodeMap[&F]; | 
|  | 3874 |  | 
|  | 3875 | for (Instruction &I : instructions(&F)) { | 
|  | 3876 | bool IsInterestingOpcode = false; | 
|  | 3877 |  | 
|  | 3878 | // To allow easy access to all instructions in a function with a given | 
|  | 3879 | // opcode we store them in the InfoCache. As not all opcodes are interesting | 
|  | 3880 | // to concrete attributes we only cache the ones that are as identified in | 
|  | 3881 | // the following switch. | 
|  | 3882 | // Note: There are no concrete attributes now so this is initially empty. | 
|  | 3883 | switch (I.getOpcode()) { | 
|  | 3884 | default: | 
|  | 3885 | assert((!ImmutableCallSite(&I)) && (!isa<CallBase>(&I)) && | 
|  | 3886 | "New call site/base instruction type needs to be known int the " | 
|  | 3887 | "Attributor."); | 
|  | 3888 | break; | 
|  | 3889 | case Instruction::Load: | 
|  | 3890 | // The alignment of a pointer is interesting for loads. | 
|  | 3891 | case Instruction::Store: | 
|  | 3892 | // The alignment of a pointer is interesting for stores. | 
|  | 3893 | case Instruction::Call: | 
|  | 3894 | case Instruction::CallBr: | 
|  | 3895 | case Instruction::Invoke: | 
|  | 3896 | case Instruction::CleanupRet: | 
|  | 3897 | case Instruction::CatchSwitch: | 
|  | 3898 | case Instruction::Resume: | 
|  | 3899 | case Instruction::Ret: | 
|  | 3900 | IsInterestingOpcode = true; | 
|  | 3901 | } | 
|  | 3902 | if (IsInterestingOpcode) | 
|  | 3903 | InstOpcodeMap[I.getOpcode()].push_back(&I); | 
|  | 3904 | if (I.mayReadOrWriteMemory()) | 
|  | 3905 | ReadOrWriteInsts.push_back(&I); | 
|  | 3906 | } | 
|  | 3907 | } | 
|  | 3908 |  | 
| Hideto Ueno | 3bb5cbc | 2019-09-17 05:45:18 +0000 | [diff] [blame] | 3909 | void Attributor::identifyDefaultAbstractAttributes(Function &F) { | 
| Johannes Doerfert | 2f62206 | 2019-09-04 16:35:20 +0000 | [diff] [blame] | 3910 | if (!VisitedFunctions.insert(&F).second) | 
|  | 3911 | return; | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 3912 |  | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 3913 | IRPosition FPos = IRPosition::function(F); | 
|  | 3914 |  | 
| Johannes Doerfert | 305b961 | 2019-08-04 18:40:01 +0000 | [diff] [blame] | 3915 | // Check for dead BasicBlocks in every function. | 
| Johannes Doerfert | 21fe0a3 | 2019-08-06 00:55:11 +0000 | [diff] [blame] | 3916 | // We need dead instruction detection because we do not want to deal with | 
|  | 3917 | // broken IR in which SSA rules do not apply. | 
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 3918 | getOrCreateAAFor<AAIsDead>(FPos); | 
| Johannes Doerfert | 305b961 | 2019-08-04 18:40:01 +0000 | [diff] [blame] | 3919 |  | 
|  | 3920 | // Every function might be "will-return". | 
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 3921 | getOrCreateAAFor<AAWillReturn>(FPos); | 
| Johannes Doerfert | 305b961 | 2019-08-04 18:40:01 +0000 | [diff] [blame] | 3922 |  | 
| Stefan Stipanovic | 5360589 | 2019-06-27 11:27:54 +0000 | [diff] [blame] | 3923 | // Every function can be nounwind. | 
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 3924 | getOrCreateAAFor<AANoUnwind>(FPos); | 
| Stefan Stipanovic | 5360589 | 2019-06-27 11:27:54 +0000 | [diff] [blame] | 3925 |  | 
| Stefan Stipanovic | 0626367 | 2019-07-11 21:37:40 +0000 | [diff] [blame] | 3926 | // Every function might be marked "nosync" | 
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 3927 | getOrCreateAAFor<AANoSync>(FPos); | 
| Stefan Stipanovic | 0626367 | 2019-07-11 21:37:40 +0000 | [diff] [blame] | 3928 |  | 
| Hideto Ueno | 65bbaf9 | 2019-07-12 17:38:51 +0000 | [diff] [blame] | 3929 | // Every function might be "no-free". | 
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 3930 | getOrCreateAAFor<AANoFree>(FPos); | 
| Hideto Ueno | 65bbaf9 | 2019-07-12 17:38:51 +0000 | [diff] [blame] | 3931 |  | 
| Johannes Doerfert | e83f303 | 2019-08-05 23:22:05 +0000 | [diff] [blame] | 3932 | // Every function might be "no-return". | 
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 3933 | getOrCreateAAFor<AANoReturn>(FPos); | 
| Johannes Doerfert | e83f303 | 2019-08-05 23:22:05 +0000 | [diff] [blame] | 3934 |  | 
| Stefan Stipanovic | 431141c | 2019-09-15 21:47:41 +0000 | [diff] [blame] | 3935 | // Every function might be applicable for Heap-To-Stack conversion. | 
|  | 3936 | if (EnableHeapToStack) | 
|  | 3937 | getOrCreateAAFor<AAHeapToStack>(FPos); | 
|  | 3938 |  | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 3939 | // Return attributes are only appropriate if the return type is non void. | 
|  | 3940 | Type *ReturnType = F.getReturnType(); | 
|  | 3941 | if (!ReturnType->isVoidTy()) { | 
|  | 3942 | // Argument attribute "returned" --- Create only one per function even | 
|  | 3943 | // though it is an argument attribute. | 
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 3944 | getOrCreateAAFor<AAReturnedValues>(FPos); | 
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 3945 |  | 
| Hideto Ueno | f2b9dc4 | 2019-09-07 07:03:05 +0000 | [diff] [blame] | 3946 | IRPosition RetPos = IRPosition::returned(F); | 
|  | 3947 |  | 
|  | 3948 | // Every function might be simplified. | 
|  | 3949 | getOrCreateAAFor<AAValueSimplify>(RetPos); | 
|  | 3950 |  | 
| Stefan Stipanovic | 69ebb02 | 2019-07-22 19:36:27 +0000 | [diff] [blame] | 3951 | if (ReturnType->isPointerTy()) { | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 3952 |  | 
| Hideto Ueno | e7bea9b | 2019-07-28 07:04:01 +0000 | [diff] [blame] | 3953 | // Every function with pointer return type might be marked align. | 
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 3954 | getOrCreateAAFor<AAAlign>(RetPos); | 
| Hideto Ueno | e7bea9b | 2019-07-28 07:04:01 +0000 | [diff] [blame] | 3955 |  | 
| Stefan Stipanovic | 69ebb02 | 2019-07-22 19:36:27 +0000 | [diff] [blame] | 3956 | // Every function with pointer return type might be marked nonnull. | 
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 3957 | getOrCreateAAFor<AANonNull>(RetPos); | 
| Stefan Stipanovic | 69ebb02 | 2019-07-22 19:36:27 +0000 | [diff] [blame] | 3958 |  | 
|  | 3959 | // Every function with pointer return type might be marked noalias. | 
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 3960 | getOrCreateAAFor<AANoAlias>(RetPos); | 
| Hideto Ueno | 19c07af | 2019-07-23 08:16:17 +0000 | [diff] [blame] | 3961 |  | 
|  | 3962 | // Every function with pointer return type might be marked | 
|  | 3963 | // dereferenceable. | 
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 3964 | getOrCreateAAFor<AADereferenceable>(RetPos); | 
| Stefan Stipanovic | 69ebb02 | 2019-07-22 19:36:27 +0000 | [diff] [blame] | 3965 | } | 
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 3966 | } | 
|  | 3967 |  | 
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 3968 | for (Argument &Arg : F.args()) { | 
| Hideto Ueno | f2b9dc4 | 2019-09-07 07:03:05 +0000 | [diff] [blame] | 3969 | IRPosition ArgPos = IRPosition::argument(Arg); | 
|  | 3970 |  | 
|  | 3971 | // Every argument might be simplified. | 
|  | 3972 | getOrCreateAAFor<AAValueSimplify>(ArgPos); | 
|  | 3973 |  | 
| Hideto Ueno | 19c07af | 2019-07-23 08:16:17 +0000 | [diff] [blame] | 3974 | if (Arg.getType()->isPointerTy()) { | 
|  | 3975 | // Every argument with pointer type might be marked nonnull. | 
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 3976 | getOrCreateAAFor<AANonNull>(ArgPos); | 
| Hideto Ueno | 19c07af | 2019-07-23 08:16:17 +0000 | [diff] [blame] | 3977 |  | 
| Hideto Ueno | cbab334 | 2019-08-29 05:52:00 +0000 | [diff] [blame] | 3978 | // Every argument with pointer type might be marked noalias. | 
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 3979 | getOrCreateAAFor<AANoAlias>(ArgPos); | 
| Hideto Ueno | cbab334 | 2019-08-29 05:52:00 +0000 | [diff] [blame] | 3980 |  | 
| Hideto Ueno | 19c07af | 2019-07-23 08:16:17 +0000 | [diff] [blame] | 3981 | // Every argument with pointer type might be marked dereferenceable. | 
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 3982 | getOrCreateAAFor<AADereferenceable>(ArgPos); | 
| Hideto Ueno | e7bea9b | 2019-07-28 07:04:01 +0000 | [diff] [blame] | 3983 |  | 
|  | 3984 | // Every argument with pointer type might be marked align. | 
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 3985 | getOrCreateAAFor<AAAlign>(ArgPos); | 
| Johannes Doerfert | 7516a5e | 2019-09-03 20:37:24 +0000 | [diff] [blame] | 3986 |  | 
|  | 3987 | // Every argument with pointer type might be marked nocapture. | 
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 3988 | getOrCreateAAFor<AANoCapture>(ArgPos); | 
| Hideto Ueno | 19c07af | 2019-07-23 08:16:17 +0000 | [diff] [blame] | 3989 | } | 
| Johannes Doerfert | accd3e8 | 2019-07-08 23:27:20 +0000 | [diff] [blame] | 3990 | } | 
|  | 3991 |  | 
| Johannes Doerfert | 3ab9e8b | 2019-09-17 10:52:41 +0000 | [diff] [blame^] | 3992 | auto CallSitePred = [&](Instruction &I) -> bool { | 
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 3993 | CallSite CS(&I); | 
| Johannes Doerfert | 3ab9e8b | 2019-09-17 10:52:41 +0000 | [diff] [blame^] | 3994 | if (CS.getCalledFunction()) { | 
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 3995 | for (int i = 0, e = CS.getCalledFunction()->arg_size(); i < e; i++) { | 
| Hideto Ueno | f2b9dc4 | 2019-09-07 07:03:05 +0000 | [diff] [blame] | 3996 |  | 
|  | 3997 | IRPosition CSArgPos = IRPosition::callsite_argument(CS, i); | 
|  | 3998 |  | 
|  | 3999 | // Call site argument might be simplified. | 
|  | 4000 | getOrCreateAAFor<AAValueSimplify>(CSArgPos); | 
|  | 4001 |  | 
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 4002 | if (!CS.getArgument(i)->getType()->isPointerTy()) | 
|  | 4003 | continue; | 
|  | 4004 |  | 
|  | 4005 | // Call site argument attribute "non-null". | 
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 4006 | getOrCreateAAFor<AANonNull>(CSArgPos); | 
| Hideto Ueno | 19c07af | 2019-07-23 08:16:17 +0000 | [diff] [blame] | 4007 |  | 
| Hideto Ueno | cbab334 | 2019-08-29 05:52:00 +0000 | [diff] [blame] | 4008 | // Call site argument attribute "no-alias". | 
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 4009 | getOrCreateAAFor<AANoAlias>(CSArgPos); | 
| Hideto Ueno | cbab334 | 2019-08-29 05:52:00 +0000 | [diff] [blame] | 4010 |  | 
| Hideto Ueno | 19c07af | 2019-07-23 08:16:17 +0000 | [diff] [blame] | 4011 | // Call site argument attribute "dereferenceable". | 
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 4012 | getOrCreateAAFor<AADereferenceable>(CSArgPos); | 
| Hideto Ueno | e7bea9b | 2019-07-28 07:04:01 +0000 | [diff] [blame] | 4013 |  | 
|  | 4014 | // Call site argument attribute "align". | 
| Johannes Doerfert | 97fd582 | 2019-09-04 16:26:20 +0000 | [diff] [blame] | 4015 | getOrCreateAAFor<AAAlign>(CSArgPos); | 
| Hideto Ueno | 54869ec | 2019-07-15 06:49:04 +0000 | [diff] [blame] | 4016 | } | 
|  | 4017 | } | 
| Johannes Doerfert | 3ab9e8b | 2019-09-17 10:52:41 +0000 | [diff] [blame^] | 4018 | return true; | 
|  | 4019 | }; | 
|  | 4020 |  | 
|  | 4021 | auto &OpcodeInstMap = InfoCache.getOpcodeInstMapForFunction(F); | 
|  | 4022 | bool Success, AnyDead = false; | 
|  | 4023 | Success = checkForAllInstructionsImpl( | 
|  | 4024 | OpcodeInstMap, CallSitePred, nullptr, AnyDead, | 
|  | 4025 | {(unsigned)Instruction::Invoke, (unsigned)Instruction::CallBr, | 
|  | 4026 | (unsigned)Instruction::Call}); | 
|  | 4027 | (void)Success; | 
|  | 4028 | assert(Success && !AnyDead && "Expected the check call to be successful!"); | 
|  | 4029 |  | 
|  | 4030 | auto LoadStorePred = [&](Instruction &I) -> bool { | 
|  | 4031 | if (isa<LoadInst>(I)) | 
|  | 4032 | getOrCreateAAFor<AAAlign>( | 
|  | 4033 | IRPosition::value(*cast<LoadInst>(I).getPointerOperand())); | 
|  | 4034 | else | 
|  | 4035 | getOrCreateAAFor<AAAlign>( | 
|  | 4036 | IRPosition::value(*cast<StoreInst>(I).getPointerOperand())); | 
|  | 4037 | return true; | 
|  | 4038 | }; | 
|  | 4039 | Success = checkForAllInstructionsImpl( | 
|  | 4040 | OpcodeInstMap, LoadStorePred, nullptr, AnyDead, | 
|  | 4041 | {(unsigned)Instruction::Load, (unsigned)Instruction::Store}); | 
|  | 4042 | (void)Success; | 
|  | 4043 | assert(Success && !AnyDead && "Expected the check call to be successful!"); | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 4044 | } | 
|  | 4045 |  | 
|  | 4046 | /// Helpers to ease debugging through output streams and print calls. | 
|  | 4047 | /// | 
|  | 4048 | ///{ | 
|  | 4049 | raw_ostream &llvm::operator<<(raw_ostream &OS, ChangeStatus S) { | 
|  | 4050 | return OS << (S == ChangeStatus::CHANGED ? "changed" : "unchanged"); | 
|  | 4051 | } | 
|  | 4052 |  | 
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 4053 | raw_ostream &llvm::operator<<(raw_ostream &OS, IRPosition::Kind AP) { | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 4054 | switch (AP) { | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 4055 | case IRPosition::IRP_INVALID: | 
|  | 4056 | return OS << "inv"; | 
|  | 4057 | case IRPosition::IRP_FLOAT: | 
|  | 4058 | return OS << "flt"; | 
|  | 4059 | case IRPosition::IRP_RETURNED: | 
|  | 4060 | return OS << "fn_ret"; | 
|  | 4061 | case IRPosition::IRP_CALL_SITE_RETURNED: | 
|  | 4062 | return OS << "cs_ret"; | 
|  | 4063 | case IRPosition::IRP_FUNCTION: | 
|  | 4064 | return OS << "fn"; | 
|  | 4065 | case IRPosition::IRP_CALL_SITE: | 
|  | 4066 | return OS << "cs"; | 
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 4067 | case IRPosition::IRP_ARGUMENT: | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 4068 | return OS << "arg"; | 
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 4069 | case IRPosition::IRP_CALL_SITE_ARGUMENT: | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 4070 | return OS << "cs_arg"; | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 4071 | } | 
|  | 4072 | llvm_unreachable("Unknown attribute position!"); | 
|  | 4073 | } | 
|  | 4074 |  | 
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 4075 | raw_ostream &llvm::operator<<(raw_ostream &OS, const IRPosition &Pos) { | 
| Johannes Doerfert | 710ebb0 | 2019-08-14 21:18:01 +0000 | [diff] [blame] | 4076 | const Value &AV = Pos.getAssociatedValue(); | 
|  | 4077 | return OS << "{" << Pos.getPositionKind() << ":" << AV.getName() << " [" | 
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 4078 | << Pos.getAnchorValue().getName() << "@" << Pos.getArgNo() << "]}"; | 
|  | 4079 | } | 
|  | 4080 |  | 
| Johannes Doerfert | acc8079 | 2019-08-12 22:07:34 +0000 | [diff] [blame] | 4081 | raw_ostream &llvm::operator<<(raw_ostream &OS, const IntegerState &S) { | 
|  | 4082 | return OS << "(" << S.getKnown() << "-" << S.getAssumed() << ")" | 
|  | 4083 | << static_cast<const AbstractState &>(S); | 
|  | 4084 | } | 
|  | 4085 |  | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 4086 | raw_ostream &llvm::operator<<(raw_ostream &OS, const AbstractState &S) { | 
|  | 4087 | return OS << (!S.isValidState() ? "top" : (S.isAtFixpoint() ? "fix" : "")); | 
|  | 4088 | } | 
|  | 4089 |  | 
|  | 4090 | raw_ostream &llvm::operator<<(raw_ostream &OS, const AbstractAttribute &AA) { | 
|  | 4091 | AA.print(OS); | 
|  | 4092 | return OS; | 
|  | 4093 | } | 
|  | 4094 |  | 
|  | 4095 | void AbstractAttribute::print(raw_ostream &OS) const { | 
| Johannes Doerfert | fb69f76 | 2019-08-05 23:32:31 +0000 | [diff] [blame] | 4096 | OS << "[P: " << getIRPosition() << "][" << getAsStr() << "][S: " << getState() | 
|  | 4097 | << "]"; | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 4098 | } | 
|  | 4099 | ///} | 
|  | 4100 |  | 
|  | 4101 | /// ---------------------------------------------------------------------------- | 
|  | 4102 | ///                       Pass (Manager) Boilerplate | 
|  | 4103 | /// ---------------------------------------------------------------------------- | 
|  | 4104 |  | 
| Hideto Ueno | 3bb5cbc | 2019-09-17 05:45:18 +0000 | [diff] [blame] | 4105 | static bool runAttributorOnModule(Module &M, AnalysisGetter &AG) { | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 4106 | if (DisableAttributor) | 
|  | 4107 | return false; | 
|  | 4108 |  | 
|  | 4109 | LLVM_DEBUG(dbgs() << "[Attributor] Run on module with " << M.size() | 
|  | 4110 | << " functions.\n"); | 
|  | 4111 |  | 
|  | 4112 | // Create an Attributor and initially empty information cache that is filled | 
|  | 4113 | // while we identify default attribute opportunities. | 
| Hideto Ueno | 3bb5cbc | 2019-09-17 05:45:18 +0000 | [diff] [blame] | 4114 | InformationCache InfoCache(M.getDataLayout(), AG); | 
| Johannes Doerfert | f7ca0fe | 2019-08-28 16:58:52 +0000 | [diff] [blame] | 4115 | Attributor A(InfoCache, DepRecInterval); | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 4116 |  | 
| Johannes Doerfert | 3ab9e8b | 2019-09-17 10:52:41 +0000 | [diff] [blame^] | 4117 | for (Function &F : M) | 
|  | 4118 | A.initializeInformationCache(F); | 
|  | 4119 |  | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 4120 | for (Function &F : M) { | 
| Johannes Doerfert | b0412e4 | 2019-09-04 16:16:13 +0000 | [diff] [blame] | 4121 | if (F.hasExactDefinition()) | 
|  | 4122 | NumFnWithExactDefinition++; | 
|  | 4123 | else | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 4124 | NumFnWithoutExactDefinition++; | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 4125 |  | 
|  | 4126 | // For now we ignore naked and optnone functions. | 
|  | 4127 | if (F.hasFnAttribute(Attribute::Naked) || | 
|  | 4128 | F.hasFnAttribute(Attribute::OptimizeNone)) | 
|  | 4129 | continue; | 
|  | 4130 |  | 
| Johannes Doerfert | 2f62206 | 2019-09-04 16:35:20 +0000 | [diff] [blame] | 4131 | // We look at internal functions only on-demand but if any use is not a | 
|  | 4132 | // direct call, we have to do it eagerly. | 
|  | 4133 | if (F.hasInternalLinkage()) { | 
|  | 4134 | if (llvm::all_of(F.uses(), [](const Use &U) { | 
|  | 4135 | return ImmutableCallSite(U.getUser()) && | 
|  | 4136 | ImmutableCallSite(U.getUser()).isCallee(&U); | 
|  | 4137 | })) | 
|  | 4138 | continue; | 
|  | 4139 | } | 
|  | 4140 |  | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 4141 | // Populate the Attributor with abstract attribute opportunities in the | 
|  | 4142 | // function and the information cache with IR information. | 
| Hideto Ueno | 3bb5cbc | 2019-09-17 05:45:18 +0000 | [diff] [blame] | 4143 | A.identifyDefaultAbstractAttributes(F); | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 4144 | } | 
|  | 4145 |  | 
| Johannes Doerfert | 2f62206 | 2019-09-04 16:35:20 +0000 | [diff] [blame] | 4146 | return A.run(M) == ChangeStatus::CHANGED; | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 4147 | } | 
|  | 4148 |  | 
|  | 4149 | PreservedAnalyses AttributorPass::run(Module &M, ModuleAnalysisManager &AM) { | 
| Stefan Stipanovic | 431141c | 2019-09-15 21:47:41 +0000 | [diff] [blame] | 4150 | auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); | 
|  | 4151 |  | 
| Hideto Ueno | 3bb5cbc | 2019-09-17 05:45:18 +0000 | [diff] [blame] | 4152 | AnalysisGetter AG(FAM); | 
|  | 4153 | if (runAttributorOnModule(M, AG)) { | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 4154 | // FIXME: Think about passes we will preserve and add them here. | 
|  | 4155 | return PreservedAnalyses::none(); | 
|  | 4156 | } | 
|  | 4157 | return PreservedAnalyses::all(); | 
|  | 4158 | } | 
|  | 4159 |  | 
|  | 4160 | namespace { | 
|  | 4161 |  | 
|  | 4162 | struct AttributorLegacyPass : public ModulePass { | 
|  | 4163 | static char ID; | 
|  | 4164 |  | 
|  | 4165 | AttributorLegacyPass() : ModulePass(ID) { | 
|  | 4166 | initializeAttributorLegacyPassPass(*PassRegistry::getPassRegistry()); | 
|  | 4167 | } | 
|  | 4168 |  | 
|  | 4169 | bool runOnModule(Module &M) override { | 
|  | 4170 | if (skipModule(M)) | 
|  | 4171 | return false; | 
| Stefan Stipanovic | 431141c | 2019-09-15 21:47:41 +0000 | [diff] [blame] | 4172 |  | 
| Hideto Ueno | 3bb5cbc | 2019-09-17 05:45:18 +0000 | [diff] [blame] | 4173 | AnalysisGetter AG; | 
|  | 4174 | return runAttributorOnModule(M, AG); | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 4175 | } | 
|  | 4176 |  | 
|  | 4177 | void getAnalysisUsage(AnalysisUsage &AU) const override { | 
|  | 4178 | // FIXME: Think about passes we will preserve and add them here. | 
| Stefan Stipanovic | 431141c | 2019-09-15 21:47:41 +0000 | [diff] [blame] | 4179 | AU.addRequired<TargetLibraryInfoWrapperPass>(); | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 4180 | } | 
|  | 4181 | }; | 
|  | 4182 |  | 
|  | 4183 | } // end anonymous namespace | 
|  | 4184 |  | 
|  | 4185 | Pass *llvm::createAttributorLegacyPass() { return new AttributorLegacyPass(); } | 
|  | 4186 |  | 
|  | 4187 | char AttributorLegacyPass::ID = 0; | 
| Johannes Doerfert | 2402062 | 2019-08-05 23:30:01 +0000 | [diff] [blame] | 4188 |  | 
|  | 4189 | const char AAReturnedValues::ID = 0; | 
|  | 4190 | const char AANoUnwind::ID = 0; | 
|  | 4191 | const char AANoSync::ID = 0; | 
| Johannes Doerfert | eccdf08 | 2019-08-05 23:35:12 +0000 | [diff] [blame] | 4192 | const char AANoFree::ID = 0; | 
| Johannes Doerfert | 2402062 | 2019-08-05 23:30:01 +0000 | [diff] [blame] | 4193 | const char AANonNull::ID = 0; | 
|  | 4194 | const char AANoRecurse::ID = 0; | 
|  | 4195 | const char AAWillReturn::ID = 0; | 
|  | 4196 | const char AANoAlias::ID = 0; | 
|  | 4197 | const char AANoReturn::ID = 0; | 
|  | 4198 | const char AAIsDead::ID = 0; | 
|  | 4199 | const char AADereferenceable::ID = 0; | 
|  | 4200 | const char AAAlign::ID = 0; | 
| Johannes Doerfert | 7516a5e | 2019-09-03 20:37:24 +0000 | [diff] [blame] | 4201 | const char AANoCapture::ID = 0; | 
| Hideto Ueno | f2b9dc4 | 2019-09-07 07:03:05 +0000 | [diff] [blame] | 4202 | const char AAValueSimplify::ID = 0; | 
| Stefan Stipanovic | 431141c | 2019-09-15 21:47:41 +0000 | [diff] [blame] | 4203 | const char AAHeapToStack::ID = 0; | 
| Johannes Doerfert | 2402062 | 2019-08-05 23:30:01 +0000 | [diff] [blame] | 4204 |  | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 4205 | // Macro magic to create the static generator function for attributes that | 
|  | 4206 | // follow the naming scheme. | 
|  | 4207 |  | 
|  | 4208 | #define SWITCH_PK_INV(CLASS, PK, POS_NAME)                                     \ | 
|  | 4209 | case IRPosition::PK:                                                         \ | 
|  | 4210 | llvm_unreachable("Cannot create " #CLASS " for a " POS_NAME " position!"); | 
|  | 4211 |  | 
|  | 4212 | #define SWITCH_PK_CREATE(CLASS, IRP, PK, SUFFIX)                               \ | 
|  | 4213 | case IRPosition::PK:                                                         \ | 
|  | 4214 | AA = new CLASS##SUFFIX(IRP);                                               \ | 
|  | 4215 | break; | 
|  | 4216 |  | 
|  | 4217 | #define CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS)                 \ | 
|  | 4218 | CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) {      \ | 
|  | 4219 | CLASS *AA = nullptr;                                                       \ | 
|  | 4220 | switch (IRP.getPositionKind()) {                                           \ | 
|  | 4221 | SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid")                             \ | 
|  | 4222 | SWITCH_PK_INV(CLASS, IRP_FLOAT, "floating")                              \ | 
|  | 4223 | SWITCH_PK_INV(CLASS, IRP_ARGUMENT, "argument")                           \ | 
|  | 4224 | SWITCH_PK_INV(CLASS, IRP_RETURNED, "returned")                           \ | 
|  | 4225 | SWITCH_PK_INV(CLASS, IRP_CALL_SITE_RETURNED, "call site returned")       \ | 
|  | 4226 | SWITCH_PK_INV(CLASS, IRP_CALL_SITE_ARGUMENT, "call site argument")       \ | 
|  | 4227 | SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function)                     \ | 
|  | 4228 | SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE, CallSite)                    \ | 
|  | 4229 | }                                                                          \ | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 4230 | return *AA;                                                                \ | 
|  | 4231 | } | 
|  | 4232 |  | 
|  | 4233 | #define CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS)                    \ | 
|  | 4234 | CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) {      \ | 
|  | 4235 | CLASS *AA = nullptr;                                                       \ | 
|  | 4236 | switch (IRP.getPositionKind()) {                                           \ | 
|  | 4237 | SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid")                             \ | 
|  | 4238 | SWITCH_PK_INV(CLASS, IRP_FUNCTION, "function")                           \ | 
|  | 4239 | SWITCH_PK_INV(CLASS, IRP_CALL_SITE, "call site")                         \ | 
|  | 4240 | SWITCH_PK_CREATE(CLASS, IRP, IRP_FLOAT, Floating)                        \ | 
|  | 4241 | SWITCH_PK_CREATE(CLASS, IRP, IRP_ARGUMENT, Argument)                     \ | 
|  | 4242 | SWITCH_PK_CREATE(CLASS, IRP, IRP_RETURNED, Returned)                     \ | 
|  | 4243 | SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_RETURNED, CallSiteReturned)   \ | 
|  | 4244 | SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_ARGUMENT, CallSiteArgument)   \ | 
|  | 4245 | }                                                                          \ | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 4246 | return *AA;                                                                \ | 
|  | 4247 | } | 
|  | 4248 |  | 
| Hideto Ueno | f2b9dc4 | 2019-09-07 07:03:05 +0000 | [diff] [blame] | 4249 | #define CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS)                      \ | 
|  | 4250 | CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) {      \ | 
|  | 4251 | CLASS *AA = nullptr;                                                       \ | 
|  | 4252 | switch (IRP.getPositionKind()) {                                           \ | 
|  | 4253 | SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid")                             \ | 
|  | 4254 | SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function)                     \ | 
|  | 4255 | SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE, CallSite)                    \ | 
|  | 4256 | SWITCH_PK_CREATE(CLASS, IRP, IRP_FLOAT, Floating)                        \ | 
|  | 4257 | SWITCH_PK_CREATE(CLASS, IRP, IRP_ARGUMENT, Argument)                     \ | 
|  | 4258 | SWITCH_PK_CREATE(CLASS, IRP, IRP_RETURNED, Returned)                     \ | 
|  | 4259 | SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_RETURNED, CallSiteReturned)   \ | 
|  | 4260 | SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_ARGUMENT, CallSiteArgument)   \ | 
|  | 4261 | }                                                                          \ | 
|  | 4262 | return *AA;                                                                \ | 
|  | 4263 | } | 
|  | 4264 |  | 
| Stefan Stipanovic | 431141c | 2019-09-15 21:47:41 +0000 | [diff] [blame] | 4265 | #define CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS)            \ | 
|  | 4266 | CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) {      \ | 
|  | 4267 | CLASS *AA = nullptr;                                                       \ | 
|  | 4268 | switch (IRP.getPositionKind()) {                                           \ | 
|  | 4269 | SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid")                             \ | 
|  | 4270 | SWITCH_PK_INV(CLASS, IRP_ARGUMENT, "argument")                           \ | 
|  | 4271 | SWITCH_PK_INV(CLASS, IRP_FLOAT, "floating")                              \ | 
|  | 4272 | SWITCH_PK_INV(CLASS, IRP_RETURNED, "returned")                           \ | 
|  | 4273 | SWITCH_PK_INV(CLASS, IRP_CALL_SITE_RETURNED, "call site returned")       \ | 
|  | 4274 | SWITCH_PK_INV(CLASS, IRP_CALL_SITE_ARGUMENT, "call site argument")       \ | 
|  | 4275 | SWITCH_PK_INV(CLASS, IRP_CALL_SITE, "call site")                         \ | 
|  | 4276 | SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function)                     \ | 
|  | 4277 | }                                                                          \ | 
|  | 4278 | AA->initialize(A);                                                         \ | 
|  | 4279 | return *AA;                                                                \ | 
|  | 4280 | } | 
|  | 4281 |  | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 4282 | CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoUnwind) | 
|  | 4283 | CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoSync) | 
|  | 4284 | CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoFree) | 
|  | 4285 | CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoRecurse) | 
|  | 4286 | CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAWillReturn) | 
|  | 4287 | CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoReturn) | 
|  | 4288 | CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAIsDead) | 
|  | 4289 | CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAReturnedValues) | 
|  | 4290 |  | 
|  | 4291 | CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANonNull) | 
|  | 4292 | CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoAlias) | 
|  | 4293 | CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AADereferenceable) | 
|  | 4294 | CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAAlign) | 
| Johannes Doerfert | 7516a5e | 2019-09-03 20:37:24 +0000 | [diff] [blame] | 4295 | CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoCapture) | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 4296 |  | 
| Hideto Ueno | f2b9dc4 | 2019-09-07 07:03:05 +0000 | [diff] [blame] | 4297 | CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAValueSimplify) | 
|  | 4298 |  | 
| Stefan Stipanovic | 431141c | 2019-09-15 21:47:41 +0000 | [diff] [blame] | 4299 | CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAHeapToStack) | 
|  | 4300 |  | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 4301 | #undef CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION | 
|  | 4302 | #undef CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION | 
| Hideto Ueno | f2b9dc4 | 2019-09-07 07:03:05 +0000 | [diff] [blame] | 4303 | #undef CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION | 
| Johannes Doerfert | 12cbbab | 2019-08-20 06:15:50 +0000 | [diff] [blame] | 4304 | #undef SWITCH_PK_CREATE | 
|  | 4305 | #undef SWITCH_PK_INV | 
|  | 4306 |  | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 4307 | INITIALIZE_PASS_BEGIN(AttributorLegacyPass, "attributor", | 
|  | 4308 | "Deduce and propagate attributes", false, false) | 
| Stefan Stipanovic | 431141c | 2019-09-15 21:47:41 +0000 | [diff] [blame] | 4309 | INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) | 
| Johannes Doerfert | aade782 | 2019-06-05 03:02:24 +0000 | [diff] [blame] | 4310 | INITIALIZE_PASS_END(AttributorLegacyPass, "attributor", | 
|  | 4311 | "Deduce and propagate attributes", false, false) |