Man page for porky.1
Table of Contents


porky - do assorted code transformations


porky [ options ] infile outfile { infile outfile } *


The porky program makes various transformations to the SUIF code. Command line options specify which transformations are performed. These options fall into two broad catagories. The first catagory is transformations to subsets of SUIF. The purpose of each such transformation is to allow subsequent passes to make simplifying assumptions, such as the assumption that there are no branches into a loop body. The other catagory of transformations is those that try to rearrange the code to make it easier for subsequent passes to get information, but don't get rid of any particular constructs. For example, the -forward-prop transformation tries to move as much computation as possible into the bound expressions of each loop but can't guarantee any particular nice form for the results.

This pass expects two or more file specifications on the command line, paired into input and then output files. For each input file, there must be a corresponding output file. If more than one input/output pair is specified, all the input files must have had their global symbol table information merged so that they can form a single file set (see the documentation for the linksuif pass). The output files will also have merged global symbol table information.

In addition to the file specifications, there can be any number of options given on the command line. All options begin with -. If no options at all are given, the SUIF file will simply be read and written back again without any transformations being performed.


-V n This sets the the verbosity level to the integer n. The default is verbosity level 0. At higher verbosity levels, more comments will be written to standard output about what porky is doing. Verbosity levels above three have the same effect as level three.

This tells porky to look at the suif file in Fortran mode to see call-by-reference variables. For some kinds of analysis, such as that required for forward propagation (the -forward-prop option), this gives porky more information, so it can do a better job. It is illegal to specify this option if the source of the SUIF code was not Fortran.

This flag says to keep doing all the specified optimizations as long as any of them make progress.

-max-iters n
This sets the maximum number of iterations done by the -iterate option to the integer n. The default is to have no limit on the number of iterations.

This option only affects the -cse, -loop-invariants, and -fredloop-invariants options. It says not to consider references to global variables as loads for the purposes of common sub-expression elimination and loop-invariant moving. The default is to essentially consider all references to global variables as loads, so multiple dynamic references to the same global variable will, if possible, be changed to a read of the global variable into a local followed by multiple references to the local variable.


This dismantles all TREE_FORs.

This dismantles all TREE_LOOPs.

This dismantles all TREE_IFs.

This dismantles all TREE_BLOCKs.

This dismantles all SUIF array instructions.

This dismantles all mbr (multi-way branch) instructions.

This dismantles all min instructions.

This dismantles all max instructions.

This dismantles all abs (absolute value) instructions.

This dismantles all divfloor instructions.

This dismantles all divceil instructions.

This dismantles all mod instructions.

This dismantles all integer min instructions.

This dismantles all integer max instructions.

This dismantles all integer abs instructions.

This dismantles all SUIF divfloor, divceil, min, max, abs, and mod instructions. This must be done before mexp/mgen as that back end can't handle these instructions. It is equivalent to each of

-Ddivfloor, -Ddivceil, -Dmin, -Dmax, -Dabss, and -Dmods.

This dismantles all SUIF divfloor and divceil instructions, and also all integer min, max, and abs instructions. This must be done before the Iwarp software pipeliner because that can handle floating point min, max, and abs instructions but not divfloor and divceil or integer versions of min, max, and abs. It is equivalent to each of -Ddivfloor, -Ddivceil, -Dimin, -Dimax, and -Diabss.

This does the default options to be used right after the front end, to turn some non-standard SUIF that the front end produces into standard SUIF. It also does some things, like constant folding and removing empty symbol tables, to make the code as simple as possible without losing information. It is equivalent to all of the options -fixbad, -for-bound, -no-index-mod, -no-empty-fors, -noempty-table, -control-simp, and -fold.

This fixes ``bad'' nodes. This is used as part of the default expansion after the front end. Many analysis passes count on the simplifying assumptions about control flow that they can make after this pass.

The effects are as follows:

* Any jump or branch from inside a TREE_FOR or TREE_LOOP to a label immediately following the TREE_FOR or TREE_LOOP (i.e. no intervening instructions that might do anything) are changed to use as its target the break label of that TREE_FOR or TREE_LOOP. This will save some nodes from being dismantled because they will contain branches to break labels instead of arbitrary outside labels.

* TREE_FOR nodes with GELE comparison are broken into two TREE_FORs and a TREE_IF to decide between them.

* Any TREE_FOR, TREE_LOOP, or TREE_IF node containing a branch or jump, or the target label used by a branch or jump, is entirely dismantled, unless both the branch or jump and all its possible targets are within the same instruction list. ``Contains'' in this case means at any level down in nested sub-lists. There is also an exception for branches or jumps to labels that are defined as part of the parent node, such as ``continue'' or ``break'' nodes for loops and fors and the targets such as toplab() and jumpto() used as part of the test code in TREE_IF and TREE_LOOP nodes. Note that this applies only to the immediate children of the node defining such a label; if TREE_LOOP A contains TREE_LOOP B and within B's body there is a jump to the ``continue'' label of A, then B will be dismantled but A will not.

* Any FOR with a test of ``equal to'' or ``not equal to'' is dismantled and a warning message is printed.

This has the same effect as -fixbad except that it uses a stricter definition of ``bad''. In this case, any node containing a jump or branch, or possible target of a jump or branch, is dismantled, even if they are both within the same instruction list. There are only two exceptions: jumps/branches to the toplab() label of a TREE_LOOP from nodes in the test part of that TREE_LOOP; and jumps/branches to the jumpto() label of a TREE_IF from nodes in the header part of that TREE_IF. These only apply to nodes in the first level test or header list, not to nested sub-lists. These two exceptions reflect the fact that TREE_LOOP test parts and TREE_IF header parts are supposed to have potential jumps to these labels and only degenerate cases wouldn't have them.

This dismantles TREE_FORs unless porky can tell that the upper bound and step are both loop constants.

This dismantles TREE_FORs with a spilled index variable.

This dismantles TREE_FORs for which the index variable might be modified by the TREE_FOR body.

This dismantles TREE_FORs with empty bodies.

This takes any calls that are within expression trees out of the expression trees and creates new local variables for them to write their results into, then substitutes a reference to that local variable in the expression tree.

This dismantles all TREE_BLOCKs that have empty symbol tables.


This puts the correct types on all ldc (load constant) instructions that load symbol addresses. This is needed after the front end because parts of the types of symbols may be completed only after a procedure that references the symbol is written out. For example, p might be declared ``extern char p[]'', then used in various procedures, then later defined ``char p[30]''. The complete type information isn't needed at the earlier stage, but in SUIF we must use one symbol and use it consistently, so the symbol's type must change to the completed type. At that point any ldc instructions already written will have the wrong type and must be fixed up by this pass.

This gets rid of all structure copies, whether through copy instructions, load-store pairs, or memcopy instructions. They are replaced with memcopies of integer sized chunks that cover all the bits of the structure. This option is useful before a RISC back end, so that it doesn't have to generate code for multi-word moves.

This removes all sub-variables and replaces uses of them with uses of their root ancestors, with the appropriate offsets.

This changes all static local variables into global variables in the file symbol table. It will do this unconditionally to all static locals, so after this pass there will no longer be any static locals. Both the variable and its var_def will be moved. If any annotations on the var_sym or var_def refer to anything not visible in the file symbol table (other than static locals that will soon be moved to the file symbol table), or operands or instructions, such annotations will be deleted. If the type of the static local is not visible in the file symbol table, its type will be changed to the nearest approximation to that type which can be made in the file symbol table and all uses of the symbol will be changed to include casts to the original type.

-array-glob cutoff-size
This makes all statically allocated arrays with size greater than cutoff-size and type visible in the inter-file global symbol table into globals with inter-file scope (external linkage). That is, it will move static local arrays and arrays with file scope that meet the size limit into the inter-file global symbol table. The variables are renamed if necessary to avoid conflict with existing global symbols. Note that to be safe this pass should only be run on code that has been linksuif `ed with all other source files to make sure all global namespace conflicts are discovered. The motivating use for this pass is to make all arrays visible to the object-level linker so that array alignment specifications given to the linker will apply to all possible arrays. This allows chache-line alignment of arrays when alignment specifications cannot be given to a back-end C compiler.

This changes the behavior of the -array-glob flag to affect automatic local arrays as well as static local arrays, provided there is a guarantee of no recursion, by way of the ``no recursion'' annotation.

This adds ``if'' nodes around some tree_for nodes to insure that whenever any tree_if node is executed, at the landing pad and first iteration will always be executed. Any tree_for nodes that already have "guarded" annotations will be unaffected because this condition is already guaranteed. All tree_for nodes end up with "guarded" annotations after this pass is done. This pass also empties out the landing pads of tree_fors -- after they are guarded, it is legal to simply move the landing pad in front of the tree_for, so this pass does so.


This folds constants wherever possible.

This tries to reassociate the result of any arrays that are dismantled so that the dependence on the index variable of the nearest enclosing TREE_FOR is a simple linear expression, if possible. Since arrays are dismantled only if the -Darrays option is used, there is no effect if -Darrays is not specified.

This simplifies TREE_IFs for which this pass can tell that one branch or the other always executes, leaving only the instructions from the branch that executes and any parts of the test section that might have side effects. It also removes entirely any TREE_FORs which it can tell will never be executed.

This forward propagates the calculation of local variables into uses of those variables when possible. The idea is to give more information about loop bounds and array indexing for doing dependence analysis and loop transformations, or generally to any pass doing analysis.

This does copy propagation, which is the same as forward propagation limited to expressions that are simple local variables (i.e. if there is a simple copy from one local variable into another, uses of the source variable will replace the destination variable where the copy is live).

This does simple constant propagation.

This does simple induction variable detection. It replaces the uses of the induction variable within the loop by expressions of the loop index and moves the incrementing of the induction variable outside the loop.

This finds simple instances of reduction. It moves the summation out of the loop.

This puts mod/ref annotations on TREE_FORs. It assumes that the address of a symbol is never stored anywhere, which is valid for Fortran, but usually not for C.

This privatizes all variables listed in the annotation "privatizable" on each TREE_FOR.

This turns local array variables into collections of element variables when all uses of the array are loads or stores of known elements. It will partly scalarize multi-dimensional arrays if they can be scalarized in some but not all dimensions.

This replaces comparisons of upper and lower bounds of a loop inside the loop body with the known result of that comparison. This is particularly useful after multi-level induction variables have been replaced.

-cse This does simple common sub-expression elimination.

This does simple dead-code elimination.

This removes symbols that are never referenced and have no external linkage, or that have external linkage but are not defined in this file (i.e. no procedure body or var_def). Static procedures that are never referenced but have bodies will be removed, but only if this pass is re-run, because by the time porky figures out that it is safe to delete a procedure, it will already have been written. The ``-iter'' option does not help this problem, because that iterates within procedures, not across all procedures; porky cannot iterate on the entire file because it keeps only one procedure in memory at a time.

This removes types that are never referenced.

This moves the calculation of loop-invariant expressions outside loop bodies.

This is the same as the -loop-invariants flag except that it only considers moving instructions marked with the "Fred" annotation.

This combines local variables that are used only as single bits (i.e. assigned only one, zero, or the value of another bit variable, and are never addressed), packing them together into variables of type ``unsigned int'' and using bitwise operations to set and extract the appropriate bits. This can be useful in some cases if it allows register allocation of the packed bits, though in other cases the cost associated with the bitwise operations will outweigh the savings.

This moves certain ``if'' nodes up in the code under some cirumstances that can allow the test for the if to be eliminated. The ``if'' nodes that are candidates to be hoisted are those that have a condition depending on only a single variable. If that is the case, and in the code preceeding the ``if'' (on the same tree_node_list) there is another ``if'' which assigns a constant to the value of that condition variable in either the ``then'' or ``else'' part, this will duplicate the original ``if'' node and put it in both the ``then'' and ``else'' parts of the higher ``if'' node, if this is legal. This is useful for code which has ``chains'' of ``if'' nodes; that is, the body of one sets a variable that is used as a test in a later ``if''. After hoisting, the constant value can often be propagated into the condition in one of the branches of the ``if''. In simple cases where the flag is cleared before the higher ``if'' and then set only in one of its branches, the test can be eliminated in both parts.

Do some code transformations to help with privatization of global variables across calls. It looks for ``possible global privatizable'' annotations on proc_syms. In each such annotation it expects to find a list of global variables. It changes the code so that a new parameter is added to the procedure for each symbol in the annotation, and all uses of the symbol are replaced by indirect references through the new parameter, and at callsites the location of that symbol is passed. If the procedure is a Fortran procedure, the new parameter is a call-by-ref parameter. It arranges for this to work through arbitrary call graphs of procedures. The result is code that has the same semantics but in which the globals listed in each of these annotations are never referenced directly, but instead a location to use is passed as a parameter. If the annotations are put on the input code properly, this allows privatization of global variables to be done as if the globals were local.

Add array reference instructions in place of pointer arithmetic where possible. This helps dependence analysis of programs that were originally written in C, for example.

Normalize all ``for'' loops to have lower bound of zero, step size of one, and ``less than or equal to'' test.

Do simple optimizations on unstructured control flow (branches and labels). The optimizations are done simultaneously in such a way that the result cannot benefit from any more of these optimizations

-- the output run through this pass again will not change.
The following optimizations are performed:

* Labels that are not the target of any possible branch are removed.

* Uses of labels that are followed by unconditional jumps or other labels without any intervening executable code are changed to uses of the last label that must always be executed before some executable code, and those labels are removed.

* Unreachable code is removed.

* Branches that would end up in the same place before any code is executed as they would if they were not taken are removed.

* Conditional branches followed in the code by unconditional branches without any intervening executable code, followed without any intervening executable code by the label that is the target of the conditional branch, are changed to reverse the condition, change its target to that of the unconditional branch, and remove the conditional branch. That is,

if (cond)
goto L1;
goto L2;

is replaced by

if (!cond)
goto L2;

(and L1 is removed if it is not a target of some other instruction).

Replace call-by-reference scalar variables with copy-in, copy-out. This is useful when a later pass, such as a back-end compiler after s2c will not have access to call-by-ref form. Instead of seeing pointer references that might alias with anything, this will allow the pass to see a local variable. Note that without the ``fortran'' flag, this pass has no effect because without the ``fortran'' flag, porky won't see anything in call-by-ref form to begin with.

Move all loop-invariant conditionals that are inside a TREE_LOOP or TREE_FOR outside the outermost loop.

This turns array references with constant indexes that point to array elements that exactly overlap scalar variables with the same type (through the sub-variable mechanism) into uses of those scalar variables.

This removes all mark instructions that contain nothing but line information that is followed immediately by another line information mark.

This attempts to turn non-perfectly nested loop nests into perfectly nested loop nests by pulling conditionals as far out as possible. This is particularly useful for pulling out loop guarding expressions to restore nests that were originally perfectly nested.


The original expander was written and maintained for the old SUIF system by Michael Wolf. Chris Wilson rewrote this expander for the present SUIF system and added the other features to create porky.

Table of Contents