Olivier Deprez | f4ef2d0 | 2021-04-20 13:36:24 +0200 | [diff] [blame] | 1 | //=- IslNodeBuilder.cpp - Translate an isl AST into a LLVM-IR AST -*- C++ -*-=// |
| 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 contains the IslNodeBuilder, a class to translate an isl AST into |
| 10 | // a LLVM-IR AST. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #ifndef POLLY_ISLNODEBUILDER_H |
| 15 | #define POLLY_ISLNODEBUILDER_H |
| 16 | |
| 17 | #include "polly/CodeGen/BlockGenerators.h" |
| 18 | #include "polly/CodeGen/IslExprBuilder.h" |
| 19 | #include "polly/ScopDetectionDiagnostic.h" |
| 20 | #include "llvm/ADT/ArrayRef.h" |
| 21 | #include "llvm/ADT/SmallSet.h" |
| 22 | #include "llvm/IR/InstrTypes.h" |
| 23 | #include "isl/ctx.h" |
| 24 | #include "isl/isl-noexceptions.h" |
| 25 | |
| 26 | using namespace llvm; |
| 27 | using namespace polly; |
| 28 | |
| 29 | namespace polly { |
| 30 | |
| 31 | struct InvariantEquivClassTy; |
| 32 | } // namespace polly |
| 33 | |
| 34 | struct SubtreeReferences { |
| 35 | LoopInfo &LI; |
| 36 | ScalarEvolution &SE; |
| 37 | Scop &S; |
| 38 | ValueMapT &GlobalMap; |
| 39 | SetVector<Value *> &Values; |
| 40 | SetVector<const SCEV *> &SCEVs; |
| 41 | BlockGenerator &BlockGen; |
| 42 | // In case an (optional) parameter space location is provided, parameter space |
| 43 | // information is collected as well. |
| 44 | isl::space *ParamSpace; |
| 45 | }; |
| 46 | |
| 47 | /// Extract the out-of-scop values and SCEVs referenced from a ScopStmt. |
| 48 | /// |
| 49 | /// This includes the SCEVUnknowns referenced by the SCEVs used in the |
| 50 | /// statement and the base pointers of the memory accesses. For scalar |
| 51 | /// statements we force the generation of alloca memory locations and list |
| 52 | /// these locations in the set of out-of-scop values as well. |
| 53 | /// |
| 54 | /// We also collect an isl::space that includes all parameter dimensions |
| 55 | /// used in the statement's memory accesses, in case the ParamSpace pointer |
| 56 | /// is non-null. |
| 57 | /// |
| 58 | /// @param Stmt The statement for which to extract the information. |
| 59 | /// @param UserPtr A void pointer that can be casted to a |
| 60 | /// SubtreeReferences structure. |
| 61 | /// @param CreateScalarRefs Should the result include allocas of scalar |
| 62 | /// references? |
| 63 | void addReferencesFromStmt(const ScopStmt *Stmt, void *UserPtr, |
| 64 | bool CreateScalarRefs = true); |
| 65 | |
| 66 | class IslNodeBuilder { |
| 67 | public: |
| 68 | IslNodeBuilder(PollyIRBuilder &Builder, ScopAnnotator &Annotator, |
| 69 | const DataLayout &DL, LoopInfo &LI, ScalarEvolution &SE, |
| 70 | DominatorTree &DT, Scop &S, BasicBlock *StartBlock) |
| 71 | : S(S), Builder(Builder), Annotator(Annotator), |
| 72 | ExprBuilder(S, Builder, IDToValue, ValueMap, DL, SE, DT, LI, |
| 73 | StartBlock), |
| 74 | BlockGen(Builder, LI, SE, DT, ScalarMap, EscapeMap, ValueMap, |
| 75 | &ExprBuilder, StartBlock), |
| 76 | RegionGen(BlockGen), DL(DL), LI(LI), SE(SE), DT(DT), |
| 77 | StartBlock(StartBlock) {} |
| 78 | |
| 79 | virtual ~IslNodeBuilder() = default; |
| 80 | |
| 81 | void addParameters(__isl_take isl_set *Context); |
| 82 | |
| 83 | /// Create Values which hold the sizes of the outermost dimension of all |
| 84 | /// Fortran arrays in the current scop. |
| 85 | /// |
| 86 | /// @returns False, if a problem occurred and a Fortran array was not |
| 87 | /// materialized. True otherwise. |
| 88 | bool materializeFortranArrayOutermostDimension(); |
| 89 | |
| 90 | /// Generate code that evaluates @p Condition at run-time. |
| 91 | /// |
| 92 | /// This function is typically called to generate the LLVM-IR for the |
| 93 | /// run-time condition of the scop, that verifies that all the optimistic |
| 94 | /// assumptions we have taken during scop modeling and transformation |
| 95 | /// hold at run-time. |
| 96 | /// |
| 97 | /// @param Condition The condition to evaluate |
| 98 | /// |
| 99 | /// @result An llvm::Value that is true if the condition holds and false |
| 100 | /// otherwise. |
| 101 | Value *createRTC(isl_ast_expr *Condition); |
| 102 | |
| 103 | void create(__isl_take isl_ast_node *Node); |
| 104 | |
| 105 | /// Allocate memory for all new arrays created by Polly. |
| 106 | void allocateNewArrays(BBPair StartExitBlocks); |
| 107 | |
| 108 | /// Preload all memory loads that are invariant. |
| 109 | bool preloadInvariantLoads(); |
| 110 | |
| 111 | /// Finalize code generation. |
| 112 | /// |
| 113 | /// @see BlockGenerator::finalizeSCoP(Scop &S) |
| 114 | virtual void finalize() { BlockGen.finalizeSCoP(S); } |
| 115 | |
| 116 | IslExprBuilder &getExprBuilder() { return ExprBuilder; } |
| 117 | |
| 118 | /// Get the associated block generator. |
| 119 | /// |
| 120 | /// @return A reference to the associated block generator. |
| 121 | BlockGenerator &getBlockGenerator() { return BlockGen; } |
| 122 | |
| 123 | /// Return the parallel subfunctions that have been created. |
| 124 | const ArrayRef<Function *> getParallelSubfunctions() const { |
| 125 | return ParallelSubfunctions; |
| 126 | } |
| 127 | |
| 128 | protected: |
| 129 | Scop &S; |
| 130 | PollyIRBuilder &Builder; |
| 131 | ScopAnnotator &Annotator; |
| 132 | |
| 133 | IslExprBuilder ExprBuilder; |
| 134 | |
| 135 | /// Maps used by the block and region generator to demote scalars. |
| 136 | /// |
| 137 | ///@{ |
| 138 | |
| 139 | /// See BlockGenerator::ScalarMap. |
| 140 | BlockGenerator::AllocaMapTy ScalarMap; |
| 141 | |
| 142 | /// See BlockGenerator::EscapeMap. |
| 143 | BlockGenerator::EscapeUsersAllocaMapTy EscapeMap; |
| 144 | |
| 145 | ///@} |
| 146 | |
| 147 | /// The generator used to copy a basic block. |
| 148 | BlockGenerator BlockGen; |
| 149 | |
| 150 | /// The generator used to copy a non-affine region. |
| 151 | RegionGenerator RegionGen; |
| 152 | |
| 153 | const DataLayout &DL; |
| 154 | LoopInfo &LI; |
| 155 | ScalarEvolution &SE; |
| 156 | DominatorTree &DT; |
| 157 | BasicBlock *StartBlock; |
| 158 | |
| 159 | /// The current iteration of out-of-scop loops |
| 160 | /// |
| 161 | /// This map provides for a given loop a llvm::Value that contains the current |
| 162 | /// loop iteration. |
| 163 | MapVector<const Loop *, const SCEV *> OutsideLoopIterations; |
| 164 | |
| 165 | // This maps an isl_id* to the Value* it has in the generated program. For now |
| 166 | // on, the only isl_ids that are stored here are the newly calculated loop |
| 167 | // ivs. |
| 168 | IslExprBuilder::IDToValueTy IDToValue; |
| 169 | |
| 170 | /// A collection of all parallel subfunctions that have been created. |
| 171 | SmallVector<Function *, 8> ParallelSubfunctions; |
| 172 | |
| 173 | /// Generate code for a given SCEV* |
| 174 | /// |
| 175 | /// This function generates code for a given SCEV expression. It generated |
| 176 | /// code is emitted at the end of the basic block our Builder currently |
| 177 | /// points to and the resulting value is returned. |
| 178 | /// |
| 179 | /// @param Expr The expression to code generate. |
| 180 | Value *generateSCEV(const SCEV *Expr); |
| 181 | |
| 182 | /// A set of Value -> Value remappings to apply when generating new code. |
| 183 | /// |
| 184 | /// When generating new code for a ScopStmt this map is used to map certain |
| 185 | /// llvm::Values to new llvm::Values. |
| 186 | ValueMapT ValueMap; |
| 187 | |
| 188 | /// Materialize code for @p Id if it was not done before. |
| 189 | /// |
| 190 | /// @returns False, iff a problem occurred and the value was not materialized. |
| 191 | bool materializeValue(__isl_take isl_id *Id); |
| 192 | |
| 193 | /// Materialize parameters of @p Set. |
| 194 | /// |
| 195 | /// @returns False, iff a problem occurred and the value was not materialized. |
| 196 | bool materializeParameters(__isl_take isl_set *Set); |
| 197 | |
| 198 | /// Materialize all parameters in the current scop. |
| 199 | /// |
| 200 | /// @returns False, iff a problem occurred and the value was not materialized. |
| 201 | bool materializeParameters(); |
| 202 | |
| 203 | // Extract the upper bound of this loop |
| 204 | // |
| 205 | // The isl code generation can generate arbitrary expressions to check if the |
| 206 | // upper bound of a loop is reached, but it provides an option to enforce |
| 207 | // 'atomic' upper bounds. An 'atomic upper bound is always of the form |
| 208 | // iv <= expr, where expr is an (arbitrary) expression not containing iv. |
| 209 | // |
| 210 | // This function extracts 'atomic' upper bounds. Polly, in general, requires |
| 211 | // atomic upper bounds for the following reasons: |
| 212 | // |
| 213 | // 1. An atomic upper bound is loop invariant |
| 214 | // |
| 215 | // It must not be calculated at each loop iteration and can often even be |
| 216 | // hoisted out further by the loop invariant code motion. |
| 217 | // |
| 218 | // 2. OpenMP needs a loop invariant upper bound to calculate the number |
| 219 | // of loop iterations. |
| 220 | // |
| 221 | // 3. With the existing code, upper bounds have been easier to implement. |
| 222 | isl::ast_expr getUpperBound(isl::ast_node For, CmpInst::Predicate &Predicate); |
| 223 | |
| 224 | /// Return non-negative number of iterations in case of the following form |
| 225 | /// of a loop and -1 otherwise. |
| 226 | /// |
| 227 | /// for (i = 0; i <= NumIter; i++) { |
| 228 | /// loop body; |
| 229 | /// } |
| 230 | /// |
| 231 | /// NumIter is a non-negative integer value. Condition can have |
| 232 | /// isl_ast_op_lt type. |
| 233 | int getNumberOfIterations(isl::ast_node For); |
| 234 | |
| 235 | /// Compute the values and loops referenced in this subtree. |
| 236 | /// |
| 237 | /// This function looks at all ScopStmts scheduled below the provided For node |
| 238 | /// and finds the llvm::Value[s] and llvm::Loops[s] which are referenced but |
| 239 | /// not locally defined. |
| 240 | /// |
| 241 | /// Values that can be synthesized or that are available as globals are |
| 242 | /// considered locally defined. |
| 243 | /// |
| 244 | /// Loops that contain the scop or that are part of the scop are considered |
| 245 | /// locally defined. Loops that are before the scop, but do not contain the |
| 246 | /// scop itself are considered not locally defined. |
| 247 | /// |
| 248 | /// @param For The node defining the subtree. |
| 249 | /// @param Values A vector that will be filled with the Values referenced in |
| 250 | /// this subtree. |
| 251 | /// @param Loops A vector that will be filled with the Loops referenced in |
| 252 | /// this subtree. |
| 253 | void getReferencesInSubtree(__isl_keep isl_ast_node *For, |
| 254 | SetVector<Value *> &Values, |
| 255 | SetVector<const Loop *> &Loops); |
| 256 | |
| 257 | /// Change the llvm::Value(s) used for code generation. |
| 258 | /// |
| 259 | /// When generating code certain values (e.g., references to induction |
| 260 | /// variables or array base pointers) in the original code may be replaced by |
| 261 | /// new values. This function allows to (partially) update the set of values |
| 262 | /// used. A typical use case for this function is the case when we continue |
| 263 | /// code generation in a subfunction/kernel function and need to explicitly |
| 264 | /// pass down certain values. |
| 265 | /// |
| 266 | /// @param NewValues A map that maps certain llvm::Values to new llvm::Values. |
| 267 | void updateValues(ValueMapT &NewValues); |
| 268 | |
| 269 | /// Return the most up-to-date version of the llvm::Value for code generation. |
| 270 | /// @param Original The Value to check for an up to date version. |
| 271 | /// @returns A remapped `Value` from ValueMap, or `Original` if no mapping |
| 272 | /// exists. |
| 273 | /// @see IslNodeBuilder::updateValues |
| 274 | /// @see IslNodeBuilder::ValueMap |
| 275 | Value *getLatestValue(Value *Original) const; |
| 276 | |
| 277 | /// Generate code for a marker now. |
| 278 | /// |
| 279 | /// For mark nodes with an unknown name, we just forward the code generation |
| 280 | /// to its child. This is currently the only behavior implemented, as there is |
| 281 | /// currently not special handling for marker nodes implemented. |
| 282 | /// |
| 283 | /// @param Mark The node we generate code for. |
| 284 | virtual void createMark(__isl_take isl_ast_node *Marker); |
| 285 | |
| 286 | virtual void createFor(__isl_take isl_ast_node *For); |
| 287 | |
| 288 | /// Set to remember materialized invariant loads. |
| 289 | /// |
| 290 | /// An invariant load is identified by its pointer (the SCEV) and its type. |
| 291 | SmallSet<std::pair<const SCEV *, Type *>, 16> PreloadedPtrs; |
| 292 | |
| 293 | /// Preload the memory access at @p AccessRange with @p Build. |
| 294 | /// |
| 295 | /// @returns The preloaded value casted to type @p Ty |
| 296 | Value *preloadUnconditionally(__isl_take isl_set *AccessRange, |
| 297 | isl_ast_build *Build, Instruction *AccInst); |
| 298 | |
| 299 | /// Preload the memory load access @p MA. |
| 300 | /// |
| 301 | /// If @p MA is not always executed it will be conditionally loaded and |
| 302 | /// merged with undef from the same type. Hence, if @p MA is executed only |
| 303 | /// under condition C then the preload code will look like this: |
| 304 | /// |
| 305 | /// MA_preload = undef; |
| 306 | /// if (C) |
| 307 | /// MA_preload = load MA; |
| 308 | /// use MA_preload |
| 309 | Value *preloadInvariantLoad(const MemoryAccess &MA, |
| 310 | __isl_take isl_set *Domain); |
| 311 | |
| 312 | /// Preload the invariant access equivalence class @p IAClass |
| 313 | /// |
| 314 | /// This function will preload the representing load from @p IAClass and |
| 315 | /// map all members of @p IAClass to that preloaded value, potentially casted |
| 316 | /// to the required type. |
| 317 | /// |
| 318 | /// @returns False, iff a problem occurred and the load was not preloaded. |
| 319 | bool preloadInvariantEquivClass(InvariantEquivClassTy &IAClass); |
| 320 | |
| 321 | void createForVector(__isl_take isl_ast_node *For, int VectorWidth); |
| 322 | void createForSequential(isl::ast_node For, bool MarkParallel); |
| 323 | |
| 324 | /// Create LLVM-IR that executes a for node thread parallel. |
| 325 | /// |
| 326 | /// @param For The FOR isl_ast_node for which code is generated. |
| 327 | void createForParallel(__isl_take isl_ast_node *For); |
| 328 | |
| 329 | /// Create new access functions for modified memory accesses. |
| 330 | /// |
| 331 | /// In case the access function of one of the memory references in the Stmt |
| 332 | /// has been modified, we generate a new isl_ast_expr that reflects the |
| 333 | /// newly modified access function and return a map that maps from the |
| 334 | /// individual memory references in the statement (identified by their id) |
| 335 | /// to these newly generated ast expressions. |
| 336 | /// |
| 337 | /// @param Stmt The statement for which to (possibly) generate new access |
| 338 | /// functions. |
| 339 | /// @param Node The ast node corresponding to the statement for us to extract |
| 340 | /// the local schedule from. |
| 341 | /// @return A new hash table that contains remappings from memory ids to new |
| 342 | /// access expressions. |
| 343 | __isl_give isl_id_to_ast_expr * |
| 344 | createNewAccesses(ScopStmt *Stmt, __isl_keep isl_ast_node *Node); |
| 345 | |
| 346 | /// Generate LLVM-IR that computes the values of the original induction |
| 347 | /// variables in function of the newly generated loop induction variables. |
| 348 | /// |
| 349 | /// Example: |
| 350 | /// |
| 351 | /// // Original |
| 352 | /// for i |
| 353 | /// for j |
| 354 | /// S(i) |
| 355 | /// |
| 356 | /// Schedule: [i,j] -> [i+j, j] |
| 357 | /// |
| 358 | /// // New |
| 359 | /// for c0 |
| 360 | /// for c1 |
| 361 | /// S(c0 - c1, c1) |
| 362 | /// |
| 363 | /// Assuming the original code consists of two loops which are |
| 364 | /// transformed according to a schedule [i,j] -> [c0=i+j,c1=j]. The resulting |
| 365 | /// ast models the original statement as a call expression where each argument |
| 366 | /// is an expression that computes the old induction variables from the new |
| 367 | /// ones, ordered such that the first argument computes the value of induction |
| 368 | /// variable that was outermost in the original code. |
| 369 | /// |
| 370 | /// @param Expr The call expression that represents the statement. |
| 371 | /// @param Stmt The statement that is called. |
| 372 | /// @param LTS The loop to SCEV map in which the mapping from the original |
| 373 | /// loop to a SCEV representing the new loop iv is added. This |
| 374 | /// mapping does not require an explicit induction variable. |
| 375 | /// Instead, we think in terms of an implicit induction variable |
| 376 | /// that counts the number of times a loop is executed. For each |
| 377 | /// original loop this count, expressed in function of the new |
| 378 | /// induction variables, is added to the LTS map. |
| 379 | void createSubstitutions(__isl_take isl_ast_expr *Expr, ScopStmt *Stmt, |
| 380 | LoopToScevMapT <S); |
| 381 | void createSubstitutionsVector(__isl_take isl_ast_expr *Expr, ScopStmt *Stmt, |
| 382 | std::vector<LoopToScevMapT> &VLTS, |
| 383 | std::vector<Value *> &IVS, |
| 384 | __isl_take isl_id *IteratorID); |
| 385 | virtual void createIf(__isl_take isl_ast_node *If); |
| 386 | void createUserVector(__isl_take isl_ast_node *User, |
| 387 | std::vector<Value *> &IVS, |
| 388 | __isl_take isl_id *IteratorID, |
| 389 | __isl_take isl_union_map *Schedule); |
| 390 | virtual void createUser(__isl_take isl_ast_node *User); |
| 391 | virtual void createBlock(__isl_take isl_ast_node *Block); |
| 392 | |
| 393 | /// Get the schedule for a given AST node. |
| 394 | /// |
| 395 | /// This information is used to reason about parallelism of loops or the |
| 396 | /// locality of memory accesses under a given schedule. |
| 397 | /// |
| 398 | /// @param Node The node we want to obtain the schedule for. |
| 399 | /// @return Return an isl_union_map that maps from the statements executed |
| 400 | /// below this ast node to the scheduling vectors used to enumerate |
| 401 | /// them. |
| 402 | /// |
| 403 | virtual __isl_give isl_union_map * |
| 404 | getScheduleForAstNode(__isl_take isl_ast_node *Node); |
| 405 | |
| 406 | private: |
| 407 | /// Create code for a copy statement. |
| 408 | /// |
| 409 | /// A copy statement is expected to have one read memory access and one write |
| 410 | /// memory access (in this very order). Data is loaded from the location |
| 411 | /// described by the read memory access and written to the location described |
| 412 | /// by the write memory access. @p NewAccesses contains for each access |
| 413 | /// the isl ast expression that describes the location accessed. |
| 414 | /// |
| 415 | /// @param Stmt The copy statement that contains the accesses. |
| 416 | /// @param NewAccesses The hash table that contains remappings from memory |
| 417 | /// ids to new access expressions. |
| 418 | void generateCopyStmt(ScopStmt *Stmt, |
| 419 | __isl_keep isl_id_to_ast_expr *NewAccesses); |
| 420 | |
| 421 | /// Materialize a canonical loop induction variable for `L`, which is a loop |
| 422 | /// that is *not* present in the Scop. |
| 423 | /// |
| 424 | /// Note that this is materialized at the point where the `Builder` is |
| 425 | /// currently pointing. |
| 426 | /// We also populate the `OutsideLoopIterations` map with `L`s SCEV to keep |
| 427 | /// track of the induction variable. |
| 428 | /// See [Code generation of induction variables of loops outside Scops] |
| 429 | Value *materializeNonScopLoopInductionVariable(const Loop *L); |
| 430 | }; |
| 431 | |
| 432 | #endif // POLLY_ISLNODEBUILDER_H |