Effective Representation of Aliases and Indirect Memory Operations in SSA Form
Total Page:16
File Type:pdf, Size:1020Kb
Effective Representation of Aliases and Indirect Memory Operations in SSA Form Fred Chow, Sun Chan, Shin-Ming Liu, Raymond Lo, Mark Streich Silicon Graphics Computer Systems 2011 N. Shoreline Blvd. Mountain View, CA 94043 Contact: Fred Chow (E-mail: [email protected], Phone: USA (415) 933-4270) Abstract. This paper addresses the problems of representing aliases and indirect memory operations in SSA form. We propose a method that prevents explosion in the number of SSA variable versions in the presence of aliases. We also present a technique that allows indirect memory operations to be globally commonized. The result is a precise and compact SSA representation based on global value numbering, called HSSA, that uniformly handles both scalar variables and indi- rect memory operations. We discuss the capabilities of the HSSA representation and present measurements that show the effects of implementing our techniques in a production global optimizer. Keywords. Aliasing, Factoring dependences, Hash tables, Indirect memory oper- ations, Program representation, Static single assignment, Value numbering. 1 Introduction The Static Single Assignment (SSA) form [CFR+91] is a popular and efficient represen- tation for performing analyses and optimizations involving scalar variables. Effective algorithms based on SSA have been developed to perform constant propagation, redun- dant computation detection, dead code elimination, induction variable recognition, and others [AWZ88, RWZ88, WZ91, Wolfe92]. But until now, SSA has only been used mostly for distinct variable names in the program. When applied to indirect variable constructs, the representation is not straight-forward, and results in added complexities in the optimization algorithms that operate on the representation [CFR+91, CG93, CCF94]. This has prevented SSA from being widely used in production compilers. In this paper, we devise a scheme that allows indirect memory operations to be rep- resented together with ordinary scalar variables in SSA form. Since indirect memory accesses also affect scalar variables due to aliasing, we start by defining notations to model the effects of aliasing for scalars in SSA form. We also describe a technique to reduce the overhead in SSA representation in the presence of aliases. Next, we intro- duce the concept of virtual variables, which model indirect memory operations as if they are scalars. We then show how virtual variables can be used to derive identical or distinct versions for indirect memory operations, effectively putting them in SSA form together with the scalar variables. This SSA representation in turn reduces the cost of analyzing the scalar variables that have aliases by taking advantage of the versioning applied to the indirect memory operations aliased with the scalar variables. We then present a method that builds a uniform SSA representation of all the scalar and indirect 254 memory operations of the program based on global value numbering, which we call the Hashed SSA representation (HSSA). The various optimizations for scalars can then automatically extend to indirect memory operations under this framework. Finally, we present measurements that show the effectiveness of our techniques in a production glo- bal optimizer that uses HSSA as its internal representation. In this paper, indirect memory operations cover both the uses of arrays and accesses to memory locations through pointers. Our method is applicable to commonly used lan- guages like C and FORTRAN. 2 SSA with Aliasing In our discussion, the source program has been translated to an intermediate representa- tion in which expressions are represented in tree form. The expression trees are associ- ated with statements that use their computed results. In SSA form, each definition of a variable is given a unique version, and different versions of the same variable can be regarded as different program variables. Each use of a variable version can only refer to a single reaching definition. When several definitions of a variable, a 1, a 2 ..... a m, reach a confluence node in the control flow graph of the pro~am, a t~ function assignment statement, a n = t~(a 1, a 2 ..... am), is inserted to merge them into the definition of a new variable version a n . Thus, the semantics of single reaching definitions is maintained. This introduction of a new variable version as the result of t~ factors use-def edges over confluence nodes, reducing the total number of use-def edges required. As a result, the use-def chain of each variable can be provided in a compact form by trivially allowing each variable to point to its single definition. One important property in SSA form is that each definition must dominate all its uses in the control flow graph of the program. Another important property in SSA form is that identical versions of the same variable must have the same value. Aliasing of a scalar variable occurs in one of four conditions: when its storage loca- tion partially overlaps another variable l, when it is pointed to by a pointer used in indi- rect memory operations, when its address is passed in a procedure call, or when it is a non-local variable that can be accessed from another procedure in a call or return. Tech- niques have been developed to analyze pointers both intra-procedurally and inter-proce- durally to provide more accurate information on what is affected by them so as to limit their ill effects on program optimizations [CWZ90, CBC93, Ruf95, WL95]. To characterize the effects of aliasing, we distinguish between two types of defini- tions of a variable: MustDefand MayDef 2 Since a MustDef must redefine the variable, it blocks the references of previous definitions from that point on. A MayDef only potentially redefines the variable, and so does not prevent previous definitions of the 1. If they exactly overlap, our representation will handle them as a single variable. 2. In [CCF94], MustDefs and MayDefs are called Killing Defs and Preserving Defs respec- tively, while in [Steen95], they are called Strong Updates and Weak Updates. 255 Original Program: SSA Representation: i 4--2 ij <---2 if(j) if(j1) \ *p +--- 3 call funcO *p ~-- 3 call funcO ".,,/ / i2~--Z(il) i3+--~(il, i2) return i return i3 Fig. 1. Example of It, X and same variable from being reterenced later in the program. On the use side, in addition to real uses of the variable, there are places in the program where there are potential refer- ences to the variable that need to be taken into account in analyzing the program. We call these potential references MayUse. To accommodate the MayDefs, we use the idea from [CCF94] in which SSA edges for the same variable are factored over its MayDefs. This is referred to as location-fac- tored SSA form in [Steen95]. We model this effect by introducing the Z assignment operator in our SSA representation. ~ links up the use-def edges through MayDefs. The operand of Z is the last version of the variable, and its result is the version after the potential definition. Thus, if variable i may be modified, we annotate the code with i 2 = )~(il) , where i I is the current version of the variable. To model MayUses, we introduce the It operator in our SSA representation, tx takes as its operand the version of the variable that may be referenced, and produces no result. Thus, if variable i may be referenced, we annotate the code with It(il), where i I is the current version of the variable. In our internal representation, expressions cannot have side effects. Memory loca- tions can only be modified by statements, which include direct and indirect store state- ments and calls. Thus, Z can only be associated with store and call statements. I.t is associated with any dereferencing operation, like the unary operator * in C, which can happen within an expression. Thus, t.t arises at both statements and expressions. We also mark return statements with It for non-local variables to represent their liveness at func- tion exits. Separating MayDefand MayUse allows us to model the effects of calls pre- cisely. For example, a call that only references a variable will only cause a I1 but no ~. For our modeling purpose, the It takes effect just before the call, and the Z takes effect right after the call. Figure 1 gives an example of the use of Ix, ;~ together with ~ in our SSA representation. In the example, functionfunc uses but does not modify variable i. The inclusion of It and Z in the SSA form does not impact the complexity of the algorithm that computes SSA form. A pre-pass inserts unnamed It's and X~ for the 256 aliased variables at the points of aliases in the program. In applying the SSA creation algorithm described in [CFR+91 ], the operands of the ~t and Z are treated as uses and the ~'s are treated as additional assignments. The variables in the Ix and X are renamed together with the rest of the program variables. Transformations performed on SSA form have to take aliasing into account in order to preserve the safety of the optimization. In our SSA representation, it means taking_ into account the IX and ~ annotations. For example, in performing dead code elimination using the algorithm presented in [CFR+91], a store can be deleted only if the store itself and all its associated ~'s are not marked live. 3 SSA with Zero Versioning In the previous section, we showed how to use IX and ;~ to model use-def information when aliases occur in a program. Even though use-def information is maintained, the number of versions multiplies because each ~ introduces a new version and it may in turn cause new ~'s to be inserted. Many of these versions have multiple possibly- defined values, and some of the defined values may also be unknown.