430 likes | 444 Views
Explore the importance of loop transformations, such as dependence testing and loop normalization, in optimizing code for better performance and accuracy. Learn about applying induction-variable substitution, constant propagation, and dead code elimination to enhance code efficiency. Understand the definition-use graph and its role in identifying and eliminating dead code. Discover the benefits of constant propagation and static single-assignment in improving algorithm performance.
E N D
Chapter 4 of Allen and Kennedy Preliminary Transformations
Overview • Why do we need this? • Requirements of dependence testing • Stride 1 • Normalized loop • Linear subscripts • Subscripts composed of functions of loop induction variables • Higher dependence test accuracy • Easier implementation of dependence tests
Programmers optimized code Confusing to smart compilers An Example INC = 2 KI = 0 DO I = 1, 100 DO J = 1, 100 KI = KI + INC U(KI) = U(KI) + W(J) ENDDO S(I) = U(KI) ENDDO
Applying induction-variable substitution Replace references to AIV with functions of loop index An Example INC = 2 KI = 0 DO I = 1, 100 DO J = 1, 100 ! Deleted: KI = KI + INC U(KI + J*INC) = U(KI + J*INC) + W(J) ENDDO KI = KI + 100 * INC S(I) = U(KI) ENDDO
Second application of IVS Remove all references to KI An Example INC = 2 KI = 0 DO I = 1, 100 DO J = 1, 100 U(KI + (I-1)*100*INC + J*INC) = U(KI + (I-1)*100*INC + J*INC) + W(J) ENDDO ! Deleted:KI = KI + 100 * INC S(I) = U(KI + I * (100*INC)) ENDDO KI = KI + 100 * 100 * INC
Applying Constant Propagation Substitute the constants An Example INC = 2 ! Deleted: KI = 0 DO I = 1, 100 DO J = 1, 100 U(I*200 + J*2 - 200) = U(I*200 + J*2 -200) + W(J) ENDDO S(I) = U(I*200) ENDDO KI = 20000
Applying Dead Code Elimination Removes all unused code An Example DO I = 1, 100 DO J = 1, 100 U(I*200 + J*2 - 200) = U(I*200 + J*2 - 200) + W(J) ENDDO S(I) = U(I*200) ENDDO
Transformations need knowledge Loop Stride Loop-invariant quantities Constant-values assignment Usage of variables Information Requirements
Loop Normalization • Lower Bound 1 with Stride 1 • To make dependence testing as simple as possible • Serves as information gathering phase
Algorithm Procedure normalizeLoop(L0); i = a unique compiler-generated LIV S1: replace the loop header for L0 DO I = L, U, S with the adjusted loop header DO i = 1, (U – L + S) / S; S2: replace each reference to I within the loop by i * S – S + L; S3: insert a finalization assignment I = i * S – S + L; immediately after the end of the loop; end normalizeLoop; Loop Normalization
Loop Normalization • Caveat • Un-normalized: DO I = 1, M DO J = I, N A(J, I) = A(J, I - 1) + 5 ENDDO ENDDO Has a direction vector of (<,=) • Normalized: DO I = 1, M DO J = 1, N – I + 1 A(J + I – 1, I) = A(J + I – 1, I – 1) + 5 ENDDO ENDDO Has a direction vector of (<,>)
Loop Normalization • Caveat • Consider interchanging loops • (<,=) becomes (=,>) OK • (<,>) becomes (>,<) Problem • Handled by another transformation • What if the step size is symbolic? • Prohibits dependence testing • Workaround: use step size 1 • Less precise, but allow dependence testing
Definition-use Graph • Traditionally called Definition-use Chains • Provides the map of variables usage • Heavily used by the transformations
Definition-use graph is a graph that contains an edge from each definition point in the program to every possible use of the variable at run time uses(b): the set of all variables used within the block b that have no prior definitions within the block defsout(b): the set of all definitions within block b that are not killed within the block killed(b): the set of all definitions that define variables killed by other definitions within block b Definition-use Graph
Computing reaches for one block b may immediately change all other reaches including b itself since reaches(b) is an input into other reaches equations Archiving correct solutions requires simultaneously solving all individual equations There is a workaround this Definition-use Graph
Dead Code Elimination • Removes all dead code • What is Dead Code ? • Code whose results are never used in any ‘Useful statements’ • What are Useful statements ? • Are they simply output statements ? • Output statements, input statements, control flow statements, and their required statements • Makes code cleaner
Constant Propagation • Replace all variables that have constant values at runtime with those constant values
Static Single-Assignment • Reduces the number of definition-use edges • Improves performance of algorithms
Example Static Single-Assignment
Example Forward Expression Substitution DO I = 1, 100 K = I + 2 A(K) = A(K) + 5 ENDDO DO I = 1, 100 A(I+2) = A(I+2) + 5 ENDDO
Forward Expression Substitution • Need definition-use edges and control flow analysis • Need to guarantee that the definition is always executed on a loop iteration before the statement into which it is substituted • Data structure to find out if a statement S is in loop L • Test whether level-K loop containing S is equal to L
Definition: an auxiliary induction variable in a DO loop headed by DO I = LB, UB, S is any variable that can be correctly expressed as cexpr * I + iexprL at every location L where it is used in the loop, where cexpr and iexprL are expressions that do not vary in the loop, although different locations in the loop may require substitution of different values of iexprL Induction Variable Substitution
Induction Variable Substitution • Example: DO I = 1, N A(I) = B(K) + 1 K = K + 4 … D(K) = D(K) + A(I) ENDDO
Induction Variable Substitution • Induction Variable Recognition
Induction Variable Substitution • More complex example DO I = 1, N, 2 K = K + 1 A(K) = A(K) + 1 K = K + 1 A(K) = A(K) + 1 ENDDO • Alternative strategy is to recognize region invariance DO I = 1, N, 2 A(K+1) = A(K+1) + 1 K = K+1 + 1 A(K) = A(K) + 1 ENDDO
Induction Variable Substitution • Driver
IVSub without loop normalization DO I = L, U, S K = K + N … = A(K) ENDDO DO I = L, U, S … = A(K + (I – L + S) / S * N) ENDDO K = K + (U – L + S) / S * N
IVSub without loop normalization • Problem: • Inefficient code • Nonlinear subscript
IVSub with Loop Normalization I = 1 DO i = 1, (U-L+S)/S, 1 K = K + N … = A (K) I = I + 1 ENDDO
IVSub with Loop Normalization I = 1 DO i = 1, (U – L + S) / S, 1 … = A (K + i * N) ENDDO K = K + (U – L + S) / S * N I = I + (U – L + S) / S
Summary • Transformations to put more subscripts into standard form • Loop Normalization • Constant Propagation • Induction Variable Substitution • Do loop normalization before induction-variable substitution • Leave optimizations to compilers