[polly] r243410 - Extend documentation of scalar code generation [NFC]

Tobias Grosser tobias at grosser.es
Tue Jul 28 05:12:04 PDT 2015


Author: grosser
Date: Tue Jul 28 07:12:04 2015
New Revision: 243410

URL: http://llvm.org/viewvc/llvm-project?rev=243410&view=rev
Log:
Extend documentation of scalar code generation [NFC]

No functional change intended

--
Reviewers: jdoerfert

Projects: #polly

Differential Revision: http://reviews.llvm.org/D11536

Modified:
    polly/trunk/include/polly/CodeGen/BlockGenerators.h

Modified: polly/trunk/include/polly/CodeGen/BlockGenerators.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/include/polly/CodeGen/BlockGenerators.h?rev=243410&r1=243409&r2=243410&view=diff
==============================================================================
--- polly/trunk/include/polly/CodeGen/BlockGenerators.h (original)
+++ polly/trunk/include/polly/CodeGen/BlockGenerators.h Tue Jul 28 07:12:04 2015
@@ -136,31 +136,129 @@ protected:
 
   /// @brief Maps to resolve scalar dependences for PHI operands and scalars.
   ///
-  /// Usage example:
+  /// When translating code that contains scalar dependences as they result from
+  /// inter-block scalar dependences (including the use of data carrying
+  /// PHI nodes), we do not directly regenerate in-register SSA code, but
+  /// instead allocate some stack memory through which these scalar values are
+  /// passed. Only a later pass of -mem2reg will then (re)introduce in-register
+  /// computations.
   ///
-  ///  x1 = ...   // x1 will be inserted in the ScalarMap and PhiOpMap.
-  ///  for (i=0...N) {
-  ///      x2 = phi(x1, add) // x2 will be inserted in the ScalarMap, x1 and
-  ///                        // add are mapped in the PHIOpMap.
-  ///      add = x2 + A[i];  // add will be inserted in the ScalarMap and
-  ///                        // the PhiOpMap.
-  ///  }
-  ///  print(x1)  // x1 is mapped in the ScalarMap.
-  ///  print(x2)  // x2 is mapped in the ScalarMap.
-  ///  print(add) // add is mapped in the ScalarMap.
+  /// To keep track of the memory location(s) used to store the data computed by
+  /// a given SSA instruction, we use the maps 'ScalarMap' and 'PHIOpMap'. Each
+  /// maps a given scalar value to a junk of stack allocated memory.
+  ///
+  /// 'ScalarMap' is used for normal scalar dependences that go from a scalar
+  /// definition to its use. Such dependences are lowered by directly writing
+  /// the value an instruction computes into the corresponding chunk of memory
+  /// and reading it back from this chunk of memory right before every use of
+  /// this original scalar value. The memory locations in 'ScalarMap' end with
+  /// '.s2a'.
+  ///
+  /// 'PHIOpMap' is used to model PHI nodes. For each PHI nodes we introduce,
+  /// besides the memory in 'ScalarMap', a second chunk of memory into which we
+  /// write at the end of each basic block preceeding the PHI instruction the
+  /// value passed through this basic block. At the place where the PHI node is
+  /// executed, we replace the PHI node with a load from the corresponding
+  /// memory location in the 'PHIOpMap' table. The memory locations in
+  /// 'PHIOpMap' end with '.phiops'.
+  ///
+  /// An access to/from memory that belongs to a PHI node is in the ScopInfo
+  /// always modeled with the name of the PHI node. However, in reality PHI
+  /// nodes can introduce reads/writes to two different memory locations, the
+  /// normal '.s2a' locations and the special '.phiops' locations. We do not
+  /// track this difference in the polyhedral description, but only through
+  /// the content of the two maps 'ScalarMap' and 'PHIOpMap'.
+  ///
+  /// Example:
+  ///
+  ///                              Input C Code
+  ///                              ============
+  ///
+  ///                 S1:      x1 = ...
+  ///                          for (i=0...N) {
+  ///                 S2:           x2 = phi(x1, add)
+  ///                 S3:           add = x2 + 42;
+  ///                          }
+  ///                 S4:      print(x1)
+  ///                          print(x2)
+  ///                          print(add)
+  ///
+  ///
+  ///        Unmodified IR                         IR After expansion
+  ///        =============                         ==================
+  ///
+  /// S1:   x1 = ...                     S1:    x1 = ...
+  ///                                           x1.s2a = s1
+  ///                                           x2.phiops = s1
+  ///        |                                    |
+  ///        |   <--<--<--<--<                    |   <--<--<--<--<
+  ///        | /              \                   | /              \
+  ///        V V               \                  V V               \
+  /// S2:  x2 = phi (x1, add)   |        S2:    x2 = x2.phiops       |
+  ///                           |               x2.s2a = x2          |
+  ///                           |                                    |
+  /// S3:  add = x2 + 42        |        S3:    add = x2 + 42        |
+  ///                           |               add.s2a = add        |
+  ///                           |               x2.phiops = add      |
+  ///        | \               /                  | \               /
+  ///        |  \             /                   |  \             /
+  ///        |   >-->-->-->-->                    |   >-->-->-->-->
+  ///        V                                    V
+  ///
+  ///                                    S4:    x1 = x1.s2a
+  /// S4:  ... = x1                             ... = x1
+  ///                                           x2 = x2.s2a
+  ///      ... = x2                             ... = x2
+  ///                                           add = add.s2a
+  ///      ... = add                            ... = add
+  ///
+  ///      ScalarMap = { x1 -> x1.s2a, x2 -> x2.s2a, add -> add.s2a }
+  ///      PHIOpMap =  { x2 -> x2.phiops }
+  ///
+  ///
+  ///  ??? Why does a PHI-node require two memory chunks ???
+  ///
+  ///  One may wonder why a PHI node requires two memory chunks and not just
+  ///  all data is stored in a single location. The following example tries
+  ///  to store all data in .s2a and drops the .phiops location:
+  ///
+  ///      S1:    x1 = ...
+  ///             x1.s2a = s1
+  ///             x2.s2a = s1             // use .s2a instead of .phiops
+  ///               |
+  ///               |   <--<--<--<--<
+  ///               | /              \
+  ///               V V               \
+  ///      S2:    x2 = x2.s2a          |  // value is same as above, but read
+  ///                                  |  // from .s2a
+  ///                                  |
+  ///             x2.s2a = x2          |  // store into .s2a as normal
+  ///                                  |
+  ///      S3:    add = x2 + 42        |
+  ///             add.s2a = add        |
+  ///             x2.s2a = add         |  // use s2a instead of .phiops
+  ///               | \               /   // !!! This is wrong, as x2.s2a now
+  ///               |   >-->-->-->-->     // contains add instead of x2.
+  ///               V
+  ///
+  ///      S4:    x1 = x1.s2a
+  ///             ... = x1
+  ///             x2 = x2.s2a             // !!! We now read 'add' instead of
+  ///             ... = x2                // 'x2'
+  ///             add = add.s2a
+  ///             ... = add
+  ///
+  ///  As visible in the example, the SSA value of the PHI node may still be
+  ///  needed _after_ the basic block, which could conceptually branch to the
+  ///  PHI node, has been run and has overwritten the PHI's old value. Hence, a
+  ///  single memory location is not enough to code-generate a PHI node.
   ///
   ///{
-
-  /// The PHIOpMap is used to get the alloca to communicate a value to a PHI
-  /// node, hence when the operand of a PHI is demoted the corresponding write
-  /// access will use the PHIOpMap to look for the correct alloca. PHI nodes
-  /// will then read that location in order to get the correct/current operand
-  /// value.
+  ///
+  /// @brief Memory locations used for the special PHI node modeling.
   ScalarAllocaMapTy &PHIOpMap;
 
-  /// The ScalarMap is used in __all__ other cases, thus always when a scalar
-  /// variable is read/written and the write is not because the scalar is a PHI
-  /// operand.
+  /// @brief Memory locations used to model scalar dependences.
   ScalarAllocaMapTy &ScalarMap;
   ///}
 





More information about the llvm-commits mailing list