File: | polly/lib/CodeGen/IslAst.cpp |
Warning: | line 674, column 3 Potential leak of memory pointed to by field '_M_head_impl' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===- IslAst.cpp - isl code generator interface --------------------------===// | |||
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 | // The isl code generator interface takes a Scop and generates an isl_ast. This | |||
10 | // ist_ast can either be returned directly or it can be pretty printed to | |||
11 | // stdout. | |||
12 | // | |||
13 | // A typical isl_ast output looks like this: | |||
14 | // | |||
15 | // for (c2 = max(0, ceild(n + m, 2); c2 <= min(511, floord(5 * n, 3)); c2++) { | |||
16 | // bb2(c2); | |||
17 | // } | |||
18 | // | |||
19 | // An in-depth discussion of our AST generation approach can be found in: | |||
20 | // | |||
21 | // Polyhedral AST generation is more than scanning polyhedra | |||
22 | // Tobias Grosser, Sven Verdoolaege, Albert Cohen | |||
23 | // ACM Transactions on Programming Languages and Systems (TOPLAS), | |||
24 | // 37(4), July 2015 | |||
25 | // http://www.grosser.es/#pub-polyhedral-AST-generation | |||
26 | // | |||
27 | //===----------------------------------------------------------------------===// | |||
28 | ||||
29 | #include "polly/CodeGen/IslAst.h" | |||
30 | #include "polly/CodeGen/CodeGeneration.h" | |||
31 | #include "polly/DependenceInfo.h" | |||
32 | #include "polly/LinkAllPasses.h" | |||
33 | #include "polly/Options.h" | |||
34 | #include "polly/ScopDetection.h" | |||
35 | #include "polly/ScopInfo.h" | |||
36 | #include "polly/ScopPass.h" | |||
37 | #include "polly/Support/GICHelper.h" | |||
38 | #include "llvm/ADT/Statistic.h" | |||
39 | #include "llvm/IR/Function.h" | |||
40 | #include "llvm/Support/Debug.h" | |||
41 | #include "llvm/Support/raw_ostream.h" | |||
42 | #include "isl/aff.h" | |||
43 | #include "isl/ast.h" | |||
44 | #include "isl/ast_build.h" | |||
45 | #include "isl/id.h" | |||
46 | #include "isl/isl-noexceptions.h" | |||
47 | #include "isl/printer.h" | |||
48 | #include "isl/schedule.h" | |||
49 | #include "isl/set.h" | |||
50 | #include "isl/union_map.h" | |||
51 | #include "isl/val.h" | |||
52 | #include <cassert> | |||
53 | #include <cstdlib> | |||
54 | ||||
55 | #define DEBUG_TYPE"polly-ast" "polly-ast" | |||
56 | ||||
57 | using namespace llvm; | |||
58 | using namespace polly; | |||
59 | ||||
60 | using IslAstUserPayload = IslAstInfo::IslAstUserPayload; | |||
61 | ||||
62 | static cl::opt<bool> | |||
63 | PollyParallel("polly-parallel", | |||
64 | cl::desc("Generate thread parallel code (isl codegen only)"), | |||
65 | cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory)); | |||
66 | ||||
67 | static cl::opt<bool> PrintAccesses("polly-ast-print-accesses", | |||
68 | cl::desc("Print memory access functions"), | |||
69 | cl::init(false), cl::ZeroOrMore, | |||
70 | cl::cat(PollyCategory)); | |||
71 | ||||
72 | static cl::opt<bool> PollyParallelForce( | |||
73 | "polly-parallel-force", | |||
74 | cl::desc( | |||
75 | "Force generation of thread parallel code ignoring any cost model"), | |||
76 | cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory)); | |||
77 | ||||
78 | static cl::opt<bool> UseContext("polly-ast-use-context", | |||
79 | cl::desc("Use context"), cl::Hidden, | |||
80 | cl::init(true), cl::ZeroOrMore, | |||
81 | cl::cat(PollyCategory)); | |||
82 | ||||
83 | static cl::opt<bool> DetectParallel("polly-ast-detect-parallel", | |||
84 | cl::desc("Detect parallelism"), cl::Hidden, | |||
85 | cl::init(false), cl::ZeroOrMore, | |||
86 | cl::cat(PollyCategory)); | |||
87 | ||||
88 | STATISTIC(ScopsProcessed, "Number of SCoPs processed")static llvm::Statistic ScopsProcessed = {"polly-ast", "ScopsProcessed" , "Number of SCoPs processed"}; | |||
89 | STATISTIC(ScopsBeneficial, "Number of beneficial SCoPs")static llvm::Statistic ScopsBeneficial = {"polly-ast", "ScopsBeneficial" , "Number of beneficial SCoPs"}; | |||
90 | STATISTIC(BeneficialAffineLoops, "Number of beneficial affine loops")static llvm::Statistic BeneficialAffineLoops = {"polly-ast", "BeneficialAffineLoops" , "Number of beneficial affine loops"}; | |||
91 | STATISTIC(BeneficialBoxedLoops, "Number of beneficial boxed loops")static llvm::Statistic BeneficialBoxedLoops = {"polly-ast", "BeneficialBoxedLoops" , "Number of beneficial boxed loops"}; | |||
92 | ||||
93 | STATISTIC(NumForLoops, "Number of for-loops")static llvm::Statistic NumForLoops = {"polly-ast", "NumForLoops" , "Number of for-loops"}; | |||
94 | STATISTIC(NumParallel, "Number of parallel for-loops")static llvm::Statistic NumParallel = {"polly-ast", "NumParallel" , "Number of parallel for-loops"}; | |||
95 | STATISTIC(NumInnermostParallel, "Number of innermost parallel for-loops")static llvm::Statistic NumInnermostParallel = {"polly-ast", "NumInnermostParallel" , "Number of innermost parallel for-loops"}; | |||
96 | STATISTIC(NumOutermostParallel, "Number of outermost parallel for-loops")static llvm::Statistic NumOutermostParallel = {"polly-ast", "NumOutermostParallel" , "Number of outermost parallel for-loops"}; | |||
97 | STATISTIC(NumReductionParallel, "Number of reduction-parallel for-loops")static llvm::Statistic NumReductionParallel = {"polly-ast", "NumReductionParallel" , "Number of reduction-parallel for-loops"}; | |||
98 | STATISTIC(NumExecutedInParallel, "Number of for-loops executed in parallel")static llvm::Statistic NumExecutedInParallel = {"polly-ast", "NumExecutedInParallel" , "Number of for-loops executed in parallel"}; | |||
99 | STATISTIC(NumIfConditions, "Number of if-conditions")static llvm::Statistic NumIfConditions = {"polly-ast", "NumIfConditions" , "Number of if-conditions"}; | |||
100 | ||||
101 | namespace polly { | |||
102 | ||||
103 | /// Temporary information used when building the ast. | |||
104 | struct AstBuildUserInfo { | |||
105 | /// Construct and initialize the helper struct for AST creation. | |||
106 | AstBuildUserInfo() = default; | |||
107 | ||||
108 | /// The dependence information used for the parallelism check. | |||
109 | const Dependences *Deps = nullptr; | |||
110 | ||||
111 | /// Flag to indicate that we are inside a parallel for node. | |||
112 | bool InParallelFor = false; | |||
113 | ||||
114 | /// Flag to indicate that we are inside an SIMD node. | |||
115 | bool InSIMD = false; | |||
116 | ||||
117 | /// The last iterator id created for the current SCoP. | |||
118 | isl_id *LastForNodeId = nullptr; | |||
119 | }; | |||
120 | } // namespace polly | |||
121 | ||||
122 | /// Free an IslAstUserPayload object pointed to by @p Ptr. | |||
123 | static void freeIslAstUserPayload(void *Ptr) { | |||
124 | delete ((IslAstInfo::IslAstUserPayload *)Ptr); | |||
125 | } | |||
126 | ||||
127 | /// Print a string @p str in a single line using @p Printer. | |||
128 | static isl_printer *printLine(__isl_take isl_printer *Printer, | |||
129 | const std::string &str, | |||
130 | __isl_keep isl_pw_aff *PWA = nullptr) { | |||
131 | Printer = isl_printer_start_line(Printer); | |||
132 | Printer = isl_printer_print_str(Printer, str.c_str()); | |||
133 | if (PWA) | |||
134 | Printer = isl_printer_print_pw_aff(Printer, PWA); | |||
135 | return isl_printer_end_line(Printer); | |||
136 | } | |||
137 | ||||
138 | /// Return all broken reductions as a string of clauses (OpenMP style). | |||
139 | static const std::string getBrokenReductionsStr(const isl::ast_node &Node) { | |||
140 | IslAstInfo::MemoryAccessSet *BrokenReductions; | |||
141 | std::string str; | |||
142 | ||||
143 | BrokenReductions = IslAstInfo::getBrokenReductions(Node); | |||
144 | if (!BrokenReductions || BrokenReductions->empty()) | |||
145 | return ""; | |||
146 | ||||
147 | // Map each type of reduction to a comma separated list of the base addresses. | |||
148 | std::map<MemoryAccess::ReductionType, std::string> Clauses; | |||
149 | for (MemoryAccess *MA : *BrokenReductions) | |||
150 | if (MA->isWrite()) | |||
151 | Clauses[MA->getReductionType()] += | |||
152 | ", " + MA->getScopArrayInfo()->getName(); | |||
153 | ||||
154 | // Now print the reductions sorted by type. Each type will cause a clause | |||
155 | // like: reduction (+ : sum0, sum1, sum2) | |||
156 | for (const auto &ReductionClause : Clauses) { | |||
157 | str += " reduction ("; | |||
158 | str += MemoryAccess::getReductionOperatorStr(ReductionClause.first); | |||
159 | // Remove the first two symbols (", ") to make the output look pretty. | |||
160 | str += " : " + ReductionClause.second.substr(2) + ")"; | |||
161 | } | |||
162 | ||||
163 | return str; | |||
164 | } | |||
165 | ||||
166 | /// Callback executed for each for node in the ast in order to print it. | |||
167 | static isl_printer *cbPrintFor(__isl_take isl_printer *Printer, | |||
168 | __isl_take isl_ast_print_options *Options, | |||
169 | __isl_keep isl_ast_node *Node, void *) { | |||
170 | isl::pw_aff DD = | |||
171 | IslAstInfo::getMinimalDependenceDistance(isl::manage_copy(Node)); | |||
172 | const std::string BrokenReductionsStr = | |||
173 | getBrokenReductionsStr(isl::manage_copy(Node)); | |||
174 | const std::string KnownParallelStr = "#pragma known-parallel"; | |||
175 | const std::string DepDisPragmaStr = "#pragma minimal dependence distance: "; | |||
176 | const std::string SimdPragmaStr = "#pragma simd"; | |||
177 | const std::string OmpPragmaStr = "#pragma omp parallel for"; | |||
178 | ||||
179 | if (!DD.is_null()) | |||
180 | Printer = printLine(Printer, DepDisPragmaStr, DD.get()); | |||
181 | ||||
182 | if (IslAstInfo::isInnermostParallel(isl::manage_copy(Node))) | |||
183 | Printer = printLine(Printer, SimdPragmaStr + BrokenReductionsStr); | |||
184 | ||||
185 | if (IslAstInfo::isExecutedInParallel(isl::manage_copy(Node))) | |||
186 | Printer = printLine(Printer, OmpPragmaStr); | |||
187 | else if (IslAstInfo::isOutermostParallel(isl::manage_copy(Node))) | |||
188 | Printer = printLine(Printer, KnownParallelStr + BrokenReductionsStr); | |||
189 | ||||
190 | return isl_ast_node_for_print(Node, Printer, Options); | |||
191 | } | |||
192 | ||||
193 | /// Check if the current scheduling dimension is parallel. | |||
194 | /// | |||
195 | /// In case the dimension is parallel we also check if any reduction | |||
196 | /// dependences is broken when we exploit this parallelism. If so, | |||
197 | /// @p IsReductionParallel will be set to true. The reduction dependences we use | |||
198 | /// to check are actually the union of the transitive closure of the initial | |||
199 | /// reduction dependences together with their reversal. Even though these | |||
200 | /// dependences connect all iterations with each other (thus they are cyclic) | |||
201 | /// we can perform the parallelism check as we are only interested in a zero | |||
202 | /// (or non-zero) dependence distance on the dimension in question. | |||
203 | static bool astScheduleDimIsParallel(const isl::ast_build &Build, | |||
204 | const Dependences *D, | |||
205 | IslAstUserPayload *NodeInfo) { | |||
206 | if (!D->hasValidDependences()) | |||
207 | return false; | |||
208 | ||||
209 | isl::union_map Schedule = Build.get_schedule(); | |||
210 | isl::union_map Dep = D->getDependences( | |||
211 | Dependences::TYPE_RAW | Dependences::TYPE_WAW | Dependences::TYPE_WAR); | |||
212 | ||||
213 | if (!D->isParallel(Schedule.get(), Dep.release())) { | |||
214 | isl::union_map DepsAll = | |||
215 | D->getDependences(Dependences::TYPE_RAW | Dependences::TYPE_WAW | | |||
216 | Dependences::TYPE_WAR | Dependences::TYPE_TC_RED); | |||
217 | // TODO: We will need to change isParallel to stop the unwrapping | |||
218 | isl_pw_aff *MinimalDependenceDistanceIsl = nullptr; | |||
219 | D->isParallel(Schedule.get(), DepsAll.release(), | |||
220 | &MinimalDependenceDistanceIsl); | |||
221 | NodeInfo->MinimalDependenceDistance = | |||
222 | isl::manage(MinimalDependenceDistanceIsl); | |||
223 | return false; | |||
224 | } | |||
225 | ||||
226 | isl::union_map RedDeps = D->getDependences(Dependences::TYPE_TC_RED); | |||
227 | if (!D->isParallel(Schedule.get(), RedDeps.release())) | |||
228 | NodeInfo->IsReductionParallel = true; | |||
229 | ||||
230 | if (!NodeInfo->IsReductionParallel) | |||
231 | return true; | |||
232 | ||||
233 | for (const auto &MaRedPair : D->getReductionDependences()) { | |||
234 | if (!MaRedPair.second) | |||
235 | continue; | |||
236 | isl::union_map MaRedDeps = isl::manage_copy(MaRedPair.second); | |||
237 | if (!D->isParallel(Schedule.get(), MaRedDeps.release())) | |||
238 | NodeInfo->BrokenReductions.insert(MaRedPair.first); | |||
239 | } | |||
240 | return true; | |||
241 | } | |||
242 | ||||
243 | // This method is executed before the construction of a for node. It creates | |||
244 | // an isl_id that is used to annotate the subsequently generated ast for nodes. | |||
245 | // | |||
246 | // In this function we also run the following analyses: | |||
247 | // | |||
248 | // - Detection of openmp parallel loops | |||
249 | // | |||
250 | static __isl_give isl_id *astBuildBeforeFor(__isl_keep isl_ast_build *Build, | |||
251 | void *User) { | |||
252 | AstBuildUserInfo *BuildInfo = (AstBuildUserInfo *)User; | |||
253 | IslAstUserPayload *Payload = new IslAstUserPayload(); | |||
254 | isl_id *Id = isl_id_alloc(isl_ast_build_get_ctx(Build), "", Payload); | |||
255 | Id = isl_id_set_free_user(Id, freeIslAstUserPayload); | |||
256 | BuildInfo->LastForNodeId = Id; | |||
257 | ||||
258 | Payload->IsParallel = astScheduleDimIsParallel(isl::manage_copy(Build), | |||
259 | BuildInfo->Deps, Payload); | |||
260 | ||||
261 | // Test for parallelism only if we are not already inside a parallel loop | |||
262 | if (!BuildInfo->InParallelFor && !BuildInfo->InSIMD) | |||
263 | BuildInfo->InParallelFor = Payload->IsOutermostParallel = | |||
264 | Payload->IsParallel; | |||
265 | ||||
266 | return Id; | |||
267 | } | |||
268 | ||||
269 | // This method is executed after the construction of a for node. | |||
270 | // | |||
271 | // It performs the following actions: | |||
272 | // | |||
273 | // - Reset the 'InParallelFor' flag, as soon as we leave a for node, | |||
274 | // that is marked as openmp parallel. | |||
275 | // | |||
276 | static __isl_give isl_ast_node * | |||
277 | astBuildAfterFor(__isl_take isl_ast_node *Node, __isl_keep isl_ast_build *Build, | |||
278 | void *User) { | |||
279 | isl_id *Id = isl_ast_node_get_annotation(Node); | |||
280 | assert(Id && "Post order visit assumes annotated for nodes")(static_cast <bool> (Id && "Post order visit assumes annotated for nodes" ) ? void (0) : __assert_fail ("Id && \"Post order visit assumes annotated for nodes\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/polly/lib/CodeGen/IslAst.cpp" , 280, __extension__ __PRETTY_FUNCTION__)); | |||
281 | IslAstUserPayload *Payload = (IslAstUserPayload *)isl_id_get_user(Id); | |||
282 | assert(Payload && "Post order visit assumes annotated for nodes")(static_cast <bool> (Payload && "Post order visit assumes annotated for nodes" ) ? void (0) : __assert_fail ("Payload && \"Post order visit assumes annotated for nodes\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/polly/lib/CodeGen/IslAst.cpp" , 282, __extension__ __PRETTY_FUNCTION__)); | |||
283 | ||||
284 | AstBuildUserInfo *BuildInfo = (AstBuildUserInfo *)User; | |||
285 | assert(Payload->Build.is_null() && "Build environment already set")(static_cast <bool> (Payload->Build.is_null() && "Build environment already set") ? void (0) : __assert_fail ( "Payload->Build.is_null() && \"Build environment already set\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/polly/lib/CodeGen/IslAst.cpp" , 285, __extension__ __PRETTY_FUNCTION__)); | |||
286 | Payload->Build = isl::manage_copy(Build); | |||
287 | Payload->IsInnermost = (Id == BuildInfo->LastForNodeId); | |||
288 | ||||
289 | Payload->IsInnermostParallel = | |||
290 | Payload->IsInnermost && (BuildInfo->InSIMD || Payload->IsParallel); | |||
291 | if (Payload->IsOutermostParallel) | |||
292 | BuildInfo->InParallelFor = false; | |||
293 | ||||
294 | isl_id_free(Id); | |||
295 | return Node; | |||
296 | } | |||
297 | ||||
298 | static isl_stat astBuildBeforeMark(__isl_keep isl_id *MarkId, | |||
299 | __isl_keep isl_ast_build *Build, | |||
300 | void *User) { | |||
301 | if (!MarkId) | |||
302 | return isl_stat_error; | |||
303 | ||||
304 | AstBuildUserInfo *BuildInfo = (AstBuildUserInfo *)User; | |||
305 | if (strcmp(isl_id_get_name(MarkId), "SIMD") == 0) | |||
306 | BuildInfo->InSIMD = true; | |||
307 | ||||
308 | return isl_stat_ok; | |||
309 | } | |||
310 | ||||
311 | static __isl_give isl_ast_node * | |||
312 | astBuildAfterMark(__isl_take isl_ast_node *Node, | |||
313 | __isl_keep isl_ast_build *Build, void *User) { | |||
314 | assert(isl_ast_node_get_type(Node) == isl_ast_node_mark)(static_cast <bool> (isl_ast_node_get_type(Node) == isl_ast_node_mark ) ? void (0) : __assert_fail ("isl_ast_node_get_type(Node) == isl_ast_node_mark" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/polly/lib/CodeGen/IslAst.cpp" , 314, __extension__ __PRETTY_FUNCTION__)); | |||
315 | AstBuildUserInfo *BuildInfo = (AstBuildUserInfo *)User; | |||
316 | auto *Id = isl_ast_node_mark_get_id(Node); | |||
317 | if (strcmp(isl_id_get_name(Id), "SIMD") == 0) | |||
318 | BuildInfo->InSIMD = false; | |||
319 | isl_id_free(Id); | |||
320 | return Node; | |||
321 | } | |||
322 | ||||
323 | static __isl_give isl_ast_node *AtEachDomain(__isl_take isl_ast_node *Node, | |||
324 | __isl_keep isl_ast_build *Build, | |||
325 | void *User) { | |||
326 | assert(!isl_ast_node_get_annotation(Node) && "Node already annotated")(static_cast <bool> (!isl_ast_node_get_annotation(Node) && "Node already annotated") ? void (0) : __assert_fail ("!isl_ast_node_get_annotation(Node) && \"Node already annotated\"" , "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/polly/lib/CodeGen/IslAst.cpp" , 326, __extension__ __PRETTY_FUNCTION__)); | |||
327 | ||||
328 | IslAstUserPayload *Payload = new IslAstUserPayload(); | |||
329 | isl_id *Id = isl_id_alloc(isl_ast_build_get_ctx(Build), "", Payload); | |||
330 | Id = isl_id_set_free_user(Id, freeIslAstUserPayload); | |||
331 | ||||
332 | Payload->Build = isl::manage_copy(Build); | |||
333 | ||||
334 | return isl_ast_node_set_annotation(Node, Id); | |||
335 | } | |||
336 | ||||
337 | // Build alias check condition given a pair of minimal/maximal access. | |||
338 | static isl::ast_expr buildCondition(Scop &S, isl::ast_build Build, | |||
339 | const Scop::MinMaxAccessTy *It0, | |||
340 | const Scop::MinMaxAccessTy *It1) { | |||
341 | ||||
342 | isl::pw_multi_aff AFirst = It0->first; | |||
343 | isl::pw_multi_aff ASecond = It0->second; | |||
344 | isl::pw_multi_aff BFirst = It1->first; | |||
345 | isl::pw_multi_aff BSecond = It1->second; | |||
346 | ||||
347 | isl::id Left = AFirst.get_tuple_id(isl::dim::set); | |||
348 | isl::id Right = BFirst.get_tuple_id(isl::dim::set); | |||
349 | ||||
350 | isl::ast_expr True = | |||
351 | isl::ast_expr::from_val(isl::val::int_from_ui(Build.ctx(), 1)); | |||
352 | isl::ast_expr False = | |||
353 | isl::ast_expr::from_val(isl::val::int_from_ui(Build.ctx(), 0)); | |||
354 | ||||
355 | const ScopArrayInfo *BaseLeft = | |||
356 | ScopArrayInfo::getFromId(Left)->getBasePtrOriginSAI(); | |||
357 | const ScopArrayInfo *BaseRight = | |||
358 | ScopArrayInfo::getFromId(Right)->getBasePtrOriginSAI(); | |||
359 | if (BaseLeft && BaseLeft == BaseRight) | |||
360 | return True; | |||
361 | ||||
362 | isl::set Params = S.getContext(); | |||
363 | ||||
364 | isl::ast_expr NonAliasGroup, MinExpr, MaxExpr; | |||
365 | ||||
366 | // In the following, we first check if any accesses will be empty under | |||
367 | // the execution context of the scop and do not code generate them if this | |||
368 | // is the case as isl will fail to derive valid AST expressions for such | |||
369 | // accesses. | |||
370 | ||||
371 | if (!AFirst.intersect_params(Params).domain().is_empty() && | |||
372 | !BSecond.intersect_params(Params).domain().is_empty()) { | |||
373 | MinExpr = Build.access_from(AFirst).address_of(); | |||
374 | MaxExpr = Build.access_from(BSecond).address_of(); | |||
375 | NonAliasGroup = MaxExpr.le(MinExpr); | |||
376 | } | |||
377 | ||||
378 | if (!BFirst.intersect_params(Params).domain().is_empty() && | |||
379 | !ASecond.intersect_params(Params).domain().is_empty()) { | |||
380 | MinExpr = Build.access_from(BFirst).address_of(); | |||
381 | MaxExpr = Build.access_from(ASecond).address_of(); | |||
382 | ||||
383 | isl::ast_expr Result = MaxExpr.le(MinExpr); | |||
384 | if (!NonAliasGroup.is_null()) | |||
385 | NonAliasGroup = isl::manage( | |||
386 | isl_ast_expr_or(NonAliasGroup.release(), Result.release())); | |||
387 | else | |||
388 | NonAliasGroup = Result; | |||
389 | } | |||
390 | ||||
391 | if (NonAliasGroup.is_null()) | |||
392 | NonAliasGroup = True; | |||
393 | ||||
394 | return NonAliasGroup; | |||
395 | } | |||
396 | ||||
397 | isl::ast_expr IslAst::buildRunCondition(Scop &S, const isl::ast_build &Build) { | |||
398 | isl::ast_expr RunCondition; | |||
399 | ||||
400 | // The conditions that need to be checked at run-time for this scop are | |||
401 | // available as an isl_set in the runtime check context from which we can | |||
402 | // directly derive a run-time condition. | |||
403 | auto PosCond = Build.expr_from(S.getAssumedContext()); | |||
404 | if (S.hasTrivialInvalidContext()) { | |||
405 | RunCondition = std::move(PosCond); | |||
406 | } else { | |||
407 | auto ZeroV = isl::val::zero(Build.ctx()); | |||
408 | auto NegCond = Build.expr_from(S.getInvalidContext()); | |||
409 | auto NotNegCond = | |||
410 | isl::ast_expr::from_val(std::move(ZeroV)).eq(std::move(NegCond)); | |||
411 | RunCondition = | |||
412 | isl::manage(isl_ast_expr_and(PosCond.release(), NotNegCond.release())); | |||
413 | } | |||
414 | ||||
415 | // Create the alias checks from the minimal/maximal accesses in each alias | |||
416 | // group which consists of read only and non read only (read write) accesses. | |||
417 | // This operation is by construction quadratic in the read-write pointers and | |||
418 | // linear in the read only pointers in each alias group. | |||
419 | for (const Scop::MinMaxVectorPairTy &MinMaxAccessPair : S.getAliasGroups()) { | |||
420 | auto &MinMaxReadWrite = MinMaxAccessPair.first; | |||
421 | auto &MinMaxReadOnly = MinMaxAccessPair.second; | |||
422 | auto RWAccEnd = MinMaxReadWrite.end(); | |||
423 | ||||
424 | for (auto RWAccIt0 = MinMaxReadWrite.begin(); RWAccIt0 != RWAccEnd; | |||
425 | ++RWAccIt0) { | |||
426 | for (auto RWAccIt1 = RWAccIt0 + 1; RWAccIt1 != RWAccEnd; ++RWAccIt1) | |||
427 | RunCondition = isl::manage(isl_ast_expr_and( | |||
428 | RunCondition.release(), | |||
429 | buildCondition(S, Build, RWAccIt0, RWAccIt1).release())); | |||
430 | for (const Scop::MinMaxAccessTy &ROAccIt : MinMaxReadOnly) | |||
431 | RunCondition = isl::manage(isl_ast_expr_and( | |||
432 | RunCondition.release(), | |||
433 | buildCondition(S, Build, RWAccIt0, &ROAccIt).release())); | |||
434 | } | |||
435 | } | |||
436 | ||||
437 | return RunCondition; | |||
438 | } | |||
439 | ||||
440 | /// Simple cost analysis for a given SCoP. | |||
441 | /// | |||
442 | /// TODO: Improve this analysis and extract it to make it usable in other | |||
443 | /// places too. | |||
444 | /// In order to improve the cost model we could either keep track of | |||
445 | /// performed optimizations (e.g., tiling) or compute properties on the | |||
446 | /// original as well as optimized SCoP (e.g., #stride-one-accesses). | |||
447 | static bool benefitsFromPolly(Scop &Scop, bool PerformParallelTest) { | |||
448 | if (PollyProcessUnprofitable) | |||
449 | return true; | |||
450 | ||||
451 | // Check if nothing interesting happened. | |||
452 | if (!PerformParallelTest && !Scop.isOptimized() && | |||
453 | Scop.getAliasGroups().empty()) | |||
454 | return false; | |||
455 | ||||
456 | // The default assumption is that Polly improves the code. | |||
457 | return true; | |||
458 | } | |||
459 | ||||
460 | /// Collect statistics for the syntax tree rooted at @p Ast. | |||
461 | static void walkAstForStatistics(const isl::ast_node &Ast) { | |||
462 | assert(!Ast.is_null())(static_cast <bool> (!Ast.is_null()) ? void (0) : __assert_fail ("!Ast.is_null()", "/build/llvm-toolchain-snapshot-14~++20210828111110+16086d47c0d0/polly/lib/CodeGen/IslAst.cpp" , 462, __extension__ __PRETTY_FUNCTION__)); | |||
463 | isl_ast_node_foreach_descendant_top_down( | |||
464 | Ast.get(), | |||
465 | [](__isl_keep isl_ast_node *Node, void *User) -> isl_bool { | |||
466 | switch (isl_ast_node_get_type(Node)) { | |||
467 | case isl_ast_node_for: | |||
468 | NumForLoops++; | |||
469 | if (IslAstInfo::isParallel(isl::manage_copy(Node))) | |||
470 | NumParallel++; | |||
471 | if (IslAstInfo::isInnermostParallel(isl::manage_copy(Node))) | |||
472 | NumInnermostParallel++; | |||
473 | if (IslAstInfo::isOutermostParallel(isl::manage_copy(Node))) | |||
474 | NumOutermostParallel++; | |||
475 | if (IslAstInfo::isReductionParallel(isl::manage_copy(Node))) | |||
476 | NumReductionParallel++; | |||
477 | if (IslAstInfo::isExecutedInParallel(isl::manage_copy(Node))) | |||
478 | NumExecutedInParallel++; | |||
479 | break; | |||
480 | ||||
481 | case isl_ast_node_if: | |||
482 | NumIfConditions++; | |||
483 | break; | |||
484 | ||||
485 | default: | |||
486 | break; | |||
487 | } | |||
488 | ||||
489 | // Continue traversing subtrees. | |||
490 | return isl_bool_true; | |||
491 | }, | |||
492 | nullptr); | |||
493 | } | |||
494 | ||||
495 | IslAst::IslAst(Scop &Scop) : S(Scop), Ctx(Scop.getSharedIslCtx()) {} | |||
496 | ||||
497 | IslAst::IslAst(IslAst &&O) | |||
498 | : S(O.S), Ctx(O.Ctx), RunCondition(std::move(O.RunCondition)), | |||
499 | Root(std::move(O.Root)) {} | |||
500 | ||||
501 | void IslAst::init(const Dependences &D) { | |||
502 | bool PerformParallelTest = PollyParallel || DetectParallel || | |||
503 | PollyVectorizerChoice != VECTORIZER_NONE; | |||
504 | auto ScheduleTree = S.getScheduleTree(); | |||
505 | ||||
506 | // Skip AST and code generation if there was no benefit achieved. | |||
507 | if (!benefitsFromPolly(S, PerformParallelTest)) | |||
508 | return; | |||
509 | ||||
510 | auto ScopStats = S.getStatistics(); | |||
511 | ScopsBeneficial++; | |||
512 | BeneficialAffineLoops += ScopStats.NumAffineLoops; | |||
513 | BeneficialBoxedLoops += ScopStats.NumBoxedLoops; | |||
514 | ||||
515 | auto Ctx = S.getIslCtx(); | |||
516 | isl_options_set_ast_build_atomic_upper_bound(Ctx.get(), true); | |||
517 | isl_options_set_ast_build_detect_min_max(Ctx.get(), true); | |||
518 | isl_ast_build *Build; | |||
519 | AstBuildUserInfo BuildInfo; | |||
520 | ||||
521 | if (UseContext) | |||
522 | Build = isl_ast_build_from_context(S.getContext().release()); | |||
523 | else | |||
524 | Build = isl_ast_build_from_context( | |||
525 | isl_set_universe(S.getParamSpace().release())); | |||
526 | ||||
527 | Build = isl_ast_build_set_at_each_domain(Build, AtEachDomain, nullptr); | |||
528 | ||||
529 | if (PerformParallelTest) { | |||
530 | BuildInfo.Deps = &D; | |||
531 | BuildInfo.InParallelFor = false; | |||
532 | BuildInfo.InSIMD = false; | |||
533 | ||||
534 | Build = isl_ast_build_set_before_each_for(Build, &astBuildBeforeFor, | |||
535 | &BuildInfo); | |||
536 | Build = | |||
537 | isl_ast_build_set_after_each_for(Build, &astBuildAfterFor, &BuildInfo); | |||
538 | ||||
539 | Build = isl_ast_build_set_before_each_mark(Build, &astBuildBeforeMark, | |||
540 | &BuildInfo); | |||
541 | ||||
542 | Build = isl_ast_build_set_after_each_mark(Build, &astBuildAfterMark, | |||
543 | &BuildInfo); | |||
544 | } | |||
545 | ||||
546 | RunCondition = buildRunCondition(S, isl::manage_copy(Build)); | |||
547 | ||||
548 | Root = isl::manage( | |||
549 | isl_ast_build_node_from_schedule(Build, S.getScheduleTree().release())); | |||
550 | walkAstForStatistics(Root); | |||
551 | ||||
552 | isl_ast_build_free(Build); | |||
553 | } | |||
554 | ||||
555 | IslAst IslAst::create(Scop &Scop, const Dependences &D) { | |||
556 | IslAst Ast{Scop}; | |||
557 | Ast.init(D); | |||
558 | return Ast; | |||
559 | } | |||
560 | ||||
561 | isl::ast_node IslAst::getAst() { return Root; } | |||
562 | isl::ast_expr IslAst::getRunCondition() { return RunCondition; } | |||
563 | ||||
564 | isl::ast_node IslAstInfo::getAst() { return Ast.getAst(); } | |||
565 | isl::ast_expr IslAstInfo::getRunCondition() { return Ast.getRunCondition(); } | |||
566 | ||||
567 | IslAstUserPayload *IslAstInfo::getNodePayload(const isl::ast_node &Node) { | |||
568 | isl::id Id = Node.get_annotation(); | |||
569 | if (Id.is_null()) | |||
570 | return nullptr; | |||
571 | IslAstUserPayload *Payload = (IslAstUserPayload *)Id.get_user(); | |||
572 | return Payload; | |||
573 | } | |||
574 | ||||
575 | bool IslAstInfo::isInnermost(const isl::ast_node &Node) { | |||
576 | IslAstUserPayload *Payload = getNodePayload(Node); | |||
577 | return Payload && Payload->IsInnermost; | |||
578 | } | |||
579 | ||||
580 | bool IslAstInfo::isParallel(const isl::ast_node &Node) { | |||
581 | return IslAstInfo::isInnermostParallel(Node) || | |||
582 | IslAstInfo::isOutermostParallel(Node); | |||
583 | } | |||
584 | ||||
585 | bool IslAstInfo::isInnermostParallel(const isl::ast_node &Node) { | |||
586 | IslAstUserPayload *Payload = getNodePayload(Node); | |||
587 | return Payload && Payload->IsInnermostParallel; | |||
588 | } | |||
589 | ||||
590 | bool IslAstInfo::isOutermostParallel(const isl::ast_node &Node) { | |||
591 | IslAstUserPayload *Payload = getNodePayload(Node); | |||
592 | return Payload && Payload->IsOutermostParallel; | |||
593 | } | |||
594 | ||||
595 | bool IslAstInfo::isReductionParallel(const isl::ast_node &Node) { | |||
596 | IslAstUserPayload *Payload = getNodePayload(Node); | |||
597 | return Payload && Payload->IsReductionParallel; | |||
598 | } | |||
599 | ||||
600 | bool IslAstInfo::isExecutedInParallel(const isl::ast_node &Node) { | |||
601 | if (!PollyParallel) | |||
602 | return false; | |||
603 | ||||
604 | // Do not parallelize innermost loops. | |||
605 | // | |||
606 | // Parallelizing innermost loops is often not profitable, especially if | |||
607 | // they have a low number of iterations. | |||
608 | // | |||
609 | // TODO: Decide this based on the number of loop iterations that will be | |||
610 | // executed. This can possibly require run-time checks, which again | |||
611 | // raises the question of both run-time check overhead and code size | |||
612 | // costs. | |||
613 | if (!PollyParallelForce && isInnermost(Node)) | |||
614 | return false; | |||
615 | ||||
616 | return isOutermostParallel(Node) && !isReductionParallel(Node); | |||
617 | } | |||
618 | ||||
619 | isl::union_map IslAstInfo::getSchedule(const isl::ast_node &Node) { | |||
620 | IslAstUserPayload *Payload = getNodePayload(Node); | |||
621 | return Payload ? Payload->Build.get_schedule() : isl::union_map(); | |||
622 | } | |||
623 | ||||
624 | isl::pw_aff | |||
625 | IslAstInfo::getMinimalDependenceDistance(const isl::ast_node &Node) { | |||
626 | IslAstUserPayload *Payload = getNodePayload(Node); | |||
627 | return Payload ? Payload->MinimalDependenceDistance : isl::pw_aff(); | |||
628 | } | |||
629 | ||||
630 | IslAstInfo::MemoryAccessSet * | |||
631 | IslAstInfo::getBrokenReductions(const isl::ast_node &Node) { | |||
632 | IslAstUserPayload *Payload = getNodePayload(Node); | |||
633 | return Payload ? &Payload->BrokenReductions : nullptr; | |||
634 | } | |||
635 | ||||
636 | isl::ast_build IslAstInfo::getBuild(const isl::ast_node &Node) { | |||
637 | IslAstUserPayload *Payload = getNodePayload(Node); | |||
638 | return Payload ? Payload->Build : isl::ast_build(); | |||
639 | } | |||
640 | ||||
641 | static std::unique_ptr<IslAstInfo> runIslAst( | |||
642 | Scop &Scop, | |||
643 | function_ref<const Dependences &(Dependences::AnalysisLevel)> GetDeps) { | |||
644 | // Skip SCoPs in case they're already handled by PPCGCodeGeneration. | |||
645 | if (Scop.isToBeSkipped()) | |||
646 | return {}; | |||
647 | ||||
648 | ScopsProcessed++; | |||
649 | ||||
650 | const Dependences &D = GetDeps(Dependences::AL_Statement); | |||
651 | ||||
652 | if (D.getSharedIslCtx() != Scop.getSharedIslCtx()) { | |||
653 | LLVM_DEBUG(do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("polly-ast")) { dbgs() << "Got dependence analysis for different SCoP/isl_ctx\n" ; } } while (false) | |||
654 | dbgs() << "Got dependence analysis for different SCoP/isl_ctx\n")do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("polly-ast")) { dbgs() << "Got dependence analysis for different SCoP/isl_ctx\n" ; } } while (false); | |||
655 | return {}; | |||
656 | } | |||
657 | ||||
658 | std::unique_ptr<IslAstInfo> Ast = std::make_unique<IslAstInfo>(Scop, D); | |||
659 | ||||
660 | LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("polly-ast")) { { if (Ast) Ast->print(dbgs()); }; } } while (false) | |||
661 | if (Ast)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("polly-ast")) { { if (Ast) Ast->print(dbgs()); }; } } while (false) | |||
662 | Ast->print(dbgs());do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("polly-ast")) { { if (Ast) Ast->print(dbgs()); }; } } while (false) | |||
663 | })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("polly-ast")) { { if (Ast) Ast->print(dbgs()); }; } } while (false); | |||
664 | ||||
665 | return Ast; | |||
666 | } | |||
667 | ||||
668 | IslAstInfo IslAstAnalysis::run(Scop &S, ScopAnalysisManager &SAM, | |||
669 | ScopStandardAnalysisResults &SAR) { | |||
670 | auto GetDeps = [&](Dependences::AnalysisLevel Lvl) -> const Dependences & { | |||
671 | return SAM.getResult<DependenceAnalysis>(S, SAR).getDependences(Lvl); | |||
672 | }; | |||
673 | ||||
674 | return std::move(*runIslAst(S, GetDeps).release()); | |||
| ||||
| ||||
675 | } | |||
676 | ||||
677 | static __isl_give isl_printer *cbPrintUser(__isl_take isl_printer *P, | |||
678 | __isl_take isl_ast_print_options *O, | |||
679 | __isl_keep isl_ast_node *Node, | |||
680 | void *User) { | |||
681 | isl::ast_node_user AstNode = isl::manage_copy(Node).as<isl::ast_node_user>(); | |||
682 | isl::ast_expr NodeExpr = AstNode.expr(); | |||
683 | isl::ast_expr CallExpr = NodeExpr.get_op_arg(0); | |||
684 | isl::id CallExprId = CallExpr.get_id(); | |||
685 | ScopStmt *AccessStmt = (ScopStmt *)CallExprId.get_user(); | |||
686 | ||||
687 | P = isl_printer_start_line(P); | |||
688 | P = isl_printer_print_str(P, AccessStmt->getBaseName()); | |||
689 | P = isl_printer_print_str(P, "("); | |||
690 | P = isl_printer_end_line(P); | |||
691 | P = isl_printer_indent(P, 2); | |||
692 | ||||
693 | for (MemoryAccess *MemAcc : *AccessStmt) { | |||
694 | P = isl_printer_start_line(P); | |||
695 | ||||
696 | if (MemAcc->isRead()) | |||
697 | P = isl_printer_print_str(P, "/* read */ &"); | |||
698 | else | |||
699 | P = isl_printer_print_str(P, "/* write */ "); | |||
700 | ||||
701 | isl::ast_build Build = IslAstInfo::getBuild(isl::manage_copy(Node)); | |||
702 | if (MemAcc->isAffine()) { | |||
703 | isl_pw_multi_aff *PwmaPtr = | |||
704 | MemAcc->applyScheduleToAccessRelation(Build.get_schedule()).release(); | |||
705 | isl::pw_multi_aff Pwma = isl::manage(PwmaPtr); | |||
706 | isl::ast_expr AccessExpr = Build.access_from(Pwma); | |||
707 | P = isl_printer_print_ast_expr(P, AccessExpr.get()); | |||
708 | } else { | |||
709 | P = isl_printer_print_str( | |||
710 | P, MemAcc->getLatestScopArrayInfo()->getName().c_str()); | |||
711 | P = isl_printer_print_str(P, "[*]"); | |||
712 | } | |||
713 | P = isl_printer_end_line(P); | |||
714 | } | |||
715 | ||||
716 | P = isl_printer_indent(P, -2); | |||
717 | P = isl_printer_start_line(P); | |||
718 | P = isl_printer_print_str(P, ");"); | |||
719 | P = isl_printer_end_line(P); | |||
720 | ||||
721 | isl_ast_print_options_free(O); | |||
722 | return P; | |||
723 | } | |||
724 | ||||
725 | void IslAstInfo::print(raw_ostream &OS) { | |||
726 | isl_ast_print_options *Options; | |||
727 | isl::ast_node RootNode = Ast.getAst(); | |||
728 | Function &F = S.getFunction(); | |||
729 | ||||
730 | OS << ":: isl ast :: " << F.getName() << " :: " << S.getNameStr() << "\n"; | |||
731 | ||||
732 | if (RootNode.is_null()) { | |||
733 | OS << ":: isl ast generation and code generation was skipped!\n\n"; | |||
734 | OS << ":: This is either because no useful optimizations could be applied " | |||
735 | "(use -polly-process-unprofitable to enforce code generation) or " | |||
736 | "because earlier passes such as dependence analysis timed out (use " | |||
737 | "-polly-dependences-computeout=0 to set dependence analysis timeout " | |||
738 | "to infinity)\n\n"; | |||
739 | return; | |||
740 | } | |||
741 | ||||
742 | isl::ast_expr RunCondition = Ast.getRunCondition(); | |||
743 | char *RtCStr, *AstStr; | |||
744 | ||||
745 | Options = isl_ast_print_options_alloc(S.getIslCtx().get()); | |||
746 | ||||
747 | if (PrintAccesses) | |||
748 | Options = | |||
749 | isl_ast_print_options_set_print_user(Options, cbPrintUser, nullptr); | |||
750 | Options = isl_ast_print_options_set_print_for(Options, cbPrintFor, nullptr); | |||
751 | ||||
752 | isl_printer *P = isl_printer_to_str(S.getIslCtx().get()); | |||
753 | P = isl_printer_set_output_format(P, ISL_FORMAT_C4); | |||
754 | P = isl_printer_print_ast_expr(P, RunCondition.get()); | |||
755 | RtCStr = isl_printer_get_str(P); | |||
756 | P = isl_printer_flush(P); | |||
757 | P = isl_printer_indent(P, 4); | |||
758 | P = isl_ast_node_print(RootNode.get(), P, Options); | |||
759 | AstStr = isl_printer_get_str(P); | |||
760 | ||||
761 | LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("polly-ast")) { { dbgs() << S.getContextStr() << "\n"; dbgs() << stringFromIslObj(S.getScheduleTree(), "null" ); }; } } while (false) | |||
762 | dbgs() << S.getContextStr() << "\n";do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("polly-ast")) { { dbgs() << S.getContextStr() << "\n"; dbgs() << stringFromIslObj(S.getScheduleTree(), "null" ); }; } } while (false) | |||
763 | dbgs() << stringFromIslObj(S.getScheduleTree(), "null");do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("polly-ast")) { { dbgs() << S.getContextStr() << "\n"; dbgs() << stringFromIslObj(S.getScheduleTree(), "null" ); }; } } while (false) | |||
764 | })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType ("polly-ast")) { { dbgs() << S.getContextStr() << "\n"; dbgs() << stringFromIslObj(S.getScheduleTree(), "null" ); }; } } while (false); | |||
765 | OS << "\nif (" << RtCStr << ")\n\n"; | |||
766 | OS << AstStr << "\n"; | |||
767 | OS << "else\n"; | |||
768 | OS << " { /* original code */ }\n\n"; | |||
769 | ||||
770 | free(RtCStr); | |||
771 | free(AstStr); | |||
772 | ||||
773 | isl_printer_free(P); | |||
774 | } | |||
775 | ||||
776 | AnalysisKey IslAstAnalysis::Key; | |||
777 | PreservedAnalyses IslAstPrinterPass::run(Scop &S, ScopAnalysisManager &SAM, | |||
778 | ScopStandardAnalysisResults &SAR, | |||
779 | SPMUpdater &U) { | |||
780 | auto &Ast = SAM.getResult<IslAstAnalysis>(S, SAR); | |||
781 | Ast.print(OS); | |||
782 | return PreservedAnalyses::all(); | |||
783 | } | |||
784 | ||||
785 | void IslAstInfoWrapperPass::releaseMemory() { Ast.reset(); } | |||
786 | ||||
787 | bool IslAstInfoWrapperPass::runOnScop(Scop &Scop) { | |||
788 | auto GetDeps = [this](Dependences::AnalysisLevel Lvl) -> const Dependences & { | |||
789 | return getAnalysis<DependenceInfo>().getDependences(Lvl); | |||
790 | }; | |||
791 | ||||
792 | Ast = runIslAst(Scop, GetDeps); | |||
793 | ||||
794 | return false; | |||
795 | } | |||
796 | ||||
797 | void IslAstInfoWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const { | |||
798 | // Get the Common analysis usage of ScopPasses. | |||
799 | ScopPass::getAnalysisUsage(AU); | |||
800 | AU.addRequiredTransitive<ScopInfoRegionPass>(); | |||
801 | AU.addRequired<DependenceInfo>(); | |||
802 | ||||
803 | AU.addPreserved<DependenceInfo>(); | |||
804 | } | |||
805 | ||||
806 | void IslAstInfoWrapperPass::printScop(raw_ostream &OS, Scop &S) const { | |||
807 | OS << "Printing analysis 'Polly - Generate an AST of the SCoP (isl)'" | |||
808 | << S.getName() << "' in function '" << S.getFunction().getName() << "':\n"; | |||
809 | if (Ast) | |||
810 | Ast->print(OS); | |||
811 | } | |||
812 | ||||
813 | char IslAstInfoWrapperPass::ID = 0; | |||
814 | ||||
815 | Pass *polly::createIslAstInfoWrapperPassPass() { | |||
816 | return new IslAstInfoWrapperPass(); | |||
817 | } | |||
818 | ||||
819 | INITIALIZE_PASS_BEGIN(IslAstInfoWrapperPass, "polly-ast",static void *initializeIslAstInfoWrapperPassPassOnce(PassRegistry &Registry) { | |||
820 | "Polly - Generate an AST of the SCoP (isl)", false,static void *initializeIslAstInfoWrapperPassPassOnce(PassRegistry &Registry) { | |||
821 | false)static void *initializeIslAstInfoWrapperPassPassOnce(PassRegistry &Registry) {; | |||
822 | INITIALIZE_PASS_DEPENDENCY(ScopInfoRegionPass)initializeScopInfoRegionPassPass(Registry);; | |||
823 | INITIALIZE_PASS_DEPENDENCY(DependenceInfo)initializeDependenceInfoPass(Registry);; | |||
824 | INITIALIZE_PASS_END(IslAstInfoWrapperPass, "polly-ast",PassInfo *PI = new PassInfo( "Polly - Generate an AST from the SCoP (isl)" , "polly-ast", &IslAstInfoWrapperPass::ID, PassInfo::NormalCtor_t (callDefaultCtor<IslAstInfoWrapperPass>), false, false) ; Registry.registerPass(*PI, true); return PI; } static llvm:: once_flag InitializeIslAstInfoWrapperPassPassFlag; void llvm:: initializeIslAstInfoWrapperPassPass(PassRegistry &Registry ) { llvm::call_once(InitializeIslAstInfoWrapperPassPassFlag, initializeIslAstInfoWrapperPassPassOnce , std::ref(Registry)); } | |||
825 | "Polly - Generate an AST from the SCoP (isl)", false, false)PassInfo *PI = new PassInfo( "Polly - Generate an AST from the SCoP (isl)" , "polly-ast", &IslAstInfoWrapperPass::ID, PassInfo::NormalCtor_t (callDefaultCtor<IslAstInfoWrapperPass>), false, false) ; Registry.registerPass(*PI, true); return PI; } static llvm:: once_flag InitializeIslAstInfoWrapperPassPassFlag; void llvm:: initializeIslAstInfoWrapperPassPass(PassRegistry &Registry ) { llvm::call_once(InitializeIslAstInfoWrapperPassPassFlag, initializeIslAstInfoWrapperPassPassOnce , std::ref(Registry)); } |
1 | // unique_ptr implementation -*- C++ -*- |
2 | |
3 | // Copyright (C) 2008-2020 Free Software Foundation, Inc. |
4 | // |
5 | // This file is part of the GNU ISO C++ Library. This library is free |
6 | // software; you can redistribute it and/or modify it under the |
7 | // terms of the GNU General Public License as published by the |
8 | // Free Software Foundation; either version 3, or (at your option) |
9 | // any later version. |
10 | |
11 | // This library is distributed in the hope that it will be useful, |
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | // GNU General Public License for more details. |
15 | |
16 | // Under Section 7 of GPL version 3, you are granted additional |
17 | // permissions described in the GCC Runtime Library Exception, version |
18 | // 3.1, as published by the Free Software Foundation. |
19 | |
20 | // You should have received a copy of the GNU General Public License and |
21 | // a copy of the GCC Runtime Library Exception along with this program; |
22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
23 | // <http://www.gnu.org/licenses/>. |
24 | |
25 | /** @file bits/unique_ptr.h |
26 | * This is an internal header file, included by other library headers. |
27 | * Do not attempt to use it directly. @headername{memory} |
28 | */ |
29 | |
30 | #ifndef _UNIQUE_PTR_H1 |
31 | #define _UNIQUE_PTR_H1 1 |
32 | |
33 | #include <bits/c++config.h> |
34 | #include <debug/assertions.h> |
35 | #include <type_traits> |
36 | #include <utility> |
37 | #include <tuple> |
38 | #include <bits/stl_function.h> |
39 | #include <bits/functional_hash.h> |
40 | #if __cplusplus201402L > 201703L |
41 | # include <compare> |
42 | # include <ostream> |
43 | #endif |
44 | |
45 | namespace std _GLIBCXX_VISIBILITY(default)__attribute__ ((__visibility__ ("default"))) |
46 | { |
47 | _GLIBCXX_BEGIN_NAMESPACE_VERSION |
48 | |
49 | /** |
50 | * @addtogroup pointer_abstractions |
51 | * @{ |
52 | */ |
53 | |
54 | #if _GLIBCXX_USE_DEPRECATED1 |
55 | #pragma GCC diagnostic push |
56 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" |
57 | template<typename> class auto_ptr; |
58 | #pragma GCC diagnostic pop |
59 | #endif |
60 | |
61 | /// Primary template of default_delete, used by unique_ptr for single objects |
62 | template<typename _Tp> |
63 | struct default_delete |
64 | { |
65 | /// Default constructor |
66 | constexpr default_delete() noexcept = default; |
67 | |
68 | /** @brief Converting constructor. |
69 | * |
70 | * Allows conversion from a deleter for objects of another type, `_Up`, |
71 | * only if `_Up*` is convertible to `_Tp*`. |
72 | */ |
73 | template<typename _Up, |
74 | typename = _Require<is_convertible<_Up*, _Tp*>>> |
75 | default_delete(const default_delete<_Up>&) noexcept { } |
76 | |
77 | /// Calls `delete __ptr` |
78 | void |
79 | operator()(_Tp* __ptr) const |
80 | { |
81 | static_assert(!is_void<_Tp>::value, |
82 | "can't delete pointer to incomplete type"); |
83 | static_assert(sizeof(_Tp)>0, |
84 | "can't delete pointer to incomplete type"); |
85 | delete __ptr; |
86 | } |
87 | }; |
88 | |
89 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
90 | // DR 740 - omit specialization for array objects with a compile time length |
91 | |
92 | /// Specialization of default_delete for arrays, used by `unique_ptr<T[]>` |
93 | template<typename _Tp> |
94 | struct default_delete<_Tp[]> |
95 | { |
96 | public: |
97 | /// Default constructor |
98 | constexpr default_delete() noexcept = default; |
99 | |
100 | /** @brief Converting constructor. |
101 | * |
102 | * Allows conversion from a deleter for arrays of another type, such as |
103 | * a const-qualified version of `_Tp`. |
104 | * |
105 | * Conversions from types derived from `_Tp` are not allowed because |
106 | * it is undefined to `delete[]` an array of derived types through a |
107 | * pointer to the base type. |
108 | */ |
109 | template<typename _Up, |
110 | typename = _Require<is_convertible<_Up(*)[], _Tp(*)[]>>> |
111 | default_delete(const default_delete<_Up[]>&) noexcept { } |
112 | |
113 | /// Calls `delete[] __ptr` |
114 | template<typename _Up> |
115 | typename enable_if<is_convertible<_Up(*)[], _Tp(*)[]>::value>::type |
116 | operator()(_Up* __ptr) const |
117 | { |
118 | static_assert(sizeof(_Tp)>0, |
119 | "can't delete pointer to incomplete type"); |
120 | delete [] __ptr; |
121 | } |
122 | }; |
123 | |
124 | /// @cond undocumented |
125 | |
126 | // Manages the pointer and deleter of a unique_ptr |
127 | template <typename _Tp, typename _Dp> |
128 | class __uniq_ptr_impl |
129 | { |
130 | template <typename _Up, typename _Ep, typename = void> |
131 | struct _Ptr |
132 | { |
133 | using type = _Up*; |
134 | }; |
135 | |
136 | template <typename _Up, typename _Ep> |
137 | struct |
138 | _Ptr<_Up, _Ep, __void_t<typename remove_reference<_Ep>::type::pointer>> |
139 | { |
140 | using type = typename remove_reference<_Ep>::type::pointer; |
141 | }; |
142 | |
143 | public: |
144 | using _DeleterConstraint = enable_if< |
145 | __and_<__not_<is_pointer<_Dp>>, |
146 | is_default_constructible<_Dp>>::value>; |
147 | |
148 | using pointer = typename _Ptr<_Tp, _Dp>::type; |
149 | |
150 | static_assert( !is_rvalue_reference<_Dp>::value, |
151 | "unique_ptr's deleter type must be a function object type" |
152 | " or an lvalue reference type" ); |
153 | |
154 | __uniq_ptr_impl() = default; |
155 | __uniq_ptr_impl(pointer __p) : _M_t() { _M_ptr() = __p; } |
156 | |
157 | template<typename _Del> |
158 | __uniq_ptr_impl(pointer __p, _Del&& __d) |
159 | : _M_t(__p, std::forward<_Del>(__d)) { } |
160 | |
161 | __uniq_ptr_impl(__uniq_ptr_impl&& __u) noexcept |
162 | : _M_t(std::move(__u._M_t)) |
163 | { __u._M_ptr() = nullptr; } |
164 | |
165 | __uniq_ptr_impl& operator=(__uniq_ptr_impl&& __u) noexcept |
166 | { |
167 | reset(__u.release()); |
168 | _M_deleter() = std::forward<_Dp>(__u._M_deleter()); |
169 | return *this; |
170 | } |
171 | |
172 | pointer& _M_ptr() { return std::get<0>(_M_t); } |
173 | pointer _M_ptr() const { return std::get<0>(_M_t); } |
174 | _Dp& _M_deleter() { return std::get<1>(_M_t); } |
175 | const _Dp& _M_deleter() const { return std::get<1>(_M_t); } |
176 | |
177 | void reset(pointer __p) noexcept |
178 | { |
179 | const pointer __old_p = _M_ptr(); |
180 | _M_ptr() = __p; |
181 | if (__old_p) |
182 | _M_deleter()(__old_p); |
183 | } |
184 | |
185 | pointer release() noexcept |
186 | { |
187 | pointer __p = _M_ptr(); |
188 | _M_ptr() = nullptr; |
189 | return __p; |
190 | } |
191 | |
192 | void |
193 | swap(__uniq_ptr_impl& __rhs) noexcept |
194 | { |
195 | using std::swap; |
196 | swap(this->_M_ptr(), __rhs._M_ptr()); |
197 | swap(this->_M_deleter(), __rhs._M_deleter()); |
198 | } |
199 | |
200 | private: |
201 | tuple<pointer, _Dp> _M_t; |
202 | }; |
203 | |
204 | // Defines move construction + assignment as either defaulted or deleted. |
205 | template <typename _Tp, typename _Dp, |
206 | bool = is_move_constructible<_Dp>::value, |
207 | bool = is_move_assignable<_Dp>::value> |
208 | struct __uniq_ptr_data : __uniq_ptr_impl<_Tp, _Dp> |
209 | { |
210 | using __uniq_ptr_impl<_Tp, _Dp>::__uniq_ptr_impl; |
211 | __uniq_ptr_data(__uniq_ptr_data&&) = default; |
212 | __uniq_ptr_data& operator=(__uniq_ptr_data&&) = default; |
213 | }; |
214 | |
215 | template <typename _Tp, typename _Dp> |
216 | struct __uniq_ptr_data<_Tp, _Dp, true, false> : __uniq_ptr_impl<_Tp, _Dp> |
217 | { |
218 | using __uniq_ptr_impl<_Tp, _Dp>::__uniq_ptr_impl; |
219 | __uniq_ptr_data(__uniq_ptr_data&&) = default; |
220 | __uniq_ptr_data& operator=(__uniq_ptr_data&&) = delete; |
221 | }; |
222 | |
223 | template <typename _Tp, typename _Dp> |
224 | struct __uniq_ptr_data<_Tp, _Dp, false, true> : __uniq_ptr_impl<_Tp, _Dp> |
225 | { |
226 | using __uniq_ptr_impl<_Tp, _Dp>::__uniq_ptr_impl; |
227 | __uniq_ptr_data(__uniq_ptr_data&&) = delete; |
228 | __uniq_ptr_data& operator=(__uniq_ptr_data&&) = default; |
229 | }; |
230 | |
231 | template <typename _Tp, typename _Dp> |
232 | struct __uniq_ptr_data<_Tp, _Dp, false, false> : __uniq_ptr_impl<_Tp, _Dp> |
233 | { |
234 | using __uniq_ptr_impl<_Tp, _Dp>::__uniq_ptr_impl; |
235 | __uniq_ptr_data(__uniq_ptr_data&&) = delete; |
236 | __uniq_ptr_data& operator=(__uniq_ptr_data&&) = delete; |
237 | }; |
238 | /// @endcond |
239 | |
240 | /// 20.7.1.2 unique_ptr for single objects. |
241 | template <typename _Tp, typename _Dp = default_delete<_Tp>> |
242 | class unique_ptr |
243 | { |
244 | template <typename _Up> |
245 | using _DeleterConstraint = |
246 | typename __uniq_ptr_impl<_Tp, _Up>::_DeleterConstraint::type; |
247 | |
248 | __uniq_ptr_data<_Tp, _Dp> _M_t; |
249 | |
250 | public: |
251 | using pointer = typename __uniq_ptr_impl<_Tp, _Dp>::pointer; |
252 | using element_type = _Tp; |
253 | using deleter_type = _Dp; |
254 | |
255 | private: |
256 | // helper template for detecting a safe conversion from another |
257 | // unique_ptr |
258 | template<typename _Up, typename _Ep> |
259 | using __safe_conversion_up = __and_< |
260 | is_convertible<typename unique_ptr<_Up, _Ep>::pointer, pointer>, |
261 | __not_<is_array<_Up>> |
262 | >; |
263 | |
264 | public: |
265 | // Constructors. |
266 | |
267 | /// Default constructor, creates a unique_ptr that owns nothing. |
268 | template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>> |
269 | constexpr unique_ptr() noexcept |
270 | : _M_t() |
271 | { } |
272 | |
273 | /** Takes ownership of a pointer. |
274 | * |
275 | * @param __p A pointer to an object of @c element_type |
276 | * |
277 | * The deleter will be value-initialized. |
278 | */ |
279 | template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>> |
280 | explicit |
281 | unique_ptr(pointer __p) noexcept |
282 | : _M_t(__p) |
283 | { } |
284 | |
285 | /** Takes ownership of a pointer. |
286 | * |
287 | * @param __p A pointer to an object of @c element_type |
288 | * @param __d A reference to a deleter. |
289 | * |
290 | * The deleter will be initialized with @p __d |
291 | */ |
292 | template<typename _Del = deleter_type, |
293 | typename = _Require<is_copy_constructible<_Del>>> |
294 | unique_ptr(pointer __p, const deleter_type& __d) noexcept |
295 | : _M_t(__p, __d) { } |
296 | |
297 | /** Takes ownership of a pointer. |
298 | * |
299 | * @param __p A pointer to an object of @c element_type |
300 | * @param __d An rvalue reference to a (non-reference) deleter. |
301 | * |
302 | * The deleter will be initialized with @p std::move(__d) |
303 | */ |
304 | template<typename _Del = deleter_type, |
305 | typename = _Require<is_move_constructible<_Del>>> |
306 | unique_ptr(pointer __p, |
307 | __enable_if_t<!is_lvalue_reference<_Del>::value, |
308 | _Del&&> __d) noexcept |
309 | : _M_t(__p, std::move(__d)) |
310 | { } |
311 | |
312 | template<typename _Del = deleter_type, |
313 | typename _DelUnref = typename remove_reference<_Del>::type> |
314 | unique_ptr(pointer, |
315 | __enable_if_t<is_lvalue_reference<_Del>::value, |
316 | _DelUnref&&>) = delete; |
317 | |
318 | /// Creates a unique_ptr that owns nothing. |
319 | template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>> |
320 | constexpr unique_ptr(nullptr_t) noexcept |
321 | : _M_t() |
322 | { } |
323 | |
324 | // Move constructors. |
325 | |
326 | /// Move constructor. |
327 | unique_ptr(unique_ptr&&) = default; |
328 | |
329 | /** @brief Converting constructor from another type |
330 | * |
331 | * Requires that the pointer owned by @p __u is convertible to the |
332 | * type of pointer owned by this object, @p __u does not own an array, |
333 | * and @p __u has a compatible deleter type. |
334 | */ |
335 | template<typename _Up, typename _Ep, typename = _Require< |
336 | __safe_conversion_up<_Up, _Ep>, |
337 | typename conditional<is_reference<_Dp>::value, |
338 | is_same<_Ep, _Dp>, |
339 | is_convertible<_Ep, _Dp>>::type>> |
340 | unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept |
341 | : _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter())) |
342 | { } |
343 | |
344 | #if _GLIBCXX_USE_DEPRECATED1 |
345 | #pragma GCC diagnostic push |
346 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" |
347 | /// Converting constructor from @c auto_ptr |
348 | template<typename _Up, typename = _Require< |
349 | is_convertible<_Up*, _Tp*>, is_same<_Dp, default_delete<_Tp>>>> |
350 | unique_ptr(auto_ptr<_Up>&& __u) noexcept; |
351 | #pragma GCC diagnostic pop |
352 | #endif |
353 | |
354 | /// Destructor, invokes the deleter if the stored pointer is not null. |
355 | ~unique_ptr() noexcept |
356 | { |
357 | static_assert(__is_invocable<deleter_type&, pointer>::value, |
358 | "unique_ptr's deleter must be invocable with a pointer"); |
359 | auto& __ptr = _M_t._M_ptr(); |
360 | if (__ptr != nullptr) |
361 | get_deleter()(std::move(__ptr)); |
362 | __ptr = pointer(); |
363 | } |
364 | |
365 | // Assignment. |
366 | |
367 | /** @brief Move assignment operator. |
368 | * |
369 | * Invokes the deleter if this object owns a pointer. |
370 | */ |
371 | unique_ptr& operator=(unique_ptr&&) = default; |
372 | |
373 | /** @brief Assignment from another type. |
374 | * |
375 | * @param __u The object to transfer ownership from, which owns a |
376 | * convertible pointer to a non-array object. |
377 | * |
378 | * Invokes the deleter if this object owns a pointer. |
379 | */ |
380 | template<typename _Up, typename _Ep> |
381 | typename enable_if< __and_< |
382 | __safe_conversion_up<_Up, _Ep>, |
383 | is_assignable<deleter_type&, _Ep&&> |
384 | >::value, |
385 | unique_ptr&>::type |
386 | operator=(unique_ptr<_Up, _Ep>&& __u) noexcept |
387 | { |
388 | reset(__u.release()); |
389 | get_deleter() = std::forward<_Ep>(__u.get_deleter()); |
390 | return *this; |
391 | } |
392 | |
393 | /// Reset the %unique_ptr to empty, invoking the deleter if necessary. |
394 | unique_ptr& |
395 | operator=(nullptr_t) noexcept |
396 | { |
397 | reset(); |
398 | return *this; |
399 | } |
400 | |
401 | // Observers. |
402 | |
403 | /// Dereference the stored pointer. |
404 | typename add_lvalue_reference<element_type>::type |
405 | operator*() const |
406 | { |
407 | __glibcxx_assert(get() != pointer()); |
408 | return *get(); |
409 | } |
410 | |
411 | /// Return the stored pointer. |
412 | pointer |
413 | operator->() const noexcept |
414 | { |
415 | _GLIBCXX_DEBUG_PEDASSERT(get() != pointer()); |
416 | return get(); |
417 | } |
418 | |
419 | /// Return the stored pointer. |
420 | pointer |
421 | get() const noexcept |
422 | { return _M_t._M_ptr(); } |
423 | |
424 | /// Return a reference to the stored deleter. |
425 | deleter_type& |
426 | get_deleter() noexcept |
427 | { return _M_t._M_deleter(); } |
428 | |
429 | /// Return a reference to the stored deleter. |
430 | const deleter_type& |
431 | get_deleter() const noexcept |
432 | { return _M_t._M_deleter(); } |
433 | |
434 | /// Return @c true if the stored pointer is not null. |
435 | explicit operator bool() const noexcept |
436 | { return get() == pointer() ? false : true; } |
437 | |
438 | // Modifiers. |
439 | |
440 | /// Release ownership of any stored pointer. |
441 | pointer |
442 | release() noexcept |
443 | { return _M_t.release(); } |
444 | |
445 | /** @brief Replace the stored pointer. |
446 | * |
447 | * @param __p The new pointer to store. |
448 | * |
449 | * The deleter will be invoked if a pointer is already owned. |
450 | */ |
451 | void |
452 | reset(pointer __p = pointer()) noexcept |
453 | { |
454 | static_assert(__is_invocable<deleter_type&, pointer>::value, |
455 | "unique_ptr's deleter must be invocable with a pointer"); |
456 | _M_t.reset(std::move(__p)); |
457 | } |
458 | |
459 | /// Exchange the pointer and deleter with another object. |
460 | void |
461 | swap(unique_ptr& __u) noexcept |
462 | { |
463 | static_assert(__is_swappable<_Dp>::value, "deleter must be swappable"); |
464 | _M_t.swap(__u._M_t); |
465 | } |
466 | |
467 | // Disable copy from lvalue. |
468 | unique_ptr(const unique_ptr&) = delete; |
469 | unique_ptr& operator=(const unique_ptr&) = delete; |
470 | }; |
471 | |
472 | /// 20.7.1.3 unique_ptr for array objects with a runtime length |
473 | // [unique.ptr.runtime] |
474 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
475 | // DR 740 - omit specialization for array objects with a compile time length |
476 | template<typename _Tp, typename _Dp> |
477 | class unique_ptr<_Tp[], _Dp> |
478 | { |
479 | template <typename _Up> |
480 | using _DeleterConstraint = |
481 | typename __uniq_ptr_impl<_Tp, _Up>::_DeleterConstraint::type; |
482 | |
483 | __uniq_ptr_data<_Tp, _Dp> _M_t; |
484 | |
485 | template<typename _Up> |
486 | using __remove_cv = typename remove_cv<_Up>::type; |
487 | |
488 | // like is_base_of<_Tp, _Up> but false if unqualified types are the same |
489 | template<typename _Up> |
490 | using __is_derived_Tp |
491 | = __and_< is_base_of<_Tp, _Up>, |
492 | __not_<is_same<__remove_cv<_Tp>, __remove_cv<_Up>>> >; |
493 | |
494 | public: |
495 | using pointer = typename __uniq_ptr_impl<_Tp, _Dp>::pointer; |
496 | using element_type = _Tp; |
497 | using deleter_type = _Dp; |
498 | |
499 | // helper template for detecting a safe conversion from another |
500 | // unique_ptr |
501 | template<typename _Up, typename _Ep, |
502 | typename _UPtr = unique_ptr<_Up, _Ep>, |
503 | typename _UP_pointer = typename _UPtr::pointer, |
504 | typename _UP_element_type = typename _UPtr::element_type> |
505 | using __safe_conversion_up = __and_< |
506 | is_array<_Up>, |
507 | is_same<pointer, element_type*>, |
508 | is_same<_UP_pointer, _UP_element_type*>, |
509 | is_convertible<_UP_element_type(*)[], element_type(*)[]> |
510 | >; |
511 | |
512 | // helper template for detecting a safe conversion from a raw pointer |
513 | template<typename _Up> |
514 | using __safe_conversion_raw = __and_< |
515 | __or_<__or_<is_same<_Up, pointer>, |
516 | is_same<_Up, nullptr_t>>, |
517 | __and_<is_pointer<_Up>, |
518 | is_same<pointer, element_type*>, |
519 | is_convertible< |
520 | typename remove_pointer<_Up>::type(*)[], |
521 | element_type(*)[]> |
522 | > |
523 | > |
524 | >; |
525 | |
526 | // Constructors. |
527 | |
528 | /// Default constructor, creates a unique_ptr that owns nothing. |
529 | template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>> |
530 | constexpr unique_ptr() noexcept |
531 | : _M_t() |
532 | { } |
533 | |
534 | /** Takes ownership of a pointer. |
535 | * |
536 | * @param __p A pointer to an array of a type safely convertible |
537 | * to an array of @c element_type |
538 | * |
539 | * The deleter will be value-initialized. |
540 | */ |
541 | template<typename _Up, |
542 | typename _Vp = _Dp, |
543 | typename = _DeleterConstraint<_Vp>, |
544 | typename = typename enable_if< |
545 | __safe_conversion_raw<_Up>::value, bool>::type> |
546 | explicit |
547 | unique_ptr(_Up __p) noexcept |
548 | : _M_t(__p) |
549 | { } |
550 | |
551 | /** Takes ownership of a pointer. |
552 | * |
553 | * @param __p A pointer to an array of a type safely convertible |
554 | * to an array of @c element_type |
555 | * @param __d A reference to a deleter. |
556 | * |
557 | * The deleter will be initialized with @p __d |
558 | */ |
559 | template<typename _Up, typename _Del = deleter_type, |
560 | typename = _Require<__safe_conversion_raw<_Up>, |
561 | is_copy_constructible<_Del>>> |
562 | unique_ptr(_Up __p, const deleter_type& __d) noexcept |
563 | : _M_t(__p, __d) { } |
564 | |
565 | /** Takes ownership of a pointer. |
566 | * |
567 | * @param __p A pointer to an array of a type safely convertible |
568 | * to an array of @c element_type |
569 | * @param __d A reference to a deleter. |
570 | * |
571 | * The deleter will be initialized with @p std::move(__d) |
572 | */ |
573 | template<typename _Up, typename _Del = deleter_type, |
574 | typename = _Require<__safe_conversion_raw<_Up>, |
575 | is_move_constructible<_Del>>> |
576 | unique_ptr(_Up __p, |
577 | __enable_if_t<!is_lvalue_reference<_Del>::value, |
578 | _Del&&> __d) noexcept |
579 | : _M_t(std::move(__p), std::move(__d)) |
580 | { } |
581 | |
582 | template<typename _Up, typename _Del = deleter_type, |
583 | typename _DelUnref = typename remove_reference<_Del>::type, |
584 | typename = _Require<__safe_conversion_raw<_Up>>> |
585 | unique_ptr(_Up, |
586 | __enable_if_t<is_lvalue_reference<_Del>::value, |
587 | _DelUnref&&>) = delete; |
588 | |
589 | /// Move constructor. |
590 | unique_ptr(unique_ptr&&) = default; |
591 | |
592 | /// Creates a unique_ptr that owns nothing. |
593 | template<typename _Del = _Dp, typename = _DeleterConstraint<_Del>> |
594 | constexpr unique_ptr(nullptr_t) noexcept |
595 | : _M_t() |
596 | { } |
597 | |
598 | template<typename _Up, typename _Ep, typename = _Require< |
599 | __safe_conversion_up<_Up, _Ep>, |
600 | typename conditional<is_reference<_Dp>::value, |
601 | is_same<_Ep, _Dp>, |
602 | is_convertible<_Ep, _Dp>>::type>> |
603 | unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept |
604 | : _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter())) |
605 | { } |
606 | |
607 | /// Destructor, invokes the deleter if the stored pointer is not null. |
608 | ~unique_ptr() |
609 | { |
610 | auto& __ptr = _M_t._M_ptr(); |
611 | if (__ptr != nullptr) |
612 | get_deleter()(__ptr); |
613 | __ptr = pointer(); |
614 | } |
615 | |
616 | // Assignment. |
617 | |
618 | /** @brief Move assignment operator. |
619 | * |
620 | * Invokes the deleter if this object owns a pointer. |
621 | */ |
622 | unique_ptr& |
623 | operator=(unique_ptr&&) = default; |
624 | |
625 | /** @brief Assignment from another type. |
626 | * |
627 | * @param __u The object to transfer ownership from, which owns a |
628 | * convertible pointer to an array object. |
629 | * |
630 | * Invokes the deleter if this object owns a pointer. |
631 | */ |
632 | template<typename _Up, typename _Ep> |
633 | typename |
634 | enable_if<__and_<__safe_conversion_up<_Up, _Ep>, |
635 | is_assignable<deleter_type&, _Ep&&> |
636 | >::value, |
637 | unique_ptr&>::type |
638 | operator=(unique_ptr<_Up, _Ep>&& __u) noexcept |
639 | { |
640 | reset(__u.release()); |
641 | get_deleter() = std::forward<_Ep>(__u.get_deleter()); |
642 | return *this; |
643 | } |
644 | |
645 | /// Reset the %unique_ptr to empty, invoking the deleter if necessary. |
646 | unique_ptr& |
647 | operator=(nullptr_t) noexcept |
648 | { |
649 | reset(); |
650 | return *this; |
651 | } |
652 | |
653 | // Observers. |
654 | |
655 | /// Access an element of owned array. |
656 | typename std::add_lvalue_reference<element_type>::type |
657 | operator[](size_t __i) const |
658 | { |
659 | __glibcxx_assert(get() != pointer()); |
660 | return get()[__i]; |
661 | } |
662 | |
663 | /// Return the stored pointer. |
664 | pointer |
665 | get() const noexcept |
666 | { return _M_t._M_ptr(); } |
667 | |
668 | /// Return a reference to the stored deleter. |
669 | deleter_type& |
670 | get_deleter() noexcept |
671 | { return _M_t._M_deleter(); } |
672 | |
673 | /// Return a reference to the stored deleter. |
674 | const deleter_type& |
675 | get_deleter() const noexcept |
676 | { return _M_t._M_deleter(); } |
677 | |
678 | /// Return @c true if the stored pointer is not null. |
679 | explicit operator bool() const noexcept |
680 | { return get() == pointer() ? false : true; } |
681 | |
682 | // Modifiers. |
683 | |
684 | /// Release ownership of any stored pointer. |
685 | pointer |
686 | release() noexcept |
687 | { return _M_t.release(); } |
688 | |
689 | /** @brief Replace the stored pointer. |
690 | * |
691 | * @param __p The new pointer to store. |
692 | * |
693 | * The deleter will be invoked if a pointer is already owned. |
694 | */ |
695 | template <typename _Up, |
696 | typename = _Require< |
697 | __or_<is_same<_Up, pointer>, |
698 | __and_<is_same<pointer, element_type*>, |
699 | is_pointer<_Up>, |
700 | is_convertible< |
701 | typename remove_pointer<_Up>::type(*)[], |
702 | element_type(*)[] |
703 | > |
704 | > |
705 | > |
706 | >> |
707 | void |
708 | reset(_Up __p) noexcept |
709 | { _M_t.reset(std::move(__p)); } |
710 | |
711 | void reset(nullptr_t = nullptr) noexcept |
712 | { reset(pointer()); } |
713 | |
714 | /// Exchange the pointer and deleter with another object. |
715 | void |
716 | swap(unique_ptr& __u) noexcept |
717 | { |
718 | static_assert(__is_swappable<_Dp>::value, "deleter must be swappable"); |
719 | _M_t.swap(__u._M_t); |
720 | } |
721 | |
722 | // Disable copy from lvalue. |
723 | unique_ptr(const unique_ptr&) = delete; |
724 | unique_ptr& operator=(const unique_ptr&) = delete; |
725 | }; |
726 | |
727 | /// @relates unique_ptr @{ |
728 | |
729 | /// Swap overload for unique_ptr |
730 | template<typename _Tp, typename _Dp> |
731 | inline |
732 | #if __cplusplus201402L > 201402L || !defined(__STRICT_ANSI__1) // c++1z or gnu++11 |
733 | // Constrained free swap overload, see p0185r1 |
734 | typename enable_if<__is_swappable<_Dp>::value>::type |
735 | #else |
736 | void |
737 | #endif |
738 | swap(unique_ptr<_Tp, _Dp>& __x, |
739 | unique_ptr<_Tp, _Dp>& __y) noexcept |
740 | { __x.swap(__y); } |
741 | |
742 | #if __cplusplus201402L > 201402L || !defined(__STRICT_ANSI__1) // c++1z or gnu++11 |
743 | template<typename _Tp, typename _Dp> |
744 | typename enable_if<!__is_swappable<_Dp>::value>::type |
745 | swap(unique_ptr<_Tp, _Dp>&, |
746 | unique_ptr<_Tp, _Dp>&) = delete; |
747 | #endif |
748 | |
749 | /// Equality operator for unique_ptr objects, compares the owned pointers |
750 | template<typename _Tp, typename _Dp, |
751 | typename _Up, typename _Ep> |
752 | _GLIBCXX_NODISCARD inline bool |
753 | operator==(const unique_ptr<_Tp, _Dp>& __x, |
754 | const unique_ptr<_Up, _Ep>& __y) |
755 | { return __x.get() == __y.get(); } |
756 | |
757 | /// unique_ptr comparison with nullptr |
758 | template<typename _Tp, typename _Dp> |
759 | _GLIBCXX_NODISCARD inline bool |
760 | operator==(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) noexcept |
761 | { return !__x; } |
762 | |
763 | #ifndef __cpp_lib_three_way_comparison |
764 | /// unique_ptr comparison with nullptr |
765 | template<typename _Tp, typename _Dp> |
766 | _GLIBCXX_NODISCARD inline bool |
767 | operator==(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) noexcept |
768 | { return !__x; } |
769 | |
770 | /// Inequality operator for unique_ptr objects, compares the owned pointers |
771 | template<typename _Tp, typename _Dp, |
772 | typename _Up, typename _Ep> |
773 | _GLIBCXX_NODISCARD inline bool |
774 | operator!=(const unique_ptr<_Tp, _Dp>& __x, |
775 | const unique_ptr<_Up, _Ep>& __y) |
776 | { return __x.get() != __y.get(); } |
777 | |
778 | /// unique_ptr comparison with nullptr |
779 | template<typename _Tp, typename _Dp> |
780 | _GLIBCXX_NODISCARD inline bool |
781 | operator!=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) noexcept |
782 | { return (bool)__x; } |
783 | |
784 | /// unique_ptr comparison with nullptr |
785 | template<typename _Tp, typename _Dp> |
786 | _GLIBCXX_NODISCARD inline bool |
787 | operator!=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) noexcept |
788 | { return (bool)__x; } |
789 | #endif // three way comparison |
790 | |
791 | /// Relational operator for unique_ptr objects, compares the owned pointers |
792 | template<typename _Tp, typename _Dp, |
793 | typename _Up, typename _Ep> |
794 | _GLIBCXX_NODISCARD inline bool |
795 | operator<(const unique_ptr<_Tp, _Dp>& __x, |
796 | const unique_ptr<_Up, _Ep>& __y) |
797 | { |
798 | typedef typename |
799 | std::common_type<typename unique_ptr<_Tp, _Dp>::pointer, |
800 | typename unique_ptr<_Up, _Ep>::pointer>::type _CT; |
801 | return std::less<_CT>()(__x.get(), __y.get()); |
802 | } |
803 | |
804 | /// unique_ptr comparison with nullptr |
805 | template<typename _Tp, typename _Dp> |
806 | _GLIBCXX_NODISCARD inline bool |
807 | operator<(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) |
808 | { |
809 | return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(__x.get(), |
810 | nullptr); |
811 | } |
812 | |
813 | /// unique_ptr comparison with nullptr |
814 | template<typename _Tp, typename _Dp> |
815 | _GLIBCXX_NODISCARD inline bool |
816 | operator<(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) |
817 | { |
818 | return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(nullptr, |
819 | __x.get()); |
820 | } |
821 | |
822 | /// Relational operator for unique_ptr objects, compares the owned pointers |
823 | template<typename _Tp, typename _Dp, |
824 | typename _Up, typename _Ep> |
825 | _GLIBCXX_NODISCARD inline bool |
826 | operator<=(const unique_ptr<_Tp, _Dp>& __x, |
827 | const unique_ptr<_Up, _Ep>& __y) |
828 | { return !(__y < __x); } |
829 | |
830 | /// unique_ptr comparison with nullptr |
831 | template<typename _Tp, typename _Dp> |
832 | _GLIBCXX_NODISCARD inline bool |
833 | operator<=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) |
834 | { return !(nullptr < __x); } |
835 | |
836 | /// unique_ptr comparison with nullptr |
837 | template<typename _Tp, typename _Dp> |
838 | _GLIBCXX_NODISCARD inline bool |
839 | operator<=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) |
840 | { return !(__x < nullptr); } |
841 | |
842 | /// Relational operator for unique_ptr objects, compares the owned pointers |
843 | template<typename _Tp, typename _Dp, |
844 | typename _Up, typename _Ep> |
845 | _GLIBCXX_NODISCARD inline bool |
846 | operator>(const unique_ptr<_Tp, _Dp>& __x, |
847 | const unique_ptr<_Up, _Ep>& __y) |
848 | { return (__y < __x); } |
849 | |
850 | /// unique_ptr comparison with nullptr |
851 | template<typename _Tp, typename _Dp> |
852 | _GLIBCXX_NODISCARD inline bool |
853 | operator>(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) |
854 | { |
855 | return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(nullptr, |
856 | __x.get()); |
857 | } |
858 | |
859 | /// unique_ptr comparison with nullptr |
860 | template<typename _Tp, typename _Dp> |
861 | _GLIBCXX_NODISCARD inline bool |
862 | operator>(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) |
863 | { |
864 | return std::less<typename unique_ptr<_Tp, _Dp>::pointer>()(__x.get(), |
865 | nullptr); |
866 | } |
867 | |
868 | /// Relational operator for unique_ptr objects, compares the owned pointers |
869 | template<typename _Tp, typename _Dp, |
870 | typename _Up, typename _Ep> |
871 | _GLIBCXX_NODISCARD inline bool |
872 | operator>=(const unique_ptr<_Tp, _Dp>& __x, |
873 | const unique_ptr<_Up, _Ep>& __y) |
874 | { return !(__x < __y); } |
875 | |
876 | /// unique_ptr comparison with nullptr |
877 | template<typename _Tp, typename _Dp> |
878 | _GLIBCXX_NODISCARD inline bool |
879 | operator>=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) |
880 | { return !(__x < nullptr); } |
881 | |
882 | /// unique_ptr comparison with nullptr |
883 | template<typename _Tp, typename _Dp> |
884 | _GLIBCXX_NODISCARD inline bool |
885 | operator>=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) |
886 | { return !(nullptr < __x); } |
887 | |
888 | #ifdef __cpp_lib_three_way_comparison |
889 | template<typename _Tp, typename _Dp, typename _Up, typename _Ep> |
890 | requires three_way_comparable_with<typename unique_ptr<_Tp, _Dp>::pointer, |
891 | typename unique_ptr<_Up, _Ep>::pointer> |
892 | inline |
893 | compare_three_way_result_t<typename unique_ptr<_Tp, _Dp>::pointer, |
894 | typename unique_ptr<_Up, _Ep>::pointer> |
895 | operator<=>(const unique_ptr<_Tp, _Dp>& __x, |
896 | const unique_ptr<_Up, _Ep>& __y) |
897 | { return compare_three_way()(__x.get(), __y.get()); } |
898 | |
899 | template<typename _Tp, typename _Dp> |
900 | requires three_way_comparable<typename unique_ptr<_Tp, _Dp>::pointer> |
901 | inline |
902 | compare_three_way_result_t<typename unique_ptr<_Tp, _Dp>::pointer> |
903 | operator<=>(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) |
904 | { |
905 | using pointer = typename unique_ptr<_Tp, _Dp>::pointer; |
906 | return compare_three_way()(__x.get(), static_cast<pointer>(nullptr)); |
907 | } |
908 | #endif |
909 | // @} relates unique_ptr |
910 | |
911 | /// @cond undocumented |
912 | template<typename _Up, typename _Ptr = typename _Up::pointer, |
913 | bool = __poison_hash<_Ptr>::__enable_hash_call> |
914 | struct __uniq_ptr_hash |
915 | #if ! _GLIBCXX_INLINE_VERSION0 |
916 | : private __poison_hash<_Ptr> |
917 | #endif |
918 | { |
919 | size_t |
920 | operator()(const _Up& __u) const |
921 | noexcept(noexcept(std::declval<hash<_Ptr>>()(std::declval<_Ptr>()))) |
922 | { return hash<_Ptr>()(__u.get()); } |
923 | }; |
924 | |
925 | template<typename _Up, typename _Ptr> |
926 | struct __uniq_ptr_hash<_Up, _Ptr, false> |
927 | : private __poison_hash<_Ptr> |
928 | { }; |
929 | /// @endcond |
930 | |
931 | /// std::hash specialization for unique_ptr. |
932 | template<typename _Tp, typename _Dp> |
933 | struct hash<unique_ptr<_Tp, _Dp>> |
934 | : public __hash_base<size_t, unique_ptr<_Tp, _Dp>>, |
935 | public __uniq_ptr_hash<unique_ptr<_Tp, _Dp>> |
936 | { }; |
937 | |
938 | #if __cplusplus201402L >= 201402L |
939 | /// @relates unique_ptr @{ |
940 | #define __cpp_lib_make_unique201304 201304 |
941 | |
942 | /// @cond undocumented |
943 | |
944 | template<typename _Tp> |
945 | struct _MakeUniq |
946 | { typedef unique_ptr<_Tp> __single_object; }; |
947 | |
948 | template<typename _Tp> |
949 | struct _MakeUniq<_Tp[]> |
950 | { typedef unique_ptr<_Tp[]> __array; }; |
951 | |
952 | template<typename _Tp, size_t _Bound> |
953 | struct _MakeUniq<_Tp[_Bound]> |
954 | { struct __invalid_type { }; }; |
955 | |
956 | /// @endcond |
957 | |
958 | /// std::make_unique for single objects |
959 | template<typename _Tp, typename... _Args> |
960 | inline typename _MakeUniq<_Tp>::__single_object |
961 | make_unique(_Args&&... __args) |
962 | { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); } |
963 | |
964 | /// std::make_unique for arrays of unknown bound |
965 | template<typename _Tp> |
966 | inline typename _MakeUniq<_Tp>::__array |
967 | make_unique(size_t __num) |
968 | { return unique_ptr<_Tp>(new remove_extent_t<_Tp>[__num]()); } |
969 | |
970 | /// Disable std::make_unique for arrays of known bound |
971 | template<typename _Tp, typename... _Args> |
972 | inline typename _MakeUniq<_Tp>::__invalid_type |
973 | make_unique(_Args&&...) = delete; |
974 | // @} relates unique_ptr |
975 | #endif // C++14 |
976 | |
977 | #if __cplusplus201402L > 201703L && __cpp_concepts |
978 | // _GLIBCXX_RESOLVE_LIB_DEFECTS |
979 | // 2948. unique_ptr does not define operator<< for stream output |
980 | /// Stream output operator for unique_ptr |
981 | template<typename _CharT, typename _Traits, typename _Tp, typename _Dp> |
982 | inline basic_ostream<_CharT, _Traits>& |
983 | operator<<(basic_ostream<_CharT, _Traits>& __os, |
984 | const unique_ptr<_Tp, _Dp>& __p) |
985 | requires requires { __os << __p.get(); } |
986 | { |
987 | __os << __p.get(); |
988 | return __os; |
989 | } |
990 | #endif // C++20 |
991 | |
992 | // @} group pointer_abstractions |
993 | |
994 | #if __cplusplus201402L >= 201703L |
995 | namespace __detail::__variant |
996 | { |
997 | template<typename> struct _Never_valueless_alt; // see <variant> |
998 | |
999 | // Provide the strong exception-safety guarantee when emplacing a |
1000 | // unique_ptr into a variant. |
1001 | template<typename _Tp, typename _Del> |
1002 | struct _Never_valueless_alt<std::unique_ptr<_Tp, _Del>> |
1003 | : std::true_type |
1004 | { }; |
1005 | } // namespace __detail::__variant |
1006 | #endif // C++17 |
1007 | |
1008 | _GLIBCXX_END_NAMESPACE_VERSION |
1009 | } // namespace |
1010 | |
1011 | #endif /* _UNIQUE_PTR_H */ |