DooleyMSThesis06 - c 2006 by Isaac James Dooley. All rights...

Info iconThis preview shows page 1. Sign up to view the full content.

View Full Document Right Arrow Icon
This is the end of the preview. Sign up to access the rest of the document.

Unformatted text preview: c 2006 by Isaac James Dooley. All rights reserved. AUTOMATED SOURCE-TO-SOURCE TRANSLATIONS TO ASSIST PARALLEL PROGRAMMERS BY ISAAC JAMES DOOLEY B.S., Birmingham-Southern College, 2004 THESIS Submitted in partial fulfillment of the requirements for the degree of Master of Science in Computer Science in the Graduate College of the University of Illinois at Urbana-Champaign, 2006 Urbana, Illinois Abstract It is commonly believed that parallel programming can be difficult. Because it is already difficult enough, any automatic ways of simplifying parallel programming are welcome. This thesis describes how source-to-source translators can be used to make parallel programming easier. This thesis describes three source-to-source translators and provide some examples of translated codes. The translators used the ROSE library. The first source-to-source translator removes global and static variables from a program and encapsulates them in a structure which is allocated on the stack. This translator facilitates the use of any MPI code with AMPI, an adaptive MPI implementation which unfortunately has limited support for MPI applications containing global or static variables. The source-to-source translator just transforms the code a minimal amount so that existing compilers, linkers, and loaders can be used. Thus no special compilers or loaders are required. Requiring special compilers or loaders necessarily would limit the acceptance of AMPI, whereas a source-to-source translator would provide a simple automated way of transforming an MPI code for use on any platform. The second source-to-source translator inserts calls to functions for tracing an application. The traces are used for post-mortem performance analysis. The translator inserts a Projections function tracing call at the beginning and end of each function in the source code. Thus an existing MPI application can be analyzed for performance function by function, without any need for the user to manually modify the application’s code. The third source-to-source translator automatically creates PUP routines for Charm++ applications. PUP routines are functions that serialize the state of a migratable object. iii PUP routines are normally created by hand, which leaves room for programmer error. For example, it is easy to overlook a member variable in a class. The source-to-source translator, however, can easily iterate through all member variables and add each to the PUP routine. AMPI shows great potential for improving the performance of scientific simulations that use MPI. AMPI adaptively manages parallel resources, provides runtime instrumented load balancing, fault-tolerance, and supports virtualization. These features are very useful for dynamic applications and are essential for large scale parallel codes. AMPI augmented with the global variable rewriting translator will be able to provide these features automatically to any C or C++ MPI application. Parallel scientific applications are generally concerned with two main criteria, capabilities and performance. To analyze performance, the source code instrumenting tool will be useful. All AMPI scientific application developers can benefit from this tool. These translation tools will increase the productivity of parallel programmers. iv To Thomas and Laura Dooley, My Loving Parents. v Acknowledgments I would like to thank my advisor Laxmikant Kale, and all the members of the Parallel Programming Laboratory for their help with various aspects of this work. I would like to thank the HPCS Fellowship program which provided funding for this project. vi Table of Contents List of Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . List of Figures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . List of Abbreviations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Chapter 1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.1 Related Work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Chapter 2 Source-To-Source Translation . . . . . . . . 2.1 ROSE for Source-to-Source Translation . . . . . . . . . 2.2 The Simplest Possible ROSE Translator . . . . . . . . 2.3 Complications . . . . . . . . . . . . . . . . . . . . . . . 2.3.1 Languages . . . . . . . . . . . . . . . . . . . . . 2.3.2 Compiler Flags . . . . . . . . . . . . . . . . . . 2.4 Stability and Robustness . . . . . . . . . . . . . . . . . Chapter 3 Thread Variable Privatization . . . . . . . 3.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3.2 Data Layout for Variables in C and C++ . . . . . . . . 3.2.1 Globals and Statics: An Overview . . . . . . . . 3.3 Global Variables with Virtualization . . . . . . . . . . 3.3.1 Manually Rewrite Source Code . . . . . . . . . 3.3.2 Swap Globals . . . . . . . . . . . . . . . . . . . 3.3.3 Compiler Based Solutions . . . . . . . . . . . . 3.3.4 Automatically Rewrite Source Code . . . . . . . 3.3.5 Example translations . . . . . . . . . . . . . . . 3.4 Case Study: MILC . . . . . . . . . . . . . . . . . . . . 3.4.1 MIMD Lattice Computations . . . . . . . . . . 3.5 Case Study: WRF . . . . . . . . . . . . . . . . . . . . 3.5.1 Description of WRF . . . . . . . . . . . . . . . 3.5.2 Globals and Statics Variables in WRF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. ... ... ... ... ... ... .. ... ... ... ... ... ... ... ... ... ... ... ... ... ... ix x xi 1 2 4 6 8 9 9 9 10 11 11 12 12 14 15 16 16 17 18 19 19 22 22 22 vii Chapter 4 Automated Performance Tracing . . . . . . 4.1 AMPI Performance Tracing with Projections . . . . . . 4.2 Performance Tracing Source-to-Source Translator . . . 4.3 Example . . . . . . . . . . . . . . . . . . . . . . . . . . Chapter 5 Automatic PUP Function Creation . . . . . 5.1 PUP Functions . . . . . . . . . . . . . . . . . . . . . . 5.2 PUP Creator Source-to-Source translator . . . . . . . . 5.3 Example . . . . . . . . . . . . . . . . . . . . . . . . . . Chapter 6 Chapter 7 Appendix A Appendix B Appendix C Appendix D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. ... ... ... .. ... ... ... 26 26 27 28 29 29 30 31 32 39 40 52 56 59 63 Example Translated Codes . . . . . . . . . . . . . . . . . . . . . Conclusions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Thread Variable Privatization: Code Listing . . . . . . . . . Automated Performance Tracing: Code Listing . . . . . . . Automatic PUP Function Creation: Code Listing . . . . . . Common Shared Routines: Code Listing . . . . . . . . . . . References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . viii List of Tables 3.1 2 source-code files with global and static variables. . . . . . . . . . . . . . . . 13 ix List of Figures 2.1 2.2 2.3 Source-to-source overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . A selection of the 241 AST nodes used by ROSE . . . . . . . . . . . . . . . . A simple identity translator that uses ROSE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 7 8 13 14 15 21 23 24 25 30 32 33 34 35 36 37 37 37 37 38 3.1 Memory layout for a program and a user-level threaded program . . . . 3.2 MPI example program with a global variable called my rank . . . . . . . 3.3 Code from figure 3.2 manually rewritten to eliminate the global variable . 3.4 Global Variables in compiled MILC object files . . . . . . . . . . . . . . . 3.5 Count of Global BSS symbols in WRF executables . . . . . . . . . . . . 3.6 43 Global BSS symbols in WRF executable ideal.exe . . . . . . . . . . . 3.7 61 Global BSS symbols in WRF executable wrf.exe . . . . . . . . . . . . 5.1 6.1 6.2 6.3 6.4 6.5 6.6 6.7 6.8 6.9 6.10 A C++ class with a PUP function . . . . . . . . . . . . . . . . . . . . . . . A C++ file before the automatic creation of PUP functions . . . . . . . . . . A C++ file after the automatic creation of PUP functions . . . . . . . . . . A sample program before tracing calls are inserted . . . . . . . . . . . . . . . Program of Figure 6.3 after tracing calls are inserted to a depth of 3. . . . . After inserting tracing calls to a depth of 2 . . . . . . . . . . . . . . . . . . . An example program with multiple global variables . . . . . . . . . . . . . . Translated version of program from Figure 6.6. Contains no global variables. Symbols created when compiling the code in Figure 6.6 . . . . . . . . . . . Symbols created when compiling the code in Figure 6.7 . . . . . . . . . . . An example program with two static variables. Both static variables are named a, but they have different scopes. . . . . . . . . . . . . . . . . . . . . 6.11 After translation, the two static variables are replaced with two variables with mangled names are in the struct. The end of the mangled name is the original name a. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 x List of Abbreviations AST ELF GAS MILC NAS NASA NCAR NPB PPL PUP QCD ROSE WRF Abstract Syntax Tree. A graph representation of source code Executable and Linkable Format (formerly Extensible Linking Format) Global Address Space MIMD Lattice Computation NASA Advanced Supercomputing Division National Aeronautics and Space Administration National Center for Atmospheric Research NAS Parallel Benchmark Parallel Programming Lab Pack and Un-Pack Quantum Chromodynamics ROSE Source-to-Source Translation Library Weather Research and Forecasting simulation developed by NCAR xi Chapter 1 Introduction It is commonly believed that parallel programming can be difficult. Because it is already difficult enough, any automatic ways of simplifying parallel programming are welcome. This thesis describes how source-to-source translators can be used to make parallel programming easier. This thesis describes three source-to-source translators in chapters 3, 4, and 5 while providing some examples of translated codes in chapter 6. The translators use the ROSE library which is described in chapter 2. The first source-to-source translator removes global and static variables from a program and encapsulates them in a structure which is allocated on the stack. This translator facilitates the use of any MPI code with AMPI, an adaptive MPI implementation which unfortunately does not allow MPI applications to contain global or static variables on non 32-bit ELF platforms. The source-to-source translator just transforms the code so that existing compilers, linkers, and loaders can be used. Thus no special compilers or loaders are required for all relevant platforms. Requiring special compilers or loaders necessarily would limit the acceptance of AMPI, whereas a source-to-source translator would provide a simple automated way of transforming an existing MPI code for use with AMPI on any platform. The second source-to-source translator inserts calls to functions for tracing an application. The traces are used for post-mortem performance analysis. The translator inserts function tracing call at the beginning and end of each function in the source code. Thus an existing MPI application can have its performance traced function by function in a reasonable manner, without any need for the user to manually modify the application’s code. Just as many vendors provide tracing libraries relevant to their own particular machines, and as 1 many MPI implementations provide their own tracing facilities, AMPI and Charm++ use their own performance analysis tool Projections. Projections is a very advanced tool which is currently being extending to provide even more performance views for AMPI traced applications. The third source-to-source translator automatically creates PUP routines for Charm++ applications. PUP routines are functions that serialize the state for a migratable object. PUP routines are normally created by hand, which leaves room for programmer error. For example, it is easy to overlook a member variable in a class. The source-to-source translator, however, can easily iterate through all member variables and add each to the PUP routine. This thesis describes three source-to-source translators using the ROSE library along with their motivating issues and examples of translated codes. The examples are simple enough for the reader to quickly understand, but the translators have been used on much larger codes spanning dozens of files and thousands of lines of code. The translators are available in the Charm++ source code repository for any interested readers to view or use. 1.1 Related Work There are no existing software source-to-source translation tools that perform the specific translations done by the three source-to-source tools described in this thesis. The translators proposed in this thesis use the ROSE library[1, 14, 16, 15]. Other frameworks could have been used to perform similar tasks, but ROSE best suited the initial goals of the project. For example, the LLVM compiler infrastructure[10, 9, 8] is a particularly well suited framework to build the translators described in this thesis, however it was not chosen because its generated output code does not look like the original C or C++ input. It is a goal of our work to be able to rewrite an application and retain its original structure as much as possible, including the comments which would have been lost in a LLVM based translation. ROSE just translates from source to source not to some optimized machine language as does 2 LLVM. Another research oriented extensible compiler infrastructure for source-to-source translation is Cetus[12]. Cetus does not provide support for Fortran, and is designed to facilitate parallelizing Java, C++, and C. Cetus is a successor in some ways to the Polaris compiler [13] which operated instead on Fortran 77. Also, various other source-to-source converters are not of concern to the work of this thesis because they deal with converting between languages, not modifying code in the manner proposed in this thesis. For example, there are UPC to C, CAF to F90, Java to C++, and countless other esoteric variants like SML to Java, or Lambda Calculus to Javascript. 3 Chapter 2 Source-To-Source Translation Source-to-source translation is a process by which a source code is modified by a special purpose application and the resulting source code can then be used as desired. Source-tosource translation therefore can be platform independent, and can facilitate a number of interesting changes to a set of source code files. Some change for example can be applied to hundreds or thousands of files at once in a manner much faster than could be done by hand. The input and output languages from a translator may or may not be the same. This thesis only considers translation from C to C or C++ to C++. Some possible example changes include: - Changing all variable names to be consistently formatted - Translating a fortran program to a functionally equivalent C program - Restructuring loops to facilitate optimizations(unrolling, jamming, merging) - Inlining of functions - Changing all function names in a library’s source to be prepended with the library’s name Source-to-source translation should be done by an application that fully understands and can correctly parse the input language. A simple search-and-replace function of a text editor will not be able to correctly analyze the structure and symantics of most languages. For example, a regex based search will not be able to differentiate between a function and variable with the same name. 4 The general method for source-to-source translation is to parse the input source code into an abstract syntax tree(AST), then to manipulate the AST, and finally to generate source code from the modified AST. Figure 2.1 shows this flow from input to output, with an example of an actual AST produced by the PUP translator described in Chapter 5. 0:85 SgFile 1 0x806ae40 root 1:84 SgGlobal 978 0x808c190 0:85 SgFile 1 0x806ae40 *[977] root 1:84 SgGlobal 978 0x808c190 2:83 SgClassDeclaration 1 someClass 0x42bd914c definition *[977] 2:83 SgClassDeclaration 1 someClass 0x42bd914c AST Manipulation 4:7 SgVariableDeclaration 1 0x42b480d8 *[0] *[2] 5:6 SgInitializedName 1 0x8591d58 3:82 SgClassDefinition 4 0x83a5a08 *[0] *[1] *[2] *[3] definition 8:11 SgVariableDeclaration 1 0x42b481c8 12:15 SgVariableDeclaration 1 0x42b482b8 16:81 SgMemberFunctionDeclaration 3 0x42cba048 3:82 SgClassDefinition 4 0x83a5a08 *[0] *[0] parameterList definition CtorInitializerList *[0] *[1] 9:10 SgInitializedName 1 0x8591da8 13:14 SgInitializedName 1 0x8591df8 17:20 SgFunctionParameterList 1 0x42acab20 21:78 SgFunctionDefinition 1 0x8465990 79:80 SgCtorInitializerList 0 0x42d0c330 4:7 SgVariableDeclaration 1 0x42b480d8 8:11 SgVariableDeclaration 1 0x42b481c8 12:15 SgVariableDeclaration 1 0x42b482b8 initptr initptr initptr *[0] body *[0] *[0] *[0] 18:19 SgInitializedName 1 0x8592938 22:77 SgBasicBlock 3 0x846f9e0 5:6 SgInitializedName 1 0x8591d58 9:10 SgInitializedName 1 0x8591da8 13:14 SgInitializedName 1 0x8591df8 initptr *[0] *[1] *[2] initptr initptr initptr 23:40 SgExprStatement 1 0x86a778c 41:58 SgExprStatement 1 0x86a77b0 59:76 SgExprStatement 1 0x86a77d4 expression_root expression_root expression_root 24:39 SgExpressionRoot 1 0x84e87ec 42:57 SgExpressionRoot 1 0x84e8820 60:75 SgExpressionRoot 1 0x84e8854 operand_i operand_i operand_i 25:38 SgFunctionCallExp 2 0x86c13cc 43:56 SgFunctionCallExp 2 0x86c1400 61:74 SgFunctionCallExp 2 0x86c1434 function args function args function args 28:37 SgExprListExp 2 0x86cdac4 62:63 SgFunctionRefExp 0 0x8738a08 46:55 SgExprListExp 2 0x86cdaf0 64:73 SgExprListExp 2 0x86cdb1c *[0] *[1] *[0] *[1] *[0] *[1] 29:30 SgVarRefExp 0 0x849426c 31:36 SgArrowExp 2 0x8654c08 47:48 SgVarRefExp 0 0x84942c4 49:54 SgArrowExp 2 0x8654c3c 65:66 SgVarRefExp 0 0x849431c 67:72 SgArrowExp 2 0x8654c70 .C Original Source Code lhs_operand_i rhs_operand_i lhs_operand_i rhs_operand_i lhs_operand_i rhs_operand_i 32:33 SgThisExp 0 0x8648d60 34:35 SgVarRefExp 0 0x8494298 50:51 SgThisExp 0 0x8648d90 52:53 SgVarRefExp 0 0x84942f0 68:69 SgThisExp 0 0x8648dc0 70:71 SgVarRefExp 0 0x8494348 .C Generated Translated Source Code Figure 2.1: Source-to-source overview 5 2.1 ROSE for Source-to-Source Translation ROSE is a library that can be used to write source-to-source translators[1, 14, 16, 15]. A ROSE based translator can parse, modify and output C or C++ code. The ROSE library is developed at Lawrence Livermore National Laboratories by Dan Quinlan and others. It currently supports C and C++ languages, although it has been used by some other group to support FORTRAN via a front-end parser called OPEN64. ROSE is not available on the internet, but may someday be freely released. Academic users might be able to obtain a copy from the ROSE team. ROSE uses the EDG front-end for its parsing of C++ and C into the abstract syntax tree that is exposed to the user of the ROSE library. Each node in the tree will have a scope, a file info, some type of specifier for how the associated code should be generated after modification, a link to a parent, and various specific attributes such as a name. Some of the 241 types of AST nodes used by ROSE are listed in figure 2.2. The programmer reference documentation distributed with ROSE should be used to explore the various types of nodes. Each node has its own kinds of attributes and accessor functions. The details for each node is well beyond the scope of this thesis. In addition to parsing source files into an AST, the ROSE library provides query functions that traverse the AST building a list of all nodes of the desired type. For example, it is easy to obtain a list of all variable declarations in a file or given scope. Iterators can easily scan through all variable reference expressions, or any other type of AST node. Various mechanisms are in place and are being developed in ROSE to allow for modification of the AST. Lower level rewrite mechanisms allow for modification, removal, and insertion of AST nodes while higher level mechanisms allow for insertion of arbitrary C++ code represented by a string to the AST in a specified location. 6 - SgProject A ROSE project that can contain multiple files - SgFile A source-code file - SgFunctionDeclaration A function declaration - SgFunctionDefinition A function definition - SgFunctionCallExpr A function call expression - SgFunctionRefExp A function reference, to be used in a function call expression - SgBasicBlock A block of code, surrounded by { and } - SgVarRefExp A variable reference expression - SgVariableDeclaration A variable declaration - SgClassDeclaration A class declaration, either a forward declaration or a defining declaration - SgClassDefinition A class definition - SgMemberFunctionDeclaration A member function in a class - SgCtorInitializerList for initialization lists at constructors - SgArrowExp The “->” operator for pointers - SgThisExp The pointer to the “this” object - SgWhileStmt A while statement - SgMinusOp The unary operator minus - SgPointerDerefExp A pointer dereference expression - SgDeleteExp The C++ delete operator Figure 2.2: A selection of the 241 AST nodes used by ROSE 7 2.2 The Simplest Possible ROSE Translator The simplest of all ROSE translators is the identity translator, an example of which is shown in figure 2.3. It takes the source for a program, parses it in to the internal AST format, and generates output code which should be almost identical to the initial input files. This translator is useful for debugging ROSE, and for initially testing new codes. For example the identity translator should always be used first when a new code is being translated. This will ensure the translator is being given correct compiler options, include directories, and ROSE language flags. #include ” r o s e . h” int main ( int argc , char ∗ argv [ ] ) { // B u i l d t h e AST used by ROSE S g P r o j e c t ∗ p r o j e c t = f r o n t e n d ( argc , argv ) ; // I n s e r t your own m a n i p u l a t i o n o f t h e AST h e r e . . . generateDOT ( ∗ p r o j e c t ) ; // Generate a graph f o r t h e AST generatePDF ( ∗ p r o j e c t ) ; // Generate a p d f d e s c r i b i n g t h e AST // Generate s o u r c e code from AST and c a l l t h e normal c o m p i l e r return backend ( p r o j e c t ) ; } Figure 2.3: A simple identity translator that uses ROSE All transformations are done through accesses to the project variable which contains pointers to the SgFile nodes in the project. Each file contains a scope node which can be used to further access the tree. Additionally queries can be performed directly on project or any other node to return a list of any desired type of node in the AST. 8 2.3 Complications When using ROSE for the first time, a number of problems can arise, and the ROSE documentation is large, but has sparse coverage of the entire ROSE library and its use. A new user of ROSE should be aware of two considerable problems when developing translators. The first is an issue regarding language differences between C and C++ while the second is a simpler problem with include flags. 2.3.1 Languages There are a number of subtle issues regarding dialects of C and C++. All C programs are not valid C++ programs. Thus in some cases the user of a translator must pass special flags to the ROSE-based translator to specify which language is used for a program. This problem exists when parsing the NAS Parallel Benchmark IS. The NAS NPB benchmarks use a variable called class to store the desired benchmark problem size. In C++, class is a reserved keyword, which can therefore not be used as a variable name. To parse such a C file, it may be necessary to use the command line option -rose:C only or -rose:C99 only. Running the identity translator on a code should allow the user to quickly determine which flag should be used. 2.3.2 Compiler Flags ROSE currently does not include “.” as an include directory, so a flag such as “-I.” should commonly be used. Additionally, a space is not allowed between the “I” and the following directory. Some common compilers allows such a space, but ROSE does not. 9 2.4 Stability and Robustness Rose provides multiple different mechanisms for manipulating AST’s, from a very low level tedious manual modification of the nodes of the tree and all their associated fields to a higher level method whereby a string of C++ code can be inserted at a particular location in the AST. The higher level methods are not robust or fully implemented, and thus are not used for the three translators described in this thesis. The low level method is seeming quite robust. Unfortunately learning how to use each particular type of AST node is non-intuitive at first, and much guessing and checking is required before learning what must be done in each case. There is no description of what is required for each node in a well-formed ROSE AST. Currently there are only two known C codes which we have not yet managed to parse with even the identity translator. The first is a C program which includes the file charm++.h and the second is part of the Zoltan partitioning library. These may prove to be simple hurdles to overcome, or maybe ROSE has bugs which will be difficult to pinpoint. 10 Chapter 3 Thread Variable Privatization 3.1 Introduction Amongst the various possible uses of source-to-source translation in parallel programming is the modification to remove global variables from C or C++ programs. Various user-level thread packages will require global variables to be handled differently when virtualization is applied. The term “virtualization” refers in this thesis to the use of multiple threads or virtual processors within a single process on one physical processor. Parallel frameworks such as AMPI[6, 3, 11, 7, 5] and various multi-paradigm languages currently under development will be able to benefit from this work. In order to build a user-level thread based system, the thread-private state for each thread must be encapsulated and accessible by the currently running thread upon a thread context-switch. Often time the thread-private data is the stack, and associated internal processor state including the contents of various registers. It is not always possible to just invent a new language and compiler for use in existing production applications. Because a huge amount of code for existing applications is already written in C, C++, and FORTRAN; it is best to try to utilize these languages as much as possible. Section 3.2 describes the layout of C and C++ programs in memory and why we must specifically address global and static variables. Section 3.3 addresses the issues with global and static variables in the context of virtualized MPI applications. The information provided in this chapter may also prove useful in contexts other than MPI, such as a virtualized version of a GAS language. 11 3.2 Data Layout for Variables in C and C++ Almost all compiled languages on traditional computers follow the same pattern for data layout. Source code is compiled into executable programs that use a single 32 or 64-bit virtual address space. The program, when executing, will be loaded into its virtual memory space in a number of segments. Figure 3.1 shows a simple view of the partitioning or segmenting of a program’s address space. The exact layout depends upon the operating system, compilers, linkers and loaders used to compile and run the program. The typical method is to have a code segment, a data segment, a stack, and a heap. The code segment may be write-protected while the data segment is able to be written. The series of instructions to be executed will be loaded at runtime into the code segment. The data segment will contain constants and data compiled into the program. The heap is used at runtime from which memory is dynamically allocated. The stack will grow from one end of its segment as functions are called and their return pointers and variables are pushed onto the stack. In reality on many systems the layout can be more complicated, with more segments, complicated permission schemes, and varying names or designations for the regions of memory, but these further complications are beyond the scope of this thesis. 3.2.1 Globals and Statics: An Overview Global variables are both simple and complicated. In a C program, it is trivial to create a global variable, however understanding how a global variable is handled by compilers, linkers, and loaders is more difficult. This section provides simple examples to show how global variables are compiled on current systems. Additionally this section provides example programs containing static variables, which are similar but not identical to globals. Table 3.1 lists the code from two files, and shows the relevant symbols from an executable compiled from these two source files. The symbols are produced by running the tool nm on the resulting executable. The program has 2 globals in the first file, one called a, and a static global called 12 Process Code Segment Data Segment Globals, Statics User Level Threads Code Segment Data Segment Globals, Statics Thread 1 Stack Stack Thread 2 Stack Thread 3 Stack Heap Heap Figure 3.1: Memory layout for a program and a user-level threaded program b. The second file utilizes the same global a as well as its own static global b. As expected in the symbols found in the executable are found two b variables, one for each file, and one a shared by both files. Additionally each file contains a function which in turn contains a static variable. These statics are not globals, but a similar effect happens when they are compiled, that is they are located along with the globals in a single memory segment. The symbols in the executable show that indeed two variables named c.0 appear. These are for the two different static integers named c. Source File 1 int a; static int b; void f(void); int main(){ static int c; a=100; b=100; f(); } Source File 2 #include <stdio.h> int a; static int b; void f(void){ static int c; printf(”a=%d b=%d”, a, b); a=100; b=0; } Symbols in Executable 08049614 B a 08049620 b b 08049628 b b ... 0804961c b c.0 08049624 b c.0 ... 080483b8 T f 0804838c T main Table 3.1: 2 source-code files with global and static variables. 13 Global variables are accessible from any file in which they are declared, either with or without the use of the term extern. Global variables are all grouped together into a particular segment of memory when a program is run. Thus all files can know exactly how to reference the global. Static variables are variables whose values persist beyond exiting the scope of the variable. For this reason, a static variable is essentially a global variable with a limited scope. The static variable can only be accessed in its scope using the standard scoping rules. Thus a static variable can be implemented in the same manner as a global, with a sufficiently mangled name to distinguish between multiple static variables with the same name, but different scopes. 3.3 Global Variables with Virtualization In an MPI application, the user expects that if one of the processors sets the value of a global variable, then the value will still be the same the next time that the same processor reads the value. Commonly this may occur as in Figure 3.2. Obviously the programmer will expect the value of my rank not to change after setting it. In the most common MPI implementations, each MPI processor is assigned to an OS process running on a physical processor. In this case each process has its own set of global variables. Thus things work as expected. Unfortunately, under virtualization, things start breaking down. #include ”mpi . h” int my rank ; int main ( ) { MPI I ni t ( . . . ) ; MPI Comm rank ( MPI COMM WORLD, &my rank ) ; ... p r i n t f ( ”myrank=%d \ n” , my rank ) ; } Figure 3.2: MPI example program with a global variable called my rank If multiple threads run sharing a single copy of the global, they may interfere with each 14 other, and each may not see its latest updates to a global variable. Figure 3.2 shows a not so farfetched example where a global variable is used in an MPI program. Thus in our example the actual memory location holding the my rank should be unique for each MPI process. In AMPI, many virtual processors may execute within a single OS process. Thus we must have a mechanism for providing separate sets of global variables for each virtual processor. Section 3.3.1 describes one mechanism for providing separate sets of globals to each virtual processor; just require that the programmer remove any global variables. Vacuously, then, there is a null set of globals for each process. A better mechanism for providing separate sets of variables it to modify the GOT as described in Section 3.3.2. Section 3.3.3 discusses briefly how a compiler could eliminate global variables, but tells of the downsides to this approach. The scheme we propose is to use a source-to-source translator which removes all globals and statics from a program without changing the behavior of the program. Section 3.3.4 describes the source-to-source translator written for this purpose. 3.3.1 Manually Rewrite Source Code One way of solving this problem for AMPI applications is to not use any global variables. The globals will therefore live on the stack or heap, not in the single overlapping section for the DATA segment. This is easily accomplished for the example 3.2 as shown in 3.3. The global variable is just declared in the main function. #include ”mpi . h” int main ( ) { int my rank ; MPI I ni t ( . . . ) ; MPI Comm rank ( MPI COMM WORLD, &my rank ) ; ... } Figure 3.3: Code from figure 3.2 manually rewritten to eliminate the global variable 15 3.3.2 Swap Globals Another way of solving this problem for AMPI applications is to have AMPI swap the globals in and out at each thread context switch. This solution requires a platform where it is possible to identify the memory locations for globals making it possible to replace the global data. On some platforms all global variables are removed from their actual data by a second layer of indirection. To access a global variable, a pointer to the data is stored in a table. On such platforms, AMPI can just store different copies of the table and modify the pointers in the table at a context switch. A platform which supports swapping global variables by use of a table of pointers to the global variables is ELF. ELF uses a Global Offset Table(GOT), which contains a list of all global variables, and pointers to the actual data, along with other data describing the variables. The entries in this table can be modified easily, but the modifications will take small amounts of time. Unfortunately, the methods for accessing the ELF GOT varies across operating systems and architectures. Currently AMPI’s swap-globals method supports 32bit x86 linux. Extending it to support 64-bit ELF could probably be done as well. A common platform which does not provide ELF is Apple’s Mac OSX, which uses MachO executable format. All globals are accessed by a pointer computed as an offset from the contents of a register which is essentially the program counter. Thus globals can be more quickly accessed on Mach-O systems, but they lack the flexibility provided in ELF by its use of an extra level of indirection. 3.3.3 Compiler Based Solutions Compilers could be modified to force global variables to be located on the stack inside of the main function. Such a solution would work with AMPI, where each thread has its own stack, and would hence have its own set of global variables. Unfortunately, modifying a compiler will limit the potential deployment platforms because users may not want to build or install 16 another set of compilers. Also, common compilers such as gcc are notoriously difficult to modify due to a lack of documentation for the compiler’s codebase. Users will also have their preferences for compilers which are fast or work well with their applications, and many of those are proprietary, and thus not easily modified. 3.3.4 Automatically Rewrite Source Code A source-to-source translator could be used to automatically encapsulate all global variables and put them on the stack. The approach of creating a source-to-source translator to encapsulate the global variables has proven effective so far. The translator we propose uses the ROSE library to parse and modify the source code for an application. The source for the translator is provided in Appendix A. The steps in the process are listed below. Dan Quinlan, the lead developer for ROSE, wrote an initial translator which which identified and moved global variables. It only worked in the simplest cases, it didn’t handle statics, and it didn’t handle multiple files well, but it led to our proposed translator. - Build list of all global variables by iterating through entire AST - Build list of static variables by iterating through entire AST - Set output filenames to overwrite existing if desired - Find file containing the main function: main(), AMPI Main()or AMPI Main cpp() - Create a struct(initially empty) to encapsulate all the globals and statics - Create a new initializer function(initially empty) - Build list of all variable references to statics or globals by iterating through entire AST - Move all global variables into the class, removing their old declarations 17 - Move all static variables into the class, removing their old declarations, and mangling their names - Declare an instance of the struct in the top of the main function - Add a call to the initializer function in the main function, using the new instance of the struct - Append a reference to the struct to all function definitions in the project - Append the reference to the struct to all function call expressions - Fixup all references to the globals or statics to be indirected through the parameter provided in all functions - Remove all initializers from the globals and statics contained in the struct, and place equivalent statements in the initializer function - Copy the struct definition from its one location in the file containing the main function to the top of all other files - Remove extern declarations for any globals moved into the struct The translator which was written following the structure listed above works with a great many samples. Unfortunately there is at least one known cases where this approach fails. Section 3.4 describes one of these problems and a proposed solution in the context of a real application we want to use with the translator. 3.3.5 Example translations This section provides two example programs translated by a source-to-source translator which eliminates global and static variables. The first example shows a program with three global variables. The second example shows a program with multiple static variables, each 18 with the same name. The examples are meant to provide easy to read examples, not to show all the features of the translator . Figure 6.6 lists the original code for a simple program which contains three global variables. Figure 6.7 lists the code output by the translator. The output code contains no globals, but does contain a struct which encapsulates the globals. The struct is instantiated in the top of main, and is added on as a pointer parameter to all other functions, in this case only f(). Tables 6.8 and 6.9 verify that the globals are present before translation, and they are eliminated by the translation. The second example, which shows how statics are handled, is shown in Figures 6.10 and 6.11. The two statics have their names mangled to reflect their different scopes. To do this, the translator specifically requests a mangled name for each static variable from ROSE. Thus a complicated mangled name replaces the original name for the variable. Although seemingly complicated, a mangled name must be used if more than one static variable has the same name. The intializers are handled correctly in this case as well. For the example, if main() or f() had contained other statements, those would have remained, but this example is intended to be simple. 3.4 Case Study: MILC This section presents a large MPI code named MILC. It describes the limited success so far with the translator and the plans for expanding the translator to work well with the complicated cases that arise when using this large real world application. 3.4.1 MIMD Lattice Computations MILC is a code used to simulate and study quantum chromodynamics(QCD), a theory describing the strong interactions between subatomic particles. MILC, which stands for MIMD Lattice Computation, is a widely used large code with over a hundred files in its 19 distribution[4]. It is written in C, C++ and assembly, using MPI for its parallel version. The benchmarking version of MILC has been analyzed to determine the extent of its usage of global variables. The object files produced when compiling MILC can be viewed with the nm utility to determine exactly how many global and static variables MILC contains. The object files contained 78 global variables which need to be dealt with before this code can work with AMPI. Figure 3.4 lists the global variables and the corresponding object files in which they were found. The globals are spread across 8 different files. Manually modifying MILC is therefore a complicated task. Thus having a source-to-source translation tool for automatically removing these variables is of great importance. The translator described in this chapter does not yet work with this complicated example, but work is proceeding on making it translate the needed MILC files. The reason it does not yet work is that there are global variables with user defined types that are only within the scope of some of the files, namely those where the global is declared. Thus adding the variable to the stack allocated struct is non-trivial. There have been various discussed methods for handling the user defined types, and the best solution proposed so far will require many additional transformations of the code. First we will create a getsize name() function for each global variable in the file where such a global variable exists. This function will return the size of the global variable by simply calling sizeof(global variable. Additionally a non-defining function declaration for each getsize name() function, i.e. a prototype, must be added to the file containing main(). Then the struct will contain a pointer instead of an actual declaration of the variable. Then in main() each variable will be allocated using alloca(getsize name()). Finally, when rewriting all references to the globals, the variable will have to be dereferenced from the struct since it is now a pointer. This solution should work for all possible examples we could foresee, including typedef and class global variables. The situation is similarly complicated for static variables of a user defined type. 20 gaugefix2.o: diffmat offset sumvec offset setup.o: gf par buf gauge stuff.o: gauge action description loop char loop coeff loop expect loop ind loop length loop num loop table control.o: beta ensemble id epsilon even sites on node fpi mass fpi nmasses gen pt g ssplaq g stplaq iseed lattice linktrsum mass1 mass2 nflavors1 nflavors2 niter node prn npbp reps in n sources nt number of nodes nx ny nz odd sites on node phases in propinterval control.o: rsqmin rsqprop savefile saveflag sequence number sites on node source inc source start spectrum multimom low mass spectrum multimom mass step spectrum multimom nmasses spectrum request startfile startflag start lat hdr startlat p steps stringLFN t fatlink this node t longlink total iters trajecs u0 valid fatlinks valid longlinks volume warms reunitarize2.o: av deviation max deviation quark stuff.o: num basic paths path num d congrad5 fn.o: cg p resid t dest ttt fermion force asqtad3.o: backwardlink tempmom Figure 3.4: Global Variables in compiled MILC object files 21 3.5 Case Study: WRF This section presents a large MPI code named WRF. We first give a brief description of WRF and then describe why the global variables in this example cannot be eliminated by my translator. Finally we discuss the future plans for extending my translator to work with FORTRAN codes, and hence the important interesting code WRF. 3.5.1 Description of WRF WRF is a Weather Research and Forcasting modeling system, developed by the National Center for Atmospheric Research(NCAR)[17, 2]. It is an advanced 3-D fluid dynamics code that incorporates a variety of models for air, land, and oceans. Its goal is “to provide a next-generation mesoscale forecast model and data assimilation system that will advance both the understanding and prediction of mesoscale weather and accelerate the transfer of research advances into operations.” WRF uses multiple levels of nested structured grids with microphysics, cumulus parameterizations, surface physics, planetary boundary layer physics, and atmospheric radiation physics. 3.5.2 Globals and Statics Variables in WRF I built a copy of WRF to determine what global variables exist in its executables. My plan was then to determine if my translator would be able to eliminate these global variables. Unfortunately WRF contains a number of FORTRAN files which currently cannot be handled by my translator. Because many scientific and engineering applications use FORTRAN, the translator must be extended to support this currently unsupported language. Adding fortran support is currently a major desire for the PPL group members working with AMPI applications. WRF can be built with the command ”compile em b wave”. This produced two im22 Executable Number of Globals ideal.exe 43 wrf.exe 61 Figure 3.5: Count of Global BSS symbols in WRF executables portant executables on the NCSA IBM AIX machine named copper. The first executable is ideal.exe. The second is wrf.exe. The executables were examined with the ”nm” tool and a count of the Global BSS symbols is reported in table 3.5. These variables are from FORTRAN modules, which are similar to C global variables. wrf.exe contains 61 globals while ideal.exe contains 43. 23 &&N&@data info mpi status &&N&@esmf calendarmod old offsets &&N&@esmf timemod point move receives &&N&@module configure point move sends &&N&@module date time pr descriptors &&N&@module dm regular decomp &&N&@module domain rslMPIHandleLUT &&N&@module ext internal rsl debug flg &&N&@module io rsl mpi communicator &&N&@module machine rsl myproc &&N&@module nesting rsl ndomains &&N&@module quilt outbuf ops rsl noprobe &&N&@module wrf error rsl nproc &&N&@module wrf quilt rsl nproc all &&N&@wrf data rsl nproc m C runtime pstartup rsl nproc n cdf routine name rsl padarea domain info rslsysxx io seq compute sh descriptors io seq monitor sw allow dynpad mess xp descriptors mh descriptors Figure 3.6: 43 Global BSS symbols in WRF executable ideal.exe 24 &&N&@data info &&N&@esmf calendarmod &&N&@esmf timemod &&N&@module configure &&N&@module date time &&N&@module dm &&N&@module domain &&N&@module ext internal &&N&@module io &&N&@module machine &&N&@module mp etanew &&N&@module mp ncloud3 &&N&@module mp ncloud5 &&N&@module mp thompson &&N&@module mp wsm3 &&N&@module mp wsm5 &&N&@module mp wsm6 &&N&@module nesting &&N&@module progtm &&N&@module quilt outbuf ops &&N&@module ra gfdleta &&N&@module ra gsfcsw &&N&@module ra rrtm &&N&@module sf myjsfc &&N&@module sf noahlsm &&N&@module sf sfclay &&N&@module wrf error &&N&@module wrf quilt &&N&@module wrf top &&N&@wrf data &&N&module ra gfdleta C runtime pstartup cdf routine name domain info idx input io seq compute io seq monitor mess mh descriptors mpi status old offsets point move receives point move sends pr descriptors regular decomp rslMPIHandleLUT rsl debug flg rsl mpi communicator rsl myproc rsl ndomains rsl noprobe rsl nproc rsl nproc all rsl nproc m rsl nproc n rsl padarea rslsysxx sh descriptors sw allow dynpad xp descriptors Figure 3.7: 61 Global BSS symbols in WRF executable wrf.exe 25 Chapter 4 Automated Performance Tracing It is critical to be able to accurately analyze the performance of large scale high-performance applications. Various languages and parallel systems provide different tools for analyzing performance. Charm++ and AMPI support tracing and analyzing performance with the tool named Projections. Projections contains many tools for analyzing time varying data including processor utilization, message statistics, timelines, and a number of histograms and other views. When analyzing performance in both serial and MPI applications, an important metric is the amount of time spent in each function. Currently the Projections performance analysis tool does not rewrite binaries, so it relies upon tracing calls made by the runtime communication library as well as user written tracing calls. Thus to get the most detailed performance data in an AMPI application, the user must explicitly write some special function calls. These calls inform the tracing library when a particular function or piece of code starts and ends. The calls are simple, and can therefore be easily inserted automatically. This chapter describes and shows an example of the source-to-source translator for automatically generating and inserting tracing calls. 4.1 AMPI Performance Tracing with Projections AMPI supports a set of function calls for tracing nested functions. These functions have prototypes and simpler macro wrappers in ampi.h which is identical to the file called mpi.h provided by AMPI. 26 - traceBeginFuncProj() specifies the beginning of a function - traceEndFuncProj() specifies the end of a function - traceRegisterFunction() called once at the beginning of the program to register each function which is traced Often a program will have a stack of function calls. If all these functions are traced, the analysis is complicated by the excessive data. For example, a multi-physics code may just want to trace the time spent in each of its three numerical solvers, and therefore the calls to each solver are bracketed with the functions above. 4.2 Performance Tracing Source-to-Source Translator We implemented a translator which automatically inserts the calls listed above into an application’s source code. The translator first identifies functions within a specified call depth from main(). It then inserts tracing calls inside each of the definitions of each of these functions. traceBeginFuncProj() is inserted at the beginning of each function, and traceEndFuncProj() is called at the end of each function and also preceding all return statements in the function. Each function that is traced also has a corresponding traceRegisterFunction() added to main(). The call depth is a configurable command line argument to the translator. This allows a user to control the degree of detail that will appear in the resulting traced performance data. When planning this translator, we decided we wanted a simple mechanism for specifying how much of an application to trace. In the future, if it becomes helpful, we will add some means for a user to specify which files to not trace or files to add to those traced. The Projections runtime and post-mortem tools will compute the exclusive times spent in each of the traced functions. Thus applicable tools can be written to display various types of performance analyses. Currently we are developing tools inside Projections for AMPI 27 now that we have a means for automatically tracing large programs. This project is active work with new graphical display tools currently being written, so performance results from applications are not described here. 4.3 Example Figure 6.3 shows an example program that has a main() function and three other functions, A(), B(), and C(). The functions are called one from another, starting with main. The purpose of having this chain of functions is to illustrate that this source-to-source translator is capable of tracing nested functions to a user selected depth. Figure 6.4 shows the resulting translated code after tracing calls were inserted to a depth of 3. Figure 6.5 shows the resulting translated code when the depth of tracing was specified to be 2. The main difference is that function C() is not traced in the later case because it is at a call depth of 3 which is greater than the specified 2. The simplicity of specifying just a simple integer depth is quite useful, but yet also provides a great deal of control over the amount of tracing data recorded. 28 Chapter 5 Automatic PUP Function Creation 5.1 PUP Functions Charm++ is a parallel runtime system and programming model which provides support for migratable objects composed of user written C++ classes along and a simple interface definition. Charm++ does not use its own compiler because it is not a language itself except for its simple translation of the short interface definitions into C++. The decision not to create and use a special purpose compiler has limited the available code analysis for help with various useful parallel functions such as the serialization of migratable objects. Charm++ currently requires uses to write Pack-and-UnPack (PUP) functions for each migratable object. See Figure 5.1 for an example of a PUP function. Each PUP function has a single pupper as its parameter, often named p, which has an associated overloaded vertical bar operator. The pupper has internal state specifiying whether it is in a packing state or an unpacking state, and this internal state controls the behavior of the overloaded vertical bar. Thus only a single function is required in order to perform both the packing and unpacking functions which serialize and unserialize an object into or from some buffer. PUP functions are used not only for migrating objects, but is also used for checkpointing and restarting objects to and from disk or remote memories, serializing some graphics data when using LiveViz and CCS, and other miscellaneous tasks. Users are currently required to write their own PUP functions, but a compiler based solution or an automated source-to-source solution would eliminate the need for users to be concerned with writing PUP functions and keeping them up to date whenever a class is 29 #include <pup . h> class exampleClass { int a ; double b ; char c ; void PUP( c l a s s PUP : : e r &p ) { p|a; p|b; p| c ; } }; Figure 5.1: A C++ class with a PUP function modified. Generally writing PUPs is considered simple, but a hassle. 5.2 PUP Creator Source-to-Source translator This thesis presents a simple PUP creation source-to-source translator. It takes in a set of C++ source files and will add to each class a PUP function. The PUP function will be populated with statements for PUPing each of the member variables in the class. Currently the translator generates a call in the form p|a; for each class member variable. This works for many cases, although arrays and pointers should be handled differentlly. This translator could be extended to handle arrays and pointers. The main trouble with this extension is that it may not be possible to determine the size of an array at compile time. One downside to automatically creating PUP functions is that a user knows the minimal set of state which should be PUPed. It is non-trivial for a compiler to determine this set of data. For example, it may be faster to compute a set of values than transmit them over a network, or maybe the programmer can easily determine which variables are live at the point where they are PUPed. This leads to one disadvantage of the current implementation; all member variables are PUPed. In an ideal version, a minimal amount of data should be PUPed since the 30 serialized version will be written to disk, stored in memory, or sent over a network. Live variable analysis is not currently implemented in ROSE, but it could potentially be added if needed. A few other concerns which are yet unaddressed are whether to PUP inherited members. Currently we do not PUP any inherited members. 5.3 Example Figure 6.1 and 6.2 shows a C++ source file before and after the PUP calls are added by my source-to-source automatic PUP creation tool. One curious result is that the explicit use of the (this)-> code generated by the translator. Note that (this)-> a is equivalent to a inside a class in most cases. The obvious exception is when another variable “a” is in a local scope and the class variable is hidden. The files displayed in the figure are the exact code consumed and produced by my translator. 31 Chapter 6 Example Translated Codes This chapter contains examples of translated codes for each of the source-to-source translators described in the thesis. Chapters 3,5, and 4 describe these examples and their motivations. #include <pup . h> c l a s s someClass { public : int a ; double b ; private : char c ; }; Figure 6.1: A C++ file before the automatic creation of PUP functions 32 #include <pup . h> c l a s s someClass { public : int a ; double b ; private : char c ; public : void PUP( c l a s s PUP : : e r &p ) { p | ( t h i s ) −> a ; p | ( t h i s ) −> b ; p | ( t h i s ) −> c ; } } ; Figure 6.2: A C++ file after the automatic creation of PUP functions 33 #include <mpi . h> int C( ) { i f (0==1) return 0 ; else return 1 ; } void B( ) { C( ) ; } int A( int j ) { B( ) ; return 7 ; } int main ( int argc , char ∗∗ argv ) { A( 1 ) ; } Figure 6.3: A sample program before tracing calls are inserted 34 #include <mpi . h> int C( ) { t r a c e B e g i n F u n c P r o j ( ”C” , ” UnknownFile ” , 1 ) ; i f ( ( 0 == 1 ) ) { traceEndFuncProj ( ”C” ) ; return 0 ; } else { traceEndFuncProj ( ”C” ) ; return 1 ; } traceEndFuncProj ( ”C” ) ; } void B( ) { t r a c e B e g i n F u n c P r o j ( ”B” , ” UnknownFile ” , 1 ) ; C( ) ; traceEndFuncProj ( ”B” ) ; } int A( int j ) { t r a c e B e g i n F u n c P r o j ( ”A” , ” UnknownFile ” , 1 ) ; B( ) ; traceEndFuncProj ( ”A” ) ; return 7 ; traceEndFuncProj ( ”A” ) ; } int main ( int argc , char ∗∗ argv ) { t r a c e R e g i s t e r F u n c t i o n ( ”main” , − 999); t r a c e B e g i n F u n c P r o j ( ”main” , ” UnknownFile ” , 1 ) ; t r a c e R e g i s t e r F u n c t i o n ( ”A” , − 999); t r a c e R e g i s t e r F u n c t i o n ( ”B” , − 999); t r a c e R e g i s t e r F u n c t i o n ( ”C” , − 999); A( 1 ) ; traceEndFuncProj ( ”main” ) ; traceEndFuncProj ( ”main” ) ; } Figure 6.4: Program of Figure 6.3 after tracing calls are inserted to a depth of 3. 35 #include <mpi . h> int C( ) { i f ( ( 0 == 1 ) ) { return 0 ; } else { return 1 ; } } void B( ) { t r a c e B e g i n F u n c P r o j ( ”B” , ” UnknownFile ” , 1 ) ; C( ) ; traceEndFuncProj ( ”B” ) ; } int A( int j ) { t r a c e B e g i n F u n c P r o j ( ”A” , ” UnknownFile ” , 1 ) ; B( ) ; traceEndFuncProj ( ”A” ) ; return 7 ; traceEndFuncProj ( ”A” ) ; } int main ( int argc , char ∗∗ argv ) { t r a c e R e g i s t e r F u n c t i o n ( ”main” , − 999); t r a c e B e g i n F u n c P r o j ( ”main” , ” UnknownFile ” , 1 ) ; t r a c e R e g i s t e r F u n c t i o n ( ”A” , − 999); t r a c e R e g i s t e r F u n c t i o n ( ”B” , − 999); A( 1 ) ; traceEndFuncProj ( ”main” ) ; } Figure 6.5: After inserting tracing calls to a depth of 2 36 i nt g l o b a l a ; float global b ; unsigned g l o b a l c ; int f ( int j ) { return j + g l o b a l c ; } int main ( int argc , char ∗∗ argv ) { f ( global a ); } Figure 6.6: An example program with multiple global variables struct A M P I g l o b a l s t { int g l o b a l a ; float global b ; unsigned int g l o b a l c ; }; int f ( int j , struct A M P I g l o b a l s t ∗ AMPI globals ) { return ( ( j ) + AMPI globals −> g l o b a l c ) ; } int main ( int argc , char ∗∗ argv ) { struct A M P I g l o b a l s t A M P I g l o b a l s o n s t a c k ; f ((& A M P I g l o b a l s o n s t a c k ) −> g l o b a l a ,& A M P I g l o b a l s o n s t a c k ) ; } Figure 6.7: Translated version of program from Figure 6.6. Contains no global variables. Address 00000000 00000004 00000004 00000004 0000000d Type T C C C T Name f global a global b global c main Figure 6.8: Symbols created when compiling the code in Figure 6.6 Address Type 00000000 T 0000000e T Name f main Figure 6.9: Symbols created when compiling the code in Figure 6.7 37 v oid f ( ) { s t a t i c i nt a =3; } int main ( int argc , char ∗∗ argv ) { s t a t i c i nt a =2; } Figure 6.10: An example program with two static variables. Both static variables are named a, but they have different scopes. struct AMPI TL Vars { int f Fb v Gb Fe int m a i n Fb i Gb i Fe scope SgSS2 } ; scope SgSS2 sep Pb Pb scope a ; c scope Pe a; Pe \ void AMPI TL Vars Init ( struct AMPI TL Vars ∗ AMPI TLs ) { AMPI TLs −> f Fb v Gb Fe scope SgSS2 scope Fb i Gb i sep Pb Pb c Pe AMPI TLs −> m a i n Pe Fe scope SgSS2 scope a = 2; } a = 3; \ void f ( struct AMPI TL Vars ∗ AMPI TLs ) { } int main ( int argc , char ∗∗ argv ) { struct AMPI TL Vars A M P I g l o b a l s o n s t a c k ; AMPI TL Vars Init(& A M P I g l o b a l s o n s t a c k ) ; } Figure 6.11: After translation, the two static variables are replaced with two variables with mangled names are in the struct. The end of the mangled name is the original name a. 38 Chapter 7 Conclusions Parallel programming can be difficult and time consuming. Using tools such as sourceto-source translators can ease the burden of parallel programming. This thesis proposes a methodology and examples of source-to-source translation to simplify various aspects of parallel programming and performance analysis. The first translator eliminated global and static variables from a C or C++ application. The second translator inserted performance tracing calls into an MPI application for use with the Projections performance analysis tool. The final translator wote PUP functions for C++ classes. These translators were written using the ROSE library, and they can handle a wide range of C and C++ applications. FORTRAN is not yet supported by these translators, but FORTRAN support may be added in the future. The output resulting code from the translators is very similar to the input code except for the modifications performed by the translator. This thesis proposes that source-to-source translation is a good approach to dealing with various parallel programming tasks. 39 Appendix A Thread Variable Privatization: Code Listing The following is the source code for the Thread Variable Privatization tool described in Chapter 3. The main source file for this translator is globalVariableRewrite.C. Additionally the shared code described in Appendix D is required. The latest versions are available in the PPL group’s CVS repository under the ROSE-Translators module. /∗ Adapted by Isaac Dooley from t h e file CharmSupport . C w r i t t e n by t h e ROSE g r o u p d e c l a r e d on a t LLNL . P u r p o s e : E n c a p s u l a t e a l l T h r e a d L o c a l (TL) v a r i a b l e s i n a s t r u c t u r e t h e s t a c k , and p a s s a r o u n d a p o i n t e r t o t h i s s t r u c t u r e . TL v a r i a b l e s Why : include global and statics AMPI can o n l y h a n d l e g l o b a l v a r i a b l e s on c e r t a i n p l a t f o r m s . B a s i c a l l y e a c h t h r e a d n e e d s i t s own t h r e a d − l o c a l c o p y o f t h e g l o b a l v a r i a b l e s , but each thread runs in a s i n g l e p r o c e s s which has only a s i n g l e s e t o f g l o b a l v a r i a b l e s . On ELF b a s e d s y s t e m s , we can m o d i f y t h e ELF G l o b a l O f f s e t T a b l e on t h r e a d c o n t e x t s w i t c h e s , b u t on s y s t e m s w i t h Mach b a s e d l i n k e r s / l o a d e r s , a l l c o d e i s p o s i t i o n i n d e p e n d e n t , and g l o b a l s a r e h a r d c o d e d r e l a t e i v e t o t h e PC , s o on t h r e a d c o n t e x t s , t h e r e i s no e f f i c i e n t way o f s w a p p i n g i n and o u t g l o b a l v a r i a b l e s s h o r t o f s w a p p i n g i n and o u t t h e e n t i r e DATA S e g m e n t ( w h i c h can b e d o n e ) . Thus r e w r i t i n g g l o b a l v a r i a b l e s w i t h a c o m p i l e r i s t h e b e s t s o l u t i o n t o t h i s problem , as i t w i l l be e f f i c i e n t as w e l l as p l a t f o r m independent . TODO: remove t h e p l a c e h o l d e r v a r i a b l e a f t e r e v e r y t h i n g i s b u i l t . Only do m o d i f i c a t i o n s i f some s t a t i c s o r g l o b a l s a r e f o u n d ∗/ #include #include #include #include #include #include < r o s e . h> <l i s t > <v e c t o r > <a l g o r i t h m > <i o s t r e a m > <e x c e p t i o n > #include ” g l o b a l V a r i a b l e C o m m o n . h” #d e f i n e DEBUG 0 using namespace s t d ; / ∗ The M i d d l e L e v e l R e w r i t e mechanism i s n o t y e t r o b u s t e n o u g h t o u s e . ∗/ /∗ U n f o r t u n a t e l y t h e c u r r e n t l o w l e v e l r e w r i t e d o e s n ’ t h a n d l e i n c l u d e s t a t e m e n t s a t t h e /∗ U n f o r t u n a t e l y t h e M i d d l e l e v e l r e w r i t e d o e s n ’ t h a n d l e m u l t i p l e f i l e s c o r r e c t l y ∗/ #d e f i n e USE MIDDLELEVELREWRITE 0 bool overwrite existing files ; top correctly ∗/ const char ∗ s t r u c t N a m e = ” AMPI TL Vars ” ; const char ∗ initFuncName = ” A M P I T L V a r s I n i t ” ; const char ∗ p l a c e H o l d e r N a m e = ” AMPI place holder ” ; 40 / ∗ ∗ main f i l e s c o n t a i n a f u n c t i o n t h a t l o o k s l i k e main ∗ / bool i s F i l e M a i n ( S g F i l e ∗ f i l e ) { // s c a n t h r o u g h a l l f u n c t i o n d e c l a r a t i o n s and s e e i f any o f them a r e main ( ) l i s t <SgNode∗> f u n c t i o n s = NodeQuery : : q u e r y S u b T r e e ( f i l e , V S g F u n c t i o n D e c l a r a t i o n ) ; f o r ( l i s t <SgNode ∗ > : : i t e r a t o r i = f u n c t i o n s . b e g i n ( ) ; i != f u n c t i o n s . end ( ) ; i ++) { i f ( isFunctionMain ( i s S g F u n c t i o n D e c l a r a t i o n (∗ i ) ) ) return true ; } return f a l s e ; } /∗ ∗ b u i l t i n f u n c t i o n s s h o u l d s t a r t w i t h d o u b l e u n d e r s c o r e ∗/ bool i s F u n c t i o n B u i l t i n ( S g F u n c t i o n D e c l a r a t i o n ∗ f u n c d e c l ) { char ∗ f u n c n a m e = f u n c d e c l − g e t n a m e ( ) . s t r ( ) ; > i f ( s t r l e n ( f u n c n a m e ) < 2) return f a l s e ; e l s e i f ( f u n c n a m e [ 0 ] == ’ ’ && f u n c n a m e [ 1 ] == ’ ’ ) return true ; else return f a l s e ; } / ∗ ∗ Lookup t h e c o r r e c t s t r u c t t o u s e f o r t h e r e f e r e n c e s S g E x p r e s s i o n ∗ l o o k u p T L S t r u c t ( SgNode ∗ whichNode ) { to the global variables ∗/ // w a l k up AST t o t h e f u n c t i o n D e c l a r a t i o n c o n t a i n i n g t h i s F u n c t i o n C a l l E x p SgNode ∗ n = whichNode ; while ( ! i s S g F u n c t i o n D e c l a r a t i o n ( n ) ) n = n− g e t p a r e n t ( ) ; > SgFunctionDeclaration ∗ parentFunctionDeclaration = isSgFunctionDeclaration (n ) ; assert ( parentFunctionDeclaration ) ; // I f we a r e n o t i n main , u s e f i n a l p a r a m e t e r f r o m p a r a m e t e r l i s t i f ( ! isFunctionMain ( parentFunctionDeclaration )){ SgFunctionParameterList ∗ f p l = parentFunctionDeclaration − get parameterList ( ) ; > assert ( fpl ); l i s t < S g I n i t i a l i z e d N a m e ∗> &a r g s = f p l − g e t a r g s ( ) ; // r e a l l y a s t d : : l i s t < > > assert ( args . s i z e () > 0); S g I n i t i a l i z e d N a m e ∗ f i n a l A r g = a r g s . back ( ) ; assert ( finalArg ); assert ( finalArg− get scope ( ) ) ; > S g V a r i a b l e S y m b o l ∗ v a r i a b l e S y m b o l = new S g V a r i a b l e S y m b o l ( f i n a l A r g ) ; a s s e r t ( variableSymbol ) ; Sg File Info ∗ f i l e i n f o = Sg File Info : : generateDefaultFileInfoForTransformationNode ( ) ; a s s e r t ( f i l e i n f o != NULL ) ; SgVarRefExp ∗ varRefExp = new SgVarRefExp ( f i l e i n f o , v a r i a b l e S y m b o l ) ; return varRefExp ; } e l s e { // we a r e i n main u s e the s t r u c t we c r e a t e d // Get main ’ s b a s i c b l o c k ( c u r r e n t l y p a r e n t F u n c t i o n D e c l a r a t i o n i s main ) SgBasicBlock ∗ basicBlock = isSgBasicBlock ( parentFunctionDeclaration − g e t d e f i n i t i o n ( ) > assert ( basicBlock ) ; // F i n d f i r s t s t a t e m e n t i n t h e b a s i c b l o c k S g S t a t e m e n t P t r L i s t &s t a t e m e n t s = b a s i c B l o c k − g e t s t a t e m e n t s ( ) ; > // TODO FIXME : assume t h e f i r s t s t a t e m e n t i n main i s o u r s t r u c t d e c l a r a t i o n S g S t a t e m e n t ∗ f i r s t S t a t e m e n t= ∗ ( s t a t e m e n t s . b e g i n ( ) ) ; assert ( firstStatement ); SgVariableDeclaration ∗ variableDeclaration = isSgVariableDeclaration ( firstStatement ) ; assert ( variableDeclaration ); // Get t h e f i r s t v a r i a b l e d e f i n e d i n v a r i a b l e D e c l a r a t i o n // T h e r e can b e m u l t i p l e i . e . ” i n t i , j , k ; ” S g I n i t i a l i z e d N a m e P t r L i s t &a r g s = v a r i a b l e D e c l a r a t i o n − g e t v a r i a b l e s ( ) ; > a s s e r t ( a r g s . s i z e ( ) == 1 ) ; // assume t h a t t h e f r o n t =o n l y v a r i a b l e b e i n g d e c l a r e d i s t h e one we want SgInitializedName ∗ finalArg = args . front ( ) ; assert ( finalArg ); // a s s e r t ( f i n a l A r g − g e t s c o p e ( ) ) ; > S g V a r i a b l e S y m b o l ∗ v a r i a b l e S y m b o l = new S g V a r i a b l e S y m b o l ( f i n a l A r g ) ; a s s e r t ( variableSymbol ) ; // C r e a t e a r e f e r e n c e t o t h e s t r u c t v a r i a b l e Sg File Info ∗ f i l e i n f o = Sg File Info : : generateDefaultFileInfoForTransformationNode ( ) ; a s s e r t ( f i l e i n f o != NULL ) ; SgVarRefExp ∗ varRefExp = new SgVarRefExp ( f i l e i n f o , v a r i a b l e S y m b o l ) ; // C r e a t e an a d d r e s s o f t h e r e f e r e n c e t o t h e s t r u c t f i l e i n f o = Sg File Info : : generateDefaultFileInfoForTransformationNode ( ) ; a s s e r t ( f i l e i n f o != NULL ) ; SgAddressOfOp ∗ p o i n t e r = new SgAddressOfOp ( f i l e i n f o , varRefExp , NULL ) ; return p o i n t e r ; } return NULL ; 41 } / ∗ ∗ R e a s s o c i a t e P r e p r o c e s s o r s t a t e m e n t s and comments f r o m a g i v e n n o d e This i s m o s t l y c o p i e d from r e w r i t e L o w L e v e l I n t e r f a c e .C ∗/ void r e a s s o c i a t e P r e p r o c e s s o r D e c l a r a t i o n s ( SgLocatedNode ∗ fromHere , SgLocatedNode ∗ t o H e r e ) { // Get a t t a c h e d p r e p r o c e s s i n g i n f o A t t a c h e d P r e p r o c e s s i n g I n f o T y p e ∗ comments = fromHere − g e t A t t a c h e d P r e p r o c e s s i n g I n f o ( ) ; > if ( comments != NULL) { #i f d e f DEBUG printf #e n d i f ( ” Found a t t a c h e d comments ( a t %p o f t y p e : %s ) : \ n” , fromHere , fromHere − s a g e c l a s s n a m e ( ) ) ; > i f ( t o H e r e − g e t A t t a c h e d P r e p r o c e s s i n g I n f o ( ) != NULL) { > t o H e r e − g e t A t t a c h e d P r e p r o c e s s i n g I n f o ()−> merge ( ∗ comments ) ; > } else { t o H e r e − s e t a t t a c h e d P r e p r o c e s s i n g I n f o P t r ( comments ) ; > } f o r ( s t d : : l i s t <P r e p r o c e s s i n g I n f o ∗ > : : i t e r a t o r } i=comments− b e g i n ( ) ; > i != comments− end ( ) ; ++i ) { > fromHere − s e t a t t a c h e d P r e p r o c e s s i n g I n f o P t r (NULL ) ; > } } /∗ ∗ C l e a n u p s t r u c t b y r e m o v i n g t h e t e m p o r a r a y p l a c e h o l d e r v a r i a b l e d e c l a r a t i o n void f i x u p C l a s s D e c l a r a t i o n P l a c e H o l d e r ( S g C l a s s D e c l a r a t i o n ∗ c l a s s D e c l a r a t i o n ) { l i s t <SgNode∗> n o d e L i s t = NodeQuery : : q u e r y S u b T r e e ( classDeclaration , ∗/ V SgVariableDeclaration ); l i s t <SgNode ∗ > : : i t e r a t o r i ; f o r ( i=n o d e L i s t . b e g i n ( ) ; i != n o d e L i s t . end ( ) ; ++i ) { S g V a r i a b l e D e c l a r a t i o n ∗ varDecl = i s S g V a r i a b l e D e c l a r a t i o n (∗ i ) ; a s s e r t ( v a r D e c l != NULL ) ; // i f t h i s v a r i a b l e i s c a l l e d ” p l a c e h o l d e r ” t h e n g e t r i d o f i t l i s t < S g I n i t i a l i z e d N a m e ∗> & v a r i a b l e L i s t = v a r D e c l − g e t v a r i a b l e s ( ) ; > l i s t <S g I n i t i a l i z e d N a m e ∗ > : : i t e r a t o r v a r ; f o r ( v a r=v a r i a b l e L i s t . b e g i n ( ) ; v a r != v a r i a b l e L i s t . end ( ) ; ++v a r ) { i f ( ( ∗ v a r)−> g e t n a m e ( ) . g e t S t r i n g ( ) == s t r i n g ( p l a c e H o l d e r N a m e ) ) { c o u t << ” Removing ” << p l a c e H o l d e r N a m e << ” v a r i a b l e ” << e n d l ; S g C l a s s D e f i n i t i o n ∗ parent = i s S g C l a s s D e f i n i t i o n ( varDecl− g e t p a r e n t ( ) ) ; > a s s e r t ( p a r e n t !=NULL ) ; p a r e n t − g e t m e m b e r s ( ) . remove ( v a r D e c l ) ; > } } } } / ∗ ∗ Move a l l i n i t i a l i z e r s f r o m t h e v a r i a b l e s i n t h e c l a s s D e c l a r a t i o n t o ∗ / /∗ ∗ a s s i g n m e n t s t a t e m e n t s i n t h e i n i t f u n c t i o n ∗/ void f i x u p I n i t i a l i z e r s ( S g C l a s s D e c l a r a t i o n ∗ c l a s s D e c l a r a t i o n , S g F u n c t i o n D e c l a r a t i o n ∗ T L I n i t ) { Sg File Info ∗ f i l e i n f o = Sg File Info : : generateDefaultFileInfoForTransformationNode ( ) ; l i s t <S g D e c l a r a t i o n S t a t e m e n t ∗> d e c l s = c l a s s D e c l a r a t i o n − g e t d e f i n i t i o n ()−> g e t m e m b e r s ( ) ; > l i s t <S g D e c l a r a t i o n S t a t e m e n t ∗ > : : i t e r a t o r i ; f o r ( i=d e c l s . b e g i n ( ) ; i != d e c l s . end ( ) ; ++i ) { SgVariableDeclaration ∗ vardecl ; i f ( v a r d e c l=i s S g V a r i a b l e D e c l a r a t i o n ( ∗ i ) ) { l i s t < S g I n i t i a l i z e d N a m e ∗> names = v a r d e c l − g e t v a r i a b l e s ( ) ; > f o r ( l i s t < S g I n i t i a l i z e d N a m e ∗ > : : i t e r a t o r n=names . b e g i n ( ) ; n!= names . end ();++ n ) { S g I n i t i a l i z e r ∗ i n i t i a l i z e r = ( ∗ n)−> g e t i n i t i a l i z e r ( ) ; i f ( i n i t i a l i z e r != NULL) { SgAssignInitializer ∗assignInit ; if ( isSgConstructorInitializer ( i n i t i a l i z e r )) c o u t << ”WARNING: Can ’ t y e t h a n d l e S g C o n s t r u c t o r I n i t i a l i z e r s ” << e n d l ; if ( isSgAggregateInitializer ( i n i t i a l i z e r )) c o u t << ”WARNING: Can ’ t y e t h a n d l e S g A g g r e g a t e I n i t i a l i z e r ” << e n d l ; i f ( ( a s s i g n I n i t= i s S g A s s i g n I n i t i a l i z e r ( i n i t i a l i z e r ) ) ! =NULL) { SgExpression ∗ i n i t e x p r = a s s i g n I n i t − get operand ( ) ; > // f i g u r e o u t w h a t i s t h e p a r a m e t e r ( t h e s t r u c t ) p a s s e d i n S g E x p r e s s i o n ∗ TLStr uct = l o o k u p T L S t r u c t ( T L I n i t − g e t d e f i n i t i o n ( ) ) ; > a s s e r t ( TLSt ruct ) ; 42 S gType ∗ t y p e = new SgTypeInt ( ) ; S g V a r i a b l e S y m b o l ∗ sym = new S g V a r i a b l e S y m b o l ( ∗ n ) ; SgVarRefExp ∗ varRefExp = new SgVarRefExp ( f i l e i n f o , sym ) ; // D e r e f e r e n c e t h e s t r u c t t o g e t t h e v a r i a b l e SgArrowExp ∗ r e d i r e c t e d R e f e r e n c e = new SgArrowExp ( f i l e i n f o , TLStruct , varRefExp , t y p e ) ; // F i g u r e o u t e x a c t l y w h a t we a r e a s s i g n i n g S g I n t V a l ∗ v = new S g I n t V a l ( f i l e i n f o , 7 ) ; ( rhs ) // c r e a t e a s s i g n m e n t s t a t e m e n t SgAssignOp ∗ a s s i g n O p = new SgAssignOp ( f i l e i n f o , r e d i r e c t e d R e f e r e n c e , i n i t e x p r , type ) ; S g E x p r e s s i o n R o o t ∗ e x p r R o o t = new S g E x p r e s s i o n R o o t ( f i l e i n f o , assignOp , type ) ; SgExprStatement ∗ e x p r S t a t e m e n t = new SgExprStatement ( f i l e i n f o , exprRoot ) ; // i n s e r t a s s i g n s t a t e m e n t i n t o t h e i n i t f u n c t i o n S g F u n c t i o n D e f i n i t i o n ∗ f u n c D e f = TLInit− g e t d e f i n i t i o n ( ) ; > S g B a s i c B l o c k ∗ bb = f u n c D e f − g e t b o d y ( ) ; > bb− a p p e n d s t a t e m e n t ( e x p r S t a t e m e n t ) ; > } ( ∗ n)−> s e t i n i t i a l i z e r (NULL ) ; } } } } } / ∗ ∗ Add a v a r i a b l e d e c l a r a t i o n t o main t h a t e n c a p s u l a t e s a l l t h e g l o b a l s . ∗ / void d e c l a r e C l a s s A n d I n i t I n M a i n ( S g G l o b a l ∗ g l o b a l S c o p e , S g C l a s s D e c l a r a t i o n ∗ c l a s s D e c l a r a t i o n , SgFunctionDeclaration ∗ TLInit ){ a s s e r t ( g l o b a l S c o p e != NULL ) ; // F i n d t h e d e f i n i t i o n o f main ( ) l i s t <S g D e c l a r a t i o n S t a t e m e n t ∗ > : : i t e r a t o r i = g l o b a l S c o p e − g e t d e c l a r a t i o n s ( ) . b e g i n ( ) ; > while ( i != g l o b a l S c o p e − g e t d e c l a r a t i o n s ( ) . end ( ) ) > { SgFunctionDeclaration ∗ f u n c t i o n D e c l a r a t i o n = i s S g F u n c t i o n D e c l a r a t i o n (∗ i ) ; i f ( f u n c t i o n D e c l a r a t i o n != NULL) { i f ( isFunctionMain ( f u n c t i o n D e c l a r a t i o n )){ // // // // We must c h e c k f o r t h e f u n c t i o n d e f i n i t i o n , b e c a u s e we may b e l o o k i n g a t a p r e d e c l a r a t i o n / p r o t o t y p e At f i r s t t h i s i s n o t o b v i o u s t h a t a n y o n e w o u l d do t h i s , b u t AMPI d o e s i t t o rename main . f o r main SgFunctionDefinition ∗ fdef = isSgFunctionDefinition ( functionDeclaration − > get definition ()); i f ( f d e f ){ SgBasicBlock ∗ block = isSgBasicBlock ( fdef − get body ( ) ) ; > a s s e r t ( block ) ; // C r e a t e a v a r i a b l e d e c l a r a t i o n Sg File Info∗ fileinfo = Sg File Info : : generateDefaultFileInfoForTransformationNode ( ) ; a s s e r t ( f i l e i n f o != NULL ) ; S g C l a s s T y p e ∗ v a r i a b l e T y p e = new S g C l a s s T y p e ( c l a s s D e c l a r a t i o n − > get firstNondefiningDeclaration ()); a s s e r t ( v a r i a b l e T y p e != NULL ) ; SgName ∗ varname = new SgName ( ” A M P I g l o b a l s o n s t a c k ” ) ; SgVariableDeclaration ∗ variableDeclaration = new S g V a r i a b l e D e c l a r a t i o n ( f i l e i n f o , ∗ varname , v a r i a b l e T y p e ) ; varname− s e t p a r e n t ( v a r i a b l e D e c l a r a t i o n ) ; > variableDeclaration − set parent ( block ) ; > a s s e r t ( v a r i a b l e D e c l a r a t i o n != NULL ) ; // C r e a t e a f u n c t i o n c a l l e x p r e s s i o n s t a t e m e n t SgFunctionSymbol ∗ funcSymbol = new SgFunctionSymbol ( T L I n i t ) ; // TODO: P r o b a b l y n o t c o r r e c t , b u t i t w o r k s f o r now SgFunctionType ∗ funcType = new SgFunctionType ( new SgTypeVoid ( ) ) ; SgFunctionRefExp ∗ f u n c t i o n R e f E x p = new SgFunctionRefExp ( f i l e i n f o , funcSymbol , funcType ) ; S g E xp r L i s t E xp ∗ e x p r l i s t = new S g E xp r L i s t E xp ( f i l e i n f o ) ; SgFunctionCallExp ∗ f u n c c a l l = new S g F u n c t i o n C a l l E x p ( f i l e i n f o , f u n c t i o n R e f E x p , e x p r l i s t , funcType ) ; S g E x p r e s s i o n R o o t ∗ e x p r R o o t = new S g E x p r e s s i o n R o o t ( f i l e i n f o , f u n c c a l l , funcType ) ; SgExprStatement ∗ e x p r S t a t e m e n t = new SgExprStatement ( f i l e i n f o , e x p r R o o t ) ; 43 // F i r s t p r e p e n d t h e i n i t f u n c t i o n c a l l , t h e n p r e p e n d t h e s t r u c t d e c l a r a t i o n block− prepend statement ( exprStatement ) ; > // I n s e r t t h e v a r i a b l e d e c l a r a t i o n i n t o t h e b o d y o f main ( ) block− i n s e r t s t a t e m e n t ( block− g e t s t a t e m e n t s ( ) . begin ( ) , v a r i a b l e D e c l a r a t i o n ) ; > > variableDeclaration − set parent ( block ) ; > } } } i ++; } } / ∗ ∗ R e w r i t e a l l f u n c t i o n c a l l and d e c l a r a t i o n p a r a m e t e r l i s t s t o i n c l u d e t h e e n c a p s u l a t e d void addTLClassAsParameter ( SgNode ∗ s u b t r e e , S g C l a s s D e c l a r a t i o n ∗ c l a s s D e c l a r a t i o n ) { map< s t r i n g , int , l e s s < s t r i n g > > m o d i f i e d F u n c t i o n N a m e s ; a s s e r t ( s u b t r e e != NULL ) ; // Add p a r a m e t e r t o f u n c t i o n globals ∗/ declarations l i s t <SgNode∗> f u n c t i o n D e c l s = NodeQuery : : q u e r y S u b T r e e ( s u b t r e e , V S g F u n c t i o n D e c l a r a t i o n ) ; c o u t << ” Found ” << f u n c t i o n D e c l s . s i z e ( ) << ” F u n c t i o n D e c l a r a t i o n s i n t h i s s u b t r e e ” << e n d l ; l i s t <SgNode ∗ > : : i t e r a t o r i ; for ( i = funct ionDecls . begin ( ) ; i != f u n c t i o n D e c l s . end ( ) ; ++i ) { SgFunctionDeclaration ∗ f u n c t i o n D e c l a r a t i o n = i s S g F u n c t i o n D e c l a r a t i o n (∗ i ) ; a s s e r t ( f u n c t i o n D e c l a r a t i o n != NULL ) ; if ( ! ! ! ){ // c r e a t e t h e p a r a m e t e r S g C l a s s T y p e ∗ v a r i a b l e T y p e = new S g C l a s s T y p e ( c l a s s D e c l a r a t i o n − > get firstNondefiningDeclaration ()); a s s e r t ( v a r i a b l e T y p e != NULL ) ; SgName var1 name = ”AMPI TLs” ; S g P o i n t e r T y p e ∗ r e f t y p e = new S g P o i n t e r T y p e ( v a r i a b l e T y p e ) ; S g I n i t i a l i z e r ∗ v a r 1 i n i t i a l i z e r = NULL ; S g I n i t i a l i z e d N a m e ∗ v a r 1 i n i t n a m e=new S g I n i t i a l i z e d N a m e ( var1 name , r e f t y p e , v a r 1 i n i t i a l i z e r , NULL ) ; > > var1 init name− set scope ( functionDeclaration − get scope ( ) ) ; assert ( var1 init name− get scope ( ) ) ; > i s F u n c t i o n M a i n ( f u n c t i o n D e c l a r a t i o n ) && i s S t a t e m e n t I n H e a d e r ( f u n c t i o n D e c l a r a t i o n ) && f u n c t i o n D e c l a r a t i o n − g e t f i l e i n f o ()−> i s C o m p i l e r G e n e r a t e d ( ) > // I n s e r t a r g u m e n t i n f u n c t i o n p a r a m e t e r l i s t SgFunctionParameterList ∗ parameterList = functionDeclaration − get parameterList ( ) ; > parameterList− append arg ( v a r 1 i n i t n a m e ) ; > var1 init name− set parent ( parameterList ) ; > > assert ( var1 init name− get parent ( ) ) ; var1 init name− set scope ( functionDeclaration − get scope ( ) ) ; > > // Add t o t h e l i s t o f m o d i f i e d f u n c t i o n s modifiedFunctionNames [ f u n c t i o n D e c l a r a t i o n − get name ( ) . s t r ( ) ] = 1 ; > } } // B u i l d a l i s t o f f u n c t i o n c a l l s w i t h i n t h e AST l i s t <SgNode∗> f u n c t i o n C a l l L i s t = NodeQuery : : q u e r y S u b T r e e ( s u b t r e e , V S g F u n c t i o n C a l l E x p ) ; c o u t << ” M o d i f i e d ” << m o d i f i e d F u n c t i o n N a m e s . s i z e ( ) << ” f u n c t i o n p a r a m e t e r l i s t s ” << e n d l ; c o u t << ” Found ” << f u n c t i o n C a l l L i s t . s i z e ( ) << ” f u n c t i o n c a l l e x p r e s s i o n s ” << e n d l ; // Add p a r a m e t e r t o f u n c t i o n c a l l s f o r ( l i s t <SgNode ∗ > : : i t e r a t o r i = f u n c t i o n C a l l L i s t . b e g i n ( ) ; i != f u n c t i o n C a l l L i s t . end ( ) ; SgFunctionCallExp ∗ functionCallExp = isSgFunctionCallExp (∗ i ) ; ROSE ASSERT( f u n c t i o n C a l l E x p != NULL ) ; i ++) { i f ( isSgFunctionRefExp ( functionCallExp − g e t f u n c t i o n ( ) ) ){ > SgFunctionSymbol ∗ symbol = i s S g F u n c t i o n R e f E x p ( f u n c t i o n C a l l E x p − g e t f u n c t i o n ()) − > > get symbol i ( ) ; a s s e r t ( symbol !=NULL ) ; char ∗ name = symbol − g e t n a m e ( ) . s t r ( ) ; > // Only add t h e parameter if we h a v e modified the corresponding function i f ( m o d i f i e d F u n c t i o n N a m e s [ name ] == 1 ) { // Add t h e a d d r e s s o f t h e s t r u c t t o t h e f u n c t i o n c a l l a r g u m e n t s functionCallExp − append arg ( lookupTLStruct ( functionCallExp ) ) ; > } } else { 44 c e r r << ”We don ’ t y e t h a n d l e f u n c t i o n c a l l by p o i n t e r s ” << ” S g P o i n t e r D e r e f E x p i s , I can p r o b a b l y append t h e f u n c t i o n p a r a m e t e r ( f i l e =” << f u n c t i o n C a l l E x p − g e t f i l e i n f o ()−> g e t f i l e n a m e S t r i n g ( ) << ” ) ” << > endl ; } } } / ∗ ∗ B u i l d a l i s t o f TL V a r i a b l e R e f e r e n c e s ∗ / l i s t <SgVarRefExp ∗> b u i l d L i s t O f T L V a r i a b l e R e f e r e n c e s // r e t u r n v a r i a b l e l i s t <SgVarRefExp ∗> T L V a r i a b l e U s e L i s t ; ( SgNode ∗ node ) { // l i s t o f a l l v a r i a b l e s ( t h e n s e l e c t o u t t h e g l o b a l v a r i a b l e s b y t e s t i n g // s c o p e , o r t h e s t a t i c s b y t h e a p p r o p r i a t e manner ) l i s t <SgNode∗> n o d e L i s t = NodeQuery : : q u e r y S u b T r e e ( node , V SgVarRefExp ) ; the l i s t <SgNode ∗ > : : i t e r a t o r i = n o d e L i s t . b e g i n ( ) ; while ( i != n o d e L i s t . end ( ) ) { SgVarRefExp ∗ v a r i a b l e R e f e r e n c e E x p r e s s i o n = i s S g V a r R e f E x p ( ∗ i ) ; a s s e r t ( v a r i a b l e R e f e r e n c e E x p r e s s i o n != NULL ) ; a s s e r t ( v a r i a b l e R e f e r e n c e E x p r e s s i o n − g e t s y m b o l ( ) != NULL ) ; > a s s e r t ( v a r i a b l e R e f e r e n c e E x p r e s s i o n − g e t s y m b o l ()−> g e t d e c l a r a t i o n ( ) != NULL ) ; > a s s e r t ( v a r i a b l e R e f e r e n c e E x p r e s s i o n − g e t s y m b o l ()−> g e t d e c l a r a t i o n ()−> g e t s c o p e ( ) > != NULL ) ; S g I n i t i a l i z e d N a m e ∗ v a r i a b l e N a m e = v a r i a b l e R e f e r e n c e E x p r e s s i o n − g e t s y m b o l ()−> > get declaration (); SgScopeStatement ∗ v a r i a b l e S c o p e = variableName− g e t s c o p e ( ) ; > assert ( variableScope ) ; // Check i f t h i s i s a v a r i a b l e d e c l a r e d i n g l o b a l s c o p e , i f so , t h e n s a v e i f ( i s S g G l o b a l ( v a r i a b l e S c o p e ) != NULL) TLVariableUseList . push back ( v a r i a b l e R e f e r e n c e E x p r e s s i o n ) ; // N o t e t h a t v a r i a b l e R e f e r e n c e E x p r e s s i o n − g e t s y m b o l ()−> g e t d e c l a r a t i o n ( ) r e t u r n s t h e > // S g I n i t i a l i z e d N a m e n o t t h e S g V a r i a b l e D e c l a r a t i o n w h e r e i t was d e c l a r e d ! S g V a r i a b l e D e c l a r a t i o n ∗ v a r i a b l e D e c l a r a t i o n = i s S g V a r i a b l e D e c l a r a t i o n ( variableName− > get parent ( ) ) ; // A l s o s a v e any s t a t i c v a r i a b l e s i f ( v a r i a b l e D e c l a r a t i o n != NULL && i s V a r D e c l S t a t i c ( v a r i a b l e D e c l a r a t i o n ) ) { TLVariableUseList . push back ( v a r i a b l e R e f e r e n c e E x p r e s s i o n ) ; it } i ++; } return T L V a r i a b l e U s e L i s t ; } S g C l a s s D e c l a r a t i o n ∗ createTLClass ( SgGlobal ∗ scope ) { // We h a v e t w o options for inserting the class d e c l a r a t i o n . The first is simple , but is buggy #i f USE MIDDLELEVELREWRITE // T h i s mechanism i s n o t y e t w o r k i n g . I h a v e s u b m i t t e d a b u g r e p o r t f o r i t char newCode [ 2 5 6 ] ; s p r i n t f ( newCode , ” s t r u c t %s { v o i d ∗%s ; } ; \ n” , structName , p l a c e H o l d e r N a m e ) ; M i d d l e L e v e l R e w r i t e : : i n s e r t ( s c o p e , newCode , M i d L e v e l C o l l e c t i o n T y p e d e f s : : StatementScope , M i d L e v e l C o l l e c t i o n T y p e d e f s : : TopOfCurrentScope ) ; #e l s e Sg File Info ∗ f i l e i n f o = Sg File Info : : generateDefaultFileInfoForTransformationNode ( ) ; a s s e r t ( f i l e i n f o != NULL ) ; S g C l a s s D e f i n i t i o n ∗ c l a s s D e f i n i t i o n = new S g C l a s s D e f i n i t i o n ( f i l e i n f o ) ; a s s e r t ( c l a s s D e f i n i t i o n != NULL ) ; SgClassDeclaration ∗ classDeclaration = new S g C l a s s D e c l a r a t i o n ( f i l e i n f o , structName , S g C l a s s D e c l a r a t i o n : : e s t r u c t , NULL, classDefinition ); a s s e r t ( c l a s s D e c l a r a t i o n != NULL ) ; // S e t t h e d e f i n i n g d e c l a r a t i o n i n t h e d e f i n i n g d e c l a r a t i o n ! classDeclaration − set definingDeclaration ( classDeclaration ); > classDeclaration − s e t s c o p e ( scope ) ; > classDeclaration − s e t p a r e n t ( scope ) ; > // S e t t h e end o f c o n s t r u c t e x p l i c t l y // ( w h e r e n o t a t r a n s f o r m a t i o n t h i s i s t h e l o c a t i o n o f t h e c l o s i n g c l a s s D e f i n i t i o n − set endOfConstruct ( f i l e i n f o ) ; > brace ) 45 SgClassDeclaration ∗ nondefiningClassDeclaration = new S g C l a s s D e c l a r a t i o n ( f i l e i n f o , structName , S g C l a s s D e c l a r a t i o n : : e s t r u c t , NULL, NULL ) ; a s s e r t ( c l a s s D e c l a r a t i o n != NULL ) ; // S e t t h e i n t e r n a l r e f e r e n c e t o t h e non− d e f i n i n g d e c l a r a t i o n classDeclaration − set firstNondefiningDeclaration ( nondefiningClassDeclaration ) ; > // S e t t h e d e f i n i n g and no− d e f i n i n g d e c l a r a t i o n s i n t h e non− d e f i n i n g c l a s s d e c l a r a t i o n ! nondefiningClassDeclaration− set firstNondefiningDeclaration ( nondefiningClassDeclaration ) ; > nondefiningClassDeclaration− set definingDeclaration ( classDeclaration ) ; > n o n d e f i n i n g C l a s s D e c l a r a t i o n − setForward ( ) ; > nondefiningClassDeclaration− set scope ( classDeclaration − get scope ( ) ) ; > > classDefinition − set declaration ( classDeclaration ); > classDefinition − set parent ( classDeclaration ); > // I n s e r t a p l a c e h o l d e r v a r i a b l e for convenience in l a t e r c a l l s // Do n o t d e l e t e t h i s , a s i t i s a c t u a l l y u s e d t o i n s e r t v a r i a b l e s a f t e r i t s e l f . // For some r e a s o n t h e r e w r i t e mechanism w i l l a l l o w i n s e r t i o n o f s t a t e m e n t s a f t e r o t h e r // s t a t e m e n t s , b u t t h i s r e q u i r e s an e x i s t i n g s t a t e m e n t t o u s e SgName ∗ varname = new SgName ( p l a c e H o l d e r N a m e ) ; S g V a r i a b l e D e c l a r a t i o n ∗ v a r i a b l e = new S g V a r i a b l e D e c l a r a t i o n ( f i l e i n f o , ∗ varname , new SgTypeInt ) ; variable− set parent ( classDefinition ) ; > varname− s e t p a r e n t ( v a r i a b l e ) ; > > // varname − s e t s c o p e ( v a r i a b l e − g e t s c o p e ( ) ) ; > c l a s s D e c l a r a t i o n − g e t d e f i n i t i o n ()−> append member ( v a r i a b l e ) ; > // Insert the class declaration before the first declaration i n a non−h e a d e r file l i s t <S g D e c l a r a t i o n S t a t e m e n t ∗> d e c l s = s c o p e − g e t d e c l a r a t i o n s ( ) ; > l i s t <S g D e c l a r a t i o n S t a t e m e n t ∗ > : : i t e r a t o r d ; f o r ( d=d e c l s . b e g i n ( ) ; d != d e c l s . end ();++ d ) { // I n s e r t a f t e r t y p e d e f s t a t e m e n t s i n a non−h e a d e r f i l e i f ( ! i s S t a t e m e n t I n H e a d e r ( ∗ d ) && ! i s S g T y p e d e f D e c l a r a t i o n ( ∗ d ) ) { i n s e r t S t m t ( ∗ d , c l a s s D e c l a r a t i o n , true ) ; break ; } } #e n d i f // F i n d t h e S g C l a s s D e c l a r a t i o n f o r t h i s n e w l y i n s e r t e d c l a s s / s t r u c t // T h i s i s h e r e i f we c h o o s e some o t h e r h i g h e r l e v e l method f o r r e w r i t i n g / i n s e r t i n g t h e s t r u c t // A d d i t i o n a l l y i t i s a n i c e s a n i t y c h e c k S g C l a s s D e c l a r a t i o n ∗ n e w C l a s s D e c l a r a t i o n=NULL ; l i s t <S g D e c l a r a t i o n S t a t e m e n t ∗ > : : i t e r a t o r i = s c o p e − g e t d e c l a r a t i o n s ( ) . b e g i n ( ) ; > while ( i != s c o p e − g e t d e c l a r a t i o n s ( ) . end ( ) ) > { S g C l a s s D e c l a r a t i o n ∗ c l a s s D e c l a r a t i o n = i s S g C l a s s D e c l a r a t i o n (∗ i ) ; i f ( c l a s s D e c l a r a t i o n != NULL && s t r c m p ( structName , c l a s s D e c l a r a t i o n − g e t n a m e ( ) . s t r ())==0) > newClassDeclaration = classDeclaration ; i ++; } a s s e r t ( newClassDeclaration ) ; return n e w C l a s s D e c l a r a t i o n ; } void c o p y T L C l a s s T o F i l e ( S g C l a s s D e c l a r a t i o n ∗ c l a s s D e c l a r a t i o n , SgFile ∗ f i l e ){ file // I n s e r t t h e c l a s s d e c l a r a t i o n b e f o r e t h e f i r s t d e c l a r a t i o n i n a non−h e a d e r a s s e r t ( c l a s s D e c l a r a t i o n != NULL ) ; SgNode ∗ n = c l a s s D e c l a r a t i o n − copy ( SgTreeCopy ( ) ) ; > SgClassDeclaration ∗ classDeclarationDeepCopy = isSgClassDeclaration (n ) ; l i s t <S g D e c l a r a t i o n S t a t e m e n t ∗> d e c l s = f i l e − g e t g l o b a l S c o p e ()−> g e t d e c l a r a t i o n s ( ) ; > f o r ( l i s t <S g D e c l a r a t i o n S t a t e m e n t ∗ > : : i t e r a t o r d=d e c l s . b e g i n ( ) ; d != d e c l s . end ();++ d ) { // I n s e r t a f t e r t y p e d e f s t a t e m e n t s i n a non−h e a d e r f i l e i f ( ! i s S t a t e m e n t I n H e a d e r ( ∗ d ) && ! i s S g T y p e d e f D e c l a r a t i o n ( ∗ d ) ) { i n s e r t S t m t ( ∗ d , c l a s s D e c l a r a t i o n D e e p C o p y , true ) ; break ; } } } SgFunctionDeclaration ∗ c r e a t e T L I n i t i a l i z e r ( SgGlobal ∗ scope , a s s e r t ( TLSt ruct != NULL ) ; a s s e r t ( s c o p e != NULL ) ; S g D e c l a r a t i o n S t a t e m e n t ∗ TLStr uct ) { Sg File Info ∗ f i l e i n f o = Sg File Info : : generateDefaultFileInfoForTransformationNode ( ) ; a s s e r t ( f i l e i n f o != NULL ) ; // C r e a t e new f u n c t i o n w h i c h w i l l b e i n s e r t e d a s a member f u n c t i o n o f c l a s s S g B a s i c B l o c k ∗ bb = new S g B a s i c B l o c k ( f i l e i n f o , NULL ) ; S g F u n c t i o n D e f i n i t i o n ∗ f u n c d e f = new S g F u n c t i o n D e f i n i t i o n ( f i l e i n f o , bb ) ; bb− s e t p a r e n t ( f u n c d e f ) ; > c 46 / / S e t u p new f u n c t i o n S g R e f e r e n c e T y p e ∗ i n t P o i n t e r T y p e = new S g R e f e r e n c e T y p e ( new SgTypeInt ) ; SgName n ( ” unused : ( ” ) ; // t h i s g e t s i g n o r e d and t h e name comes f r o m s o m e w h e r e S g I n i t i a l i z e d N a m e ∗ name = new S g I n i t i a l i z e d N a m e ( n , i n t P o i n t e r T y p e , 0 , 0 , 0 ) ; name− s e t s c o p e ( f u n c d e f ) ; > S g F u n c t i o n P a r a m e t e r L i s t ∗ f p l = new S g F u n c t i o n P a r a m e t e r L i s t ( f i l e i n f o ) ; f p l − a p p e n d a r g ( name ) ; > name− s e t p a r e n t ( f p l ) ; > SgFunctionType ∗ f u n c t y p e = new SgFunctionType ( new SgTypeVoid ( ) , FALSE ) ; SgName f u n c n a m e ( initFuncName ) ; S g F u n c t i o n D e c l a r a t i o n ∗ f d e c l= new S g F u n c t i o n D e c l a r a t i o n ( f i l e i n f o , funcdef− s e t d e c l a r a t i o n ( f d e c l ) ; > i n s e r t S t m t ( TLStruct , return } fdecl ; fdecl , false ) ; else func name , func type , funcdef ) ; / ∗ ∗ Put e a c h TL v a r i a b l e i n t o t h e TL s t r u c t and r e m o v e i t s o r i g i n a l d e c l a r a t i o n void m o v e T L V a r i a b l e s I n t o C l a s s ( l i s t < S g I n i t i a l i z e d N a m e ∗> & g l o b a l V a r i a b l e s , l i s t < S g I n i t i a l i z e d N a m e ∗> & s t a t i c V a r i a b l e s , SgClassDeclaration ∗ classDeclaration ) { // Remove a l l d u p l i c a t e s f r o m t h e g l o b a l removeDuplicates ( g l o b a l V a r i a b l e s ) ; variable list ∗/ S g V a r i a b l e S y m b o l ∗ g l o b a l C l a s s V a r i a b l e S y m b o l = NULL ; Sg File Info ∗ f i l e i n f o = Sg File Info : : generateDefaultFileInfoForTransformationNode ( ) ; //=============================================================== // Add i n t h e g l o b a l s f o r ( l i s t <S g I n i t i a l i z e d N a m e ∗ > : : i t e r a t o r v a r = g l o b a l V a r i a b l e s . b e g i n ( ) ; v a r != g l o b a l V a r i a b l e s . end ( ) ; v a r ++){ #i f d e f DEBUG c o u t << ” Adding v a r i a b l e ” << ( ∗ v a r)−> g e t n a m e ( ) . g e t S t r i n g ( ) << ” t o #e n d i f s t r u c t ” << e n d l ; ; S g V a r i a b l e D e c l a r a t i o n ∗ g l o b a l V a r i a b l e D e c l a r a t i o n = i s S g V a r i a b l e D e c l a r a t i o n ( ( ∗ v a r)−> get parent ( ) ) ; a s s e r t ( g l o b a l V a r i a b l e D e c l a r a t i o n != NULL ) ; // Get t h e g l o b a l s c o p e f r o m t h e g l o b a l v a r i a b l e d i r e c t l y SgGlobal ∗ g l o ba l S c o p e = i s S g G l o b a l ( g l o b a l V a r i a b l e D e c l a r a t i o n − g e t s c o p e ( ) ) ; > S g I n i t i a l i z e d N a m e ∗ in = ∗( g l o b a l V a r i a b l e D e c l a r a t i o n − g e t v a r i a b l e s ( ) . begin ( ) ) ; > a s s e r t ( g l o b a l S c o p e != NULL ) ; SgVariableDeclaration ∗ firstVarInStruct = isSgVariableDeclaration (∗( classDeclaration −> g e t d e f i n i t i o n ()−> g e t D e c l a r a t i o n L i s t ( ) . b e g i n ( ) ) ) ; // t h e r e s h o u l d b e a t l e a s t some p l a c e h o l d e r a s s e r t ( f i r s t V a r I n S t r u c t !=NULL ) ; or real variables in this struct /∗ 2 options here : null e x p r e s s i o n and move comments o n t o it 1) Create a 2 ) move comments o n t o n e x t d e c l a r a t i o n This s h o u l d work s i n c e t h e r e w i l l p r o b a b l y n e v e r be a g l o b a l v a r i a b l e at the bottom of a f i l e , and e v e n i f t h e r e i s , i t s a t t a c h e d comments won ’ t l i k e l y b e m i s s e d :) ∗/ // R e a s s o c i a t e any comments / p r e p r o c e s s o r statements to the next declaration // f i n d n e x t d e c l a r a t i o n l i s t <S g D e c l a r a t i o n S t a t e m e n t ∗> & d e c l l i s t = globalScope− g e t d e c l a r a t i o n s ( ) ; > S g D e c l a r a t i o n S t a t e m e n t ∗ ds = g l o b a l V a r i a b l e D e c l a r a t i o n ; l i s t <S g D e c l a r a t i o n S t a t e m e n t ∗ > : : i t e r a t o r i = f i n d ( d e c l l i s t . b e g i n ( ) , d e c l l i s t . end ( ) , d s ) ; S g D e c l a r a t i o n S t a t e m e n t ∗ f o l l o w i n g D e c l=NULL ; i f ( i != d e c l l i s t . end ( ) && ( i ++)!= d e c l l i s t . end ( ) ) { // I f t h e r e i s a f o l l o w i n g d e c l a r a t i o n followingDecl = ∗ i ; reassociatePreprocessorDeclarations ( globalVariableDeclaration , followingDecl ); } e l s e { // I f t h e r e i s no f o l l o w i n g d e c l a r a t i o n . We s h o u l d p r o b a b l y a t t a c h t o p r e v i o u s one c e r r << ”ERROR: n o t y e t i m p l e m e n t e d : r e a s s o c i a t i n g comments when no ” << ” d e c l a r a t i o n i s a f t e r t h e g l o b a l i n a f i l e ” << e n d l ; } 47 / / As u s u a l , t h e h i g h e r l e v e l m e c h a n i s m s ( h e r e L o w L e v e l R e w r i t e ) , don ’ t // Here t h e i n s e r t i o n j u s t d o e s n ’ t h a p p e n ??? n o t s u r e why y e t // Remove t h e v a r i a b l e #i f 1 work // T h i s one d o e s n ’ t d e t a c h comments and p r e p r o c e s s o r s t u f f b e f o r e m o v i n g // Thus an i n c l u d e s t a t e m e n t c o u l d move i n t o t h e c l a s s : ( SgStatement ∗ parent = isSgStatement ( g l o b a l V a r i a b l e D e c l a r a t i o n − g e t p a r e n t ( ) ) ; > a s s e r t ( parent ) ; parent− remove statement ( g l o b a l V a r i a b l e D e c l a r a t i o n ) ; > #e l s e L o w L e v e l R e w r i t e : : remove ( g l o b a l V a r i a b l e D e c l a r a t i o n ) ; #e n d i f // F i x u p t h e v a r i a b l e t o make s u r e i t i s o u t p u t , and n o t globalVariableDeclaration − s e t f i l e i n f o ( f i l e i n f o ); > clinging to its original file // Add t h e #i f 1 variable to the class c l a s s D e c l a r a t i o n − g e t d e f i n i t i o n ()−> append member ( g l o b a l V a r i a b l e D e c l a r a t i o n ) ; > globalVariableDeclaration − set parent ( classDeclaration − get definition ( ) ) ; > > #e l s e S g D e c l a r a t i o n S t a t e m e n t P t r L i s t & d e c l l i s t = c l a s s D e c l a r a t i o n − g e t d e f i n i t i o n ()−> g e t m e m b e r s ( ) ; > SgDeclarationStatement ∗ f i r s t D e c l = ∗ d e c l l i s t . begin ( ) ; i n s e r t S t m t ( f i r s t D e c l , g l o b a l V a r i a b l e D e c l a r a t i o n , FALSE ) ; #e n d i f } //============================================================== // Add i n t h e s t a t i c v a r i a b l e s // S t a t i c s can b e g l o b a l o r n o t g l o b a l // I f g l o b a l , t h e y h a v e a l r e a d y b e e n moved i n t o t h e s t r u c t , and we s h o u l d n o t a t t e m p t t o move // them a g a i n . We s h o u l d h o w e v e r rename them w i t h some m a n g l e d s c o p e c o n t a i n i n g a f i l e n a m e f o r ( l i s t <S g I n i t i a l i z e d N a m e ∗ > : : i t e r a t o r v a r = s t a t i c V a r i a b l e s . b e g i n ( ) ; v a r != s t a t i c V a r i a b l e s . end ( ) ; v a r ++){ S g F i l e I n f o ∗ f i l e i n f o =( ∗ v a r)−> g e t f i l e i n f o ( ) ; // I f t h i s i s a g l o b a l v a r i a b l e , t h e n don ’ t move i t i n t o t h e s t r u c t a g a i n i f ( f i n d ( g l o b a l V a r i a b l e s . b e g i n ( ) , g l o b a l V a r i a b l e s . end ( ) , ∗ v a r ) == g l o b a l V a r i a b l e s . end ( ) ) { S g V a r i a b l e D e c l a r a t i o n ∗ s t a t i c V a r i a b l e D e c l a r a t i o n = i s S g V a r i a b l e D e c l a r a t i o n ( ( ∗ var ) −> g e t p a r e n t ( ) ) ; a s s e r t ( s t a t i c V a r i a b l e D e c l a r a t i o n != NULL ) ; SgVariableDeclaration ∗ firstVarInStruct = isSgVariableDeclaration (∗( classDeclaration − > g e t d e f i n i t i o n ()−> g e t D e c l a r a t i o n L i s t ( ) . b e g i n ( ) ) ) ; // t h e r e s h o u l d b e a t l e a s t some p l a c e h o l d e r o r r e a l v a r i a b l e s i n t h i s s t r u c t assert ( firstVarInStruct ); // TODO: S e e n o t e f o r g l o b a l s a b o v e SgStatement ∗ parent = isSgStatement ( s t a t i c V a r i a b l e D e c l a r a t i o n − g e t p a r e n t ( ) ) ; > a s s e r t ( parent ) ; parent− remove statement ( s t a t i c V a r i a b l e D e c l a r a t i o n ) ; > c l a s s D e c l a r a t i o n − g e t d e f i n i t i o n ()−> append member ( s t a t i c V a r i a b l e D e c l a r a t i o n ) ; > assert ( staticVariableDeclaration − get parent ( ) ) ; > } // Remove t h e s t a t i c c l a s s i f i e r S g D e c l a r a t i o n S t a t e m e n t ∗ d e c l = ( ∗ v a r)−> g e t d e c l a r a t i o n ( ) ; S g D e c l a r a t i o n M o d i f i e r &d e c l M o d i f i e r = d e c l − g e t d e c l a r a t i o n M o d i f i e r ( ) ; > S g S t o r a g e M o d i f i e r &s t o r a g e M o d i f i e r = d e c l M o d i f i e r . g e t s t o r a g e M o d i f i e r ( ) ; storageModifier . setDefault ( ) ; assert (! storageModifier . isStatic ( ) ) ; // R e p l a c e name w i t h m a n g l e d name // TODO: s i m p l i f y t h e s e i f p o s s i b l e ( ∗ v a r)−> s e t n a m e ( ( ∗ v a r)−> g e t m a n g l e d n a m e ( ) ) ; } c o u t << e n d l ; return ; } void f i x u p R e f e r e n c e s T o T L V a r i a b l e s ( { l i s t <SgVarRefExp ∗> & v a r i a b l e R e f e r e n c e L i s t ) // Now f i x u p t h e SgVarRefExp t o r e f e r e n c e t h e g l o b a l v a r i a b l e s t h r o u g h a f o r ( l i s t <SgVarRefExp ∗ > : : i t e r a t o r v a r = v a r i a b l e R e f e r e n c e L i s t . b e g i n ( ) ; v a r != v a r i a b l e R e f e r e n c e L i s t . end ( ) ; v a r++) { a s s e r t ( ∗ v a r != NULL ) ; SgNode ∗ p a r e n t = ( ∗ v a r)−> g e t p a r e n t ( ) ; a s s e r t ( p a r e n t != NULL ) ; // I f t h i s i s n o t an e x p r e s s i o n t h e n i s l i k e l y a m e a n i n g l e s s SgExpression ∗ parentExpression = isSgExpression ( parent ) ; a s s e r t ( p a r e n t E x p r e s s i o n != NULL ) ; struct statement such as (” x ; ” ) 48 // B u i l d the reference through the global class variable ( ” x ” −−> ” A M P I g l o b a l s . x ” ) // B u i l d s o u r c e p o s i t i o n i n f o r m a t i o n ( marked a s t r a n s f o r m a t i o n ) Sg File Info ∗ f i l e i n f o = Sg File Info : : generateDefaultFileInfoForTransformationNode ( ) ; a s s e r t ( f i l e i n f o != NULL ) ; // Lookup t h e c o r r e c t s t r u c t t o u s e f o r t h e SgExpression ∗ l h s = lookupTLStruct (∗ var ) ; assert ( lhs ); redirected reference // B u i l d ” A M P I g l o b a l s . x ” f r o m ” x ” SgArrowExp ∗ r e d i r e c t e d R e f e r e n c e = new SgArrowExp ( f i l e i n f o , l h s , ∗ v a r ) ; a s s e r t ( r e d i r e c t e d R e f e r e n c e != NULL ) ; if ( p a r e n t E x p r e s s i o n != NULL) { // I n t r o d u c e r e f e r e n c e t o ∗ v a r through the data structure // c a s e o f b i n a r y o p e r a t o r SgUnaryOp ∗ u n a r y O p e r a t o r = isSgUnaryOp ( p a r e n t E x p r e s s i o n ) ; i f ( u n a r y O p e r a t o r != NULL) { unaryOperator− s e t o p e r a n d ( r e d i r e c t e d R e f e r e n c e ) ; > } else { // c a s e o f b i n a r y o p e r a t o r SgBinaryOp ∗ b i n a r y O p e r a t o r ; S g E xp r L i s t E xp ∗ e x p r L i s t E x p ; SgAssignInitializer∗ assignInitializer ; S g C o n d i t i o n a l E x p ∗ condExp ; SgSizeOfOp ∗ s i z e o f E x p ; i f ( binaryOperator = isSgBinaryOp ( p a r e n t E x p r e s s i o n ) ) { // f i g u r e o u t i f t h e ∗ v a r i s on t h e l h s o r t h e r h s i f ( b i n a r y O p e r a t o r − g e t l h s o p e r a n d ( ) == ∗ v a r ) > { binaryOperator− s e t l h s o p e r a n d ( r e d i r e c t e d R e f e r e n c e ) ; > } else { a s s e r t ( b i n a r y O p e r a t o r − g e t r h s o p e r a n d ( ) == ∗ v a r ) ; > binaryOperator− s e t r h s o p e r a n d ( r e d i r e c t e d R e f e r e n c e ) ; > } } else i f ( exprListExp = isSgExprListExp ( parentExpression )){ // Where t h e v a r i a b l e a p p e a r s i n t h e f u n c t i o n a r g u m e n t l i s t t h e // p a r e n t i s a S g E x p r L i s t E x p e x p r L i s t E x p − r e p l a c e e x p r e s s i o n ( ∗ var , r e d i r e c t e d R e f e r e n c e ) ; > // FIXME : T h i s c a l l i s d e p r e c a t e d } else i f ( a s s i g n I n i t i a l i z e r = i s S g A s s i g n I n i t i a l i z e r ( parentExpression )){ a s s i g n I n i t i a l i z e r − set operand ( redirectedReference ) ; > } e l s e i f ( condExp = i s S g C o n d i t i o n a l E x p ( p a r e n t E x p r e s s i o n ) ) { // The t r i n a r y o p e r a t o r ? : i f ( condExp− g e t c o n d i t i o n a l e x p ( ) == ∗ v a r ) > { condExp− s e t c o n d i t i o n a l e x p ( r e d i r e c t e d R e f e r e n c e ) ; > } e l s e i f ( condExp− g e t t r u e e x p ( ) == ∗ v a r ) > { condExp− s e t t r u e e x p ( r e d i r e c t e d R e f e r e n c e ) ; > } e l s e i f ( condExp− g e t f a l s e e x p ( ) == ∗ v a r ) > { condExp− s e t f a l s e e x p ( r e d i r e c t e d R e f e r e n c e ) ; > } else { a s s e r t ( 0 && ” some c o n d i t i o n a l o p e r a t o r b r o k e n ” ) ; } } else i f ( sizeofExp = isSgSizeOfOp ( parentExpression )){ i f ( s i z e o f E x p − g e t o p e r a n d e x p r ( ) == ∗ v a r ) > { sizeofExp− set operand expr ( redirectedReference ) ; > } else { a s s e r t ( 0 && ” s i z e o f o p e r a t o r b r o k e n ” ) ; } { // i g n o r e t h e s e c a s e s f o r now ! switch ( p a r e n t E x p r e s s i o n − v a r i a n t T ( ) ) { > case V S g I n i t i a l i z e r : case V SgRefExp : case V SgVarArgOp : default : { c e r r << ”BAD E r r o r : d e f a u l t r e a c h e d i n ” ” switch p a r e n t E x p r e s s i o n = ” << e n d l ; } } } } } } } } else 49 v oid t r a n s f o r m T L V a r i a b l e s T o U s e S t r u c t ( { // C a l l t h e t r a n s f o r m a t i o n o f e a c h // o b j e c t s when m u l t i p l e f i l e s a r e a s s e r t ( p r o j e c t != NULL ) ; SgProject ∗ project ) f i l e ( th e r e are m u l t i p l e SgFile s p e c f i e d on t h e command l i n e ! ) . // T h e s e a r e t h e g l o b a l v a r i a b l e s i n t h e i n p u t p r o g r a m ( p r o v i d e d a s h e l p f u l i n f o r m a t i o n ) l i s t < S g I n i t i a l i z e d N a m e ∗> g l o b a l V a r i a b l e s = b u i l d L i s t O f G l o b a l V a r i a b l e s ( p r o j e c t ) ; l i s t < S g I n i t i a l i z e d N a m e ∗> s t a t i c V a r i a b l e s = b u i l d L i s t O f S t a t i c V a r i a b l e s ( p r o j e c t ) ; #i f d e f DEBUG c o u t << ” P r o j e c t Wide : g l o b a l v a r i a b l e s : ” << e n d l ; f o r ( l i s t < S g I n i t i a l i z e d N a m e ∗ > : : i t e r a t o r v a r = g l o b a l V a r i a b l e s . b e g i n ( ) ; v a r != g l o b a l V a r i a b l e s . end ( ) ; v a r++) c o u t << ” ” << ( ∗ v a r)−> g e t n a m e ( ) . s t r ( ) << e n d l ; c o u t << e n d l ; c o u t << ” P r o j e c t Wide : s t a t i c v a r i a b l e s : ” << e n d l ; f o r ( l i s t < S g I n i t i a l i z e d N a m e ∗ > : : i t e r a t o r v a r = s t a t i c V a r i a b l e s . b e g i n ( ) ; v a r != s t a t i c V a r i a b l e s . end ( ) ; v a r ++){ c o u t << ” ” << ( ∗ v a r)−> g e t n a m e ( ) . s t r ( ) << ” ; mangled =” << ( ∗ v a r)−> g e t m a n g l e d n a m e ( ) . s t r ( ) << e n d l ; S g F i l e I n f o ∗ f i l e i n f o =( ∗ v a r)−> g e t f i l e i n f o ( ) ; c o u t << ” was i n f i l e ” << f i l e i n f o − g e t f i l e n a m e S t r i n g ( ) << e n d l ; > } c o u t << e n d l ; #e n d i f SgFilePtrList ∗ f i l e L i s t = project− g e t f i l e L i s t ( ) ; > SgFilePtrList : : iterator f i l e ; SgClassDeclaration ∗ classDeclaration SgFunctionDeclaration ∗ TLInit ; // F i r s t h a n d l e t h e main f i l e bool f o u n d F i l e M a i n = f a l s e ; for ( f i l e =f i l e L i s t − begin ( ) ; f i l e > if ( ; != f i l e L i s t − end ( ) ; ++ f i l e ) > { overwrite existing files ) ( ∗ f i l e )−> s e t u n p a r s e o u t p u t f i l e n a m e ( ( ∗ f i l e )−> g e t s o u r c e F i l e N a m e W i t h P a t h ( ) ); i f ( i s F i l e M a i n (∗ f i l e )){ c o u t << ” Found main i n file ” << ( ∗ f i l e )−> g e t f i l e i n f o ()−> g e t f i l e n a m e S t r i n g ( ) << e n d l ; // s h o u l d only b e one main file a s s e r t ( f o u n d F i l e M a i n == f a l s e ) ; f o u n d F i l e M a i n = true ; // g e t t h e g l o b a l s c o p e w i t h i n t h e f i l e S g G l o b a l ∗ g l o b a l S c o p e = ( ∗ f i l e )−> g e t g l o b a l S c o p e ( ) ; a s s e r t ( g l o b a l S c o p e != NULL ) ; // B u i l d t h e c l a s s d e c l a r a t i o n Sg File Info ∗ f i l e i n f o = Sg File Info : : generateDefaultFileInfoForTransformationNode ( ) ; a s s e r t ( f i l e i n f o != NULL ) ; c l a s s D e c l a r a t i o n = createTLClass ( globalScope ) ; // C r e a t e t h e i n i t i a l i z e r f u n c t i o n TLInit = c r e a t e T L I n i t i a l i z e r ( globalScope , c l a s s D e c l a r a t i o n ) ; // F i n d r e f e r e n c e s t o TL v a r i a b l e s l i s t <SgVarRefExp ∗> v a r i a b l e R e f e r e n c e L i s t = b u i l d L i s t O f T L V a r i a b l e R e f e r e n c e s ( p r o j e c t ) ; #i f d e f DEBUG c o u t << ”TL v a r i a b l e s r e f e r e n c e d i n t h i s p r o j e c t ( a l l f i l e s ) ” << e n d l ; f o r ( l i s t <SgVarRefExp ∗ > : : i t e r a t o r v a r = v a r i a b l e R e f e r e n c e L i s t . b e g i n ( ) ; v a r != v a r i a b l e R e f e r e n c e L i s t . end ( ) ; v a r++) c o u t << ” ” << ( ∗ v a r)−> g e t s y m b o l ()−> g e t d e c l a r a t i o n ()−> g e t n a m e ( ) . s t r ( ) c o u t << e n d l ; #e n d i f // Put t h e g l o b a l v a r i a b l e s i n t o t h e c l a s s , r e m o v i n g t h e o r i g i n a l d e c l a r a t i o n s moveTLVariablesIntoClass ( g l o b a l V a r i a b l e s , s t a t i c V a r i a b l e s , c l a s s D e c l a r a t i o n ) ; // C r e a t e t h e s t r u c t on t h e s t a c k and add i t a s a p a r a m e t e r t o // a l l f u n c t i o n c a l l s and d e c l a r a t i o n s declareClassAndInitInMain ( globalScope , c l a s s D e c l a r a t i o n , TLInit ) ; addTLClassAsParameter ( p r o j e c t , classDeclaration ); the variable through the class ; // F i x u p a l l r e f e r e n c e s t o T h r e a d L o c a l v a r i a b l e t o a c c e s s // ( ” x ” −−> ” A M P I s t r u c t . x ” ) fixupReferencesToTLVariables ( variableReferenceList ) ; // move a l l i n i t i a l i z e r s i n t o c l a s s f i x u p I n i t i a l i z e r s ( classDeclaration , } } i f ( f o u n d F i l e M a i n == f a l s e ) { from t h e TLInit ) ; variables that 50 c e r r << ”ERROR: Didn ’ t f i n d a f i l e c o n t a i n i n g main ( ) ”We c u r r e n t l y must have s u c h a f i l e ” << e n d l ; return ; } or similar . ” // C l e a n u p s t r u c t b y r e m o v i n g t h e t e m p o r a r a y p l a c e h o l d e r fixupClassDeclarationPlaceHolder ( classDeclaration ) ; variable declaration // C l e a n u p on e a c h f i l e f o r ( f i l e = f i l e L i s t − b e g i n ( ) ; f i l e != f i l e L i s t − end ( ) ; ++ f i l e ) { > > // Put t h e s t r u c t d e f i n i t i o n i n t h e t o p o f a l l f i l e s i f ( ! i s F i l e M a i n (∗ f i l e )){ c o u t << ” f i l e n a m e= ” << ( ∗ f i l e )−> g e t F i l e N a m e ( ) << e n d l ; copyTLClassToFile ( c l a s s D e c l a r a t i o n , ∗ f i l e ) ; } // Remove any ” e x t e r n ” d e f i n i t i o n s f r o m t h e g l o b a l s c o p e o f t h i s f i l e S g G l o b a l ∗ g l o b a l S c o p e = ( ∗ f i l e )−> g e t g l o b a l S c o p e ( ) ; a s s e r t ( g l o b a l S c o p e != NULL ) ; l i s t <S g D e c l a r a t i o n S t a t e m e n t ∗> d e c l s = g l o b a l S c o p e − g e t d e c l a r a t i o n s ( ) ; > l i s t <S g D e c l a r a t i o n S t a t e m e n t ∗ > : : i t e r a t o r i ; f o r ( i=d e c l s . b e g i n ( ) ; i != d e c l s . end ( ) ; ++i ) { S g V a r i a b l e D e c l a r a t i o n ∗ varDecl = i s S g V a r i a b l e D e c l a r a t i o n (∗ i ) ; i f ( v a r D e c l != NULL && i s V a r D e c l E x t e r n ( v a r D e c l ) ) { globalScope− remove statement ( varDecl ) ; > } } } } // ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ // MAIN PROGRAM // ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ i n t main ( i n t a r g c , char ∗ a r g v [ ] ) { c o u t << ”============================================” << e n d l ; c o u t << ” Thread L o c a l V a r i a b l e E n c a p s u l a t i o n T r a n s l a t o r . \ n I f l a s t command l i n e argument ” \”−OVERWRITE\ ” t h e n t h e s o u r c e c o d e w i l l be o v e r w r i t t e n ” << e n d l ; i f ( s t r i n g ( a r g v [ a r g c − 1 ] ) == s t r i n g ( ”−OVERWRITE” ) ) { c o u t << ” I am OVERWRITING a l l y o u r s o u r c e o v e r w r i t e e x i s t i n g f i l e s = true ; } else { o v e r w r i t e e x i s t i n g f i l e s = false ; } is ” files :) ” << e n d l << e n d l ; c o u t << ”============================================” << e n d l ; // B u i l d t h e AST u s e d b y ROSE // S t r i p o f f l a s t p a r a m e t e r ”−OVERWRITE” i f we h a v e i t S g P r o j e c t ∗ p r o j e c t = f r o n t e n d ( o v e r w r i t e e x i s t i n g f i l e s ? a r g c − 1: a r g c , a s s e r t ( p r o j e c t != NULL ) ; // t r a n s f o r m a p p l i c a t i o n a s r e q u i r e d transformTLVariablesToUseStruct ( p r o j e c t ) ; #i f 1 generateDOT ( ∗ p r o j e c t ) ; generatePDF ( ∗ p r o j e c t ) ; #e n d i f // Code g e n e r a t i o n p h a s e ( w r i t e return backend ( p r o j e c t ) ; } o u t new a p p l i c a t i o n ” r o s e < i n p u t file name > ”) argv ) ; 51 Appendix B Automated Performance Tracing: Code Listing The following is the source code for the Automated Performance Tracing-Call Insertion tool described in Chapter 4. The main source file for this translator is globalVariableRewrite.C. Additionally the shared code described in Appendix D is required. /∗ I n s e r t p e r f o r m a n c e p r o f i l i n g c a l l s i n t o AMPI c o d e s . We w o u l d l i k e b e t t e r p r o f i l i n g o f MPI c o d e s w i t h P r o j e c t i o n s . Author : ∗/ Isaac Dooley #include #include #include #include <i o s t r e a m > <a l g o r i t h m > <s t r i n g > < r o s e . h> #include <g l o b a l V a r i a b l e C o m m o n . h> using namespace s t d ; /∗ ∗ B u i l d a d e p t h =0 d e p t h =1 d e p t h =2 l i s t o f f u n c t i o n s w i t h i n a s p e c i f i e d c a l l d e p t h f r o m main means j u s t main w i l l b e i n c l u d e d means j u s t main o r f u n c t i o n s c a l l e d b y main w i l l b e i n c l u d e d means t h o s e i n d e p t h =1 and any c a l l e d b y them i s i n t h e l i s t O b v i o u s l y i t i s h a r d t o do much w i t h f u n c t i o n p o i n t e r s , s o we i g n o r e them . ∗/ l i s t <S g F u n c t i o n D e c l a r a t i o n ∗> b u i l d F u n c t i o n D e f s T o D e p t h ( i n t depth , S g P r o j e c t ∗ p r o j e c t ) { l i s t <S g F u n c t i o n D e c l a r a t i o n ∗> f u n c D e c l L i s t ; l i s t <SgNode∗> f u n c D e c l s = NodeQuery : : q u e r y S u b T r e e ( p r o j e c t , V S g F u n c t i o n D e c l a r a t i o n ) ; f o r ( l i s t <SgNode ∗ > : : i t e r a t o r i = f u n c D e c l s . b e g i n ( ) ; i != f u n c D e c l s . end ( ) ; i ++) { i f ( isFunctionMain ( i s S g F u n c t i o n D e c l a r a t i o n (∗ i ) ) ) { f u n c D e c l L i s t . push back ( i s S g F u n c t i o n D e c l a r a t i o n (∗ i ) ) ; } } f o r ( i n t d =0;d<d e p t h ; d++){ l i s t <S g F u n c t i o n D e c l a r a t i o n ∗> newFuncs ; // f o r e a c h f u n c t i o n i n t h e l i s t f o r ( l i s t <S g F u n c t i o n D e c l a r a t i o n ∗ > : : i t e r a t o r i = f u n c D e c l L i s t . b e g i n ( ) ; i != f u n c D e c l L i s t . end ( ) ; i ++) { // f i n d any S g F u n c t i o n R e f E x p i n s i d e t h e f u n c t i o n s l i s t <SgNode∗> c h i l d R e f s = NodeQuery : : q u e r y S u b T r e e ( ∗ i , V SgFunctionRefExp ) ; f o r ( l i s t <SgNode ∗ > : : i t e r a t o r i = c h i l d R e f s . b e g i n ( ) ; i != c h i l d R e f s . end ( ) ; i ++) { S g F u n c t i o n D e c l a r a t i o n ∗ f d e c l = i s S g F u n c t i o n R e f E x p ( ∗ i )−> g e t s y m b o l ()−> g e t d e c l a r a t i o n ( ) ; newFuncs . p u s h b a c k ( f d e c l ) ; } } newFuncs . s o r t ( ) ; f u n c D e c l L i s t . merge ( newFuncs ) ; removeDuplicates ( funcDeclList ) ; 52 c o u t << ” Found ” << f u n c D e c l L i s t . s i z e ( ) << ” f u n c t i o n s } return f u n c D e c l L i s t ; } to trace a t d e p t h ” << d+1 << e n d l ; void i n s e r t T i m e r C a l l s ( S g B a s i c B l o c k ∗ bb , SgStatement ∗ begin , S g S t a t e m e n t ∗ end ) { S g S t a t e m e n t ∗ b e g i n c o p y = i s S g S t a t e m e n t ( b e g i n − copy ( SgTreeCopy ( ) ) ) ; > S g S t a t e m e n t ∗ endcopy = i s S g S t a t e m e n t ( end− copy ( SgTreeCopy ( ) ) ) ; > a s s e r t ( b e g i n c o p y != NULL && endcopy != NULL ) ; bb− p r e p e n d s t a t e m e n t ( b e g i n c o p y ) ; > // don ’ t a p p e n d t o main s i n c e main a l w a y s h a s a r e t u r n s t a t e m e n t ( a l b e i t i m p l i c i t l y s o m e t i m e s ) a s s e r t ( bb != NULL ) ; a s s e r t ( i s S g F u n c t i o n D e f i n i t i o n ( bb− g e t p a r e n t ( ) ) != NULL ) ; > S g F u n c t i o n D e c l a r a t i o n ∗ f d e c l = i s S g F u n c t i o n D e f i n i t i o n ( bb− g e t p a r e n t ()) − > g e t d e c l a r a t i o n ( ) ; > a s s e r t ( f d e c l !=NULL ) ; i f ( ! isFunctionMain ( f d e c l ) ) bb− a p p e n d s t a t e m e n t ( endcopy ) ; > // also insert it before any r e t u r n statements l i s t <SgNode∗> r e t u r n s = NodeQuery : : q u e r y S u b T r e e ( bb , V SgReturnStmt ) ; f o r ( l i s t <SgNode ∗ > : : i t e r a t o r i = r e t u r n s . b e g i n ( ) ; i != r e t u r n s . end ( ) ; i ++) { endcopy = i s S g S t a t e m e n t ( end− copy ( SgTreeCopy ( ) ) ) ; // make a c o p y t o i n s e r t > i n s e r t S t m t ( i s S g S t a t e m e n t ( ∗ i ) , endcopy , true ) ; } } void i n s e r t T i m e r C a l l s ( S g F u n c t i o n D e f i n i t i o n ∗ f u n c , S g F u n c t i o n D e c l a r a t i o n ∗ beginFuncDecl , S g F u n c t i o n D e c l a r a t i o n ∗ endFuncDecl , S g F u n c t i o n D e c l a r a t i o n ∗ regFuncDecl , S g F u n c t i o n D e c l a r a t i o n ∗ mainFunc ) { Sg File Info∗ f i l e i n f o = Sg File Info : : generateDefaultFileInfoForTransformationNode ( ) ; // F i r s t c r e a t e t h e c a l l t o t r a c e B e g i n F u n c P r o j SgFunctionSymbol ∗ s t a r t F u n c S y m b o l = new SgFunctionSymbol ( b e g i n F u n c D e c l ) ; // TODO: P r o b a b l y n o t c o r r e c t , b u t i t w o r k s f o r now SgFunctionType ∗ s t a r t F u n c T y p e = new SgFunctionType ( new SgTypeVoid ( ) ) ; SgFunctionRefExp ∗ s t a r t F u n c t i o n R e f E x p = new SgFunctionRefExp ( f i l e i n f o , s t a r t F u n c S y m b o l , s t a r t F u n c T y p e ) ; S g E xp r L i s t E xp ∗ s t a r t A r g L i s t = new S g E xp r L i s t E xp ( f i l e i n f o ) ; S g S t r i n g V a l ∗ s t a r t p a r a m 1 = new S g S t r i n g V a l ( f i l e i n f o , f u n c − g e t d e c l a r a t i o n ()−> g e t n a m e ( ) . s t r ( ) > startArgList − append expression ( startparam1 ) ; > S g S t r i n g V a l ∗ s t a r t p a r a m 2 = new S g S t r i n g V a l ( f i l e i n f o , ” UnknownFile ” ) ; startArgList − append expression ( startparam2 ) ; > S g I n t V a l ∗ s t a r t p a r a m 3 = new S g I n t V a l ( f i l e i n f o , 1 ) ; startArgList − append expression ( startparam3 ) ; > SgFunctionCallExp ∗ s t a r t F u n c C a l l = new S g F u n c t i o n C a l l E x p ( f i l e i n f o , s t a r t F u n c t i o n R e f E x p , s t a r t A r g L i s t , s t a r t F u n c T y p e ) ; SgExpressionRoot ∗ startExprRoot = new S g E x p r e s s i o n R o o t ( f i l e i n f o , s t a r t F u n c C a l l , s t a r t F u n c T y p e ) ; SgExprStatement ∗ s t a r t S t a t e m e n t = new SgExprStatement ( f i l e i n f o , s t a r t E x p r R o o t ) ; ); // S e c o n d c r e a t e t h e c a l l t o t r a c e E n d F u n c P r o j SgFunctionSymbol ∗ endFuncSymbol = new SgFunctionSymbol ( endFuncDecl ) ; // TODO: P r o b a b l y n o t c o r r e c t , b u t i t w o r k s f o r now SgFunctionType ∗ endFuncType = new SgFunctionType ( new SgTypeVoid ( ) ) ; SgFunctionRefExp ∗ e n dF u nc t i o nR e f Exp = new SgFunctionRefExp ( f i l e i n f o , endFuncSymbol , endFuncType ) ; S g E xp r L i s t E xp ∗ e n d A r g L i s t = new S g E xp r L i s t E xp ( f i l e i n f o ) ; S g S t r i n g V a l ∗ endparam1 = new S g S t r i n g V a l ( f i l e i n f o , f u n c − g e t d e c l a r a t i o n ()−> g e t n a m e ( ) . s t r ( ) ) ; > e n d A r g L i s t − a p p e n d e x p r e s s i o n ( endparam1 ) ; > SgFunctionCallExp ∗ endFuncCall = new S g F u n c t i o n C a l l E x p ( f i l e i n f o , endFunctionRefExp , e n d A r g L i s t , endFuncType ) ; S g E x p r e s s i o n R o o t ∗ endExprRoot = new S g E x p r e s s i o n R o o t ( f i l e i n f o , en dFuncCall , endFuncType ) ; SgExprStatement ∗ e n d S t a t e m e n t = new SgExprStatement ( f i l e i n f o , endExprRoot ) ; S g B a s i c B l o c k ∗ body = f u n c − g e t b o d y ( ) ; > i f ( body && ! body− g e t s t a t e m e n t s ( ) . empty ( ) ) > { i n s e r t T i m e r C a l l s ( body , s t a r t S t a t e m e n t , } endStatement ) ; // F i n a l l y i n s e r t t h e r e g i s t e r c a l l t o t h e t o p o f main SgFunctionSymbol ∗ regFuncSymbol = new SgFunctionSymbol ( r e g F u n c D e c l ) ; // TODO: P r o b a b l y n o t c o r r e c t , b u t i t w o r k s f o r now SgFunctionType ∗ regFuncType = new SgFunctionType ( new SgTypeVoid ( ) ) ; SgFunctionRefExp ∗ r e g F u n c t i o n R e f E x p = new SgFunctionRefExp ( f i l e i n f o , S g E xp r L i s t E xp ∗ r e g A r g L i s t = new S g E xp r L i s t E xp ( f i l e i n f o ) ; regFuncSymbol , regFuncType ) ; 53 S g S t r i n g V a l ∗ param1 = new S g S t r i n g V a l ( f i l e i n f o , f u n c − g e t d e c l a r a t i o n ()−> g e t n a m e ( ) . s t r ( ) > r e g A r g L i s t − a p p e n d e x p r e s s i o n ( param1 ) ; > S g I n t V a l ∗ param2 = new S g I n t V a l ( f i l e i n f o , −999 ) ; r e g A r g L i s t − a p p e n d e x p r e s s i o n ( param2 ) ; > ); S g F u n c t i o n C a l l E x p ∗ r e g F u n c C a l l = new S g F u n c t i o n C a l l E x p ( f i l e i n f o , r e g F u n c t i o n R e f E x p , r e g A r g L i s t , regFuncType ) ; S g E x p r e s s i o n R o o t ∗ r e g E x p r R o o t = new S g E x p r e s s i o n R o o t ( f i l e i n f o , r e g F u n c C a l l , regFuncType ) ; SgExprStatement ∗ r e g S t a t e m e n t = new SgExprStatement ( f i l e i n f o , r e g E x p r R o o t ) ; S g B a s i c B l o c k ∗ mainbody = mainFunc− g e t d e f i n i t i o n ()−> g e t b o d y ( ) ; > i f ( mainbody && ! mainbody− g e t s t a t e m e n t s ( ) . empty ( ) ) > { mainbody− p r e p e n d s t a t e m e n t ( r e g S t a t e m e n t ) ; > } } // I n s e r t t i m e r c a l l s a t a n o d e i f i t i s a f u n c t i o n d e f i n i t i o n void i n s e r t T i m e r C a l l s ( S g P r o j e c t ∗ p r o j e c t , i n t t r a c e d e p t h ) { S g F u n c t i o n D e c l a r a t i o n ∗ b e g i n F u n c D e c l=NULL, ∗ endFuncDecl=NULL, ∗ r e g F u n c D e c l=NULL, ∗ mainFuncDecl=NULL ; // F i n d f u n c t i o n t o i n s e r t a c o r r e s p o n d i n g S g F u n c t i o n C a l l E x p f o r l i s t <SgNode∗> f u n c t i o n s = NodeQuery : : q u e r y S u b T r e e ( p r o j e c t , V S g F u n c t i o n D e c l a r a t i o n ) ; f o r ( l i s t <SgNode ∗ > : : i t e r a t o r i = f u n c t i o n s . b e g i n ( ) ; i != f u n c t i o n s . end ( ) ; i ++) { SgFunctionDeclaration ∗ f u n c d e c l = i s S g F u n c t i o n D e c l a r a t i o n (∗ i ) ; char ∗ fun name = f u n c d e c l − g e t n a m e ( ) . s t r ( ) ; > i f ( s t r c m p ( fun name , ” t r a c e B e g i n F u n c P r o j ” )==0) { beginFuncDecl = f u n c d e c l ; } i f ( s t r c m p ( fun name , ” t r a c e E n d F u n c P r o j ” )==0) { endFuncDecl = f u n c d e c l ; } i f ( s t r c m p ( fun name , ” t r a c e R e g i s t e r F u n c t i o n ” )==0) { regFuncDecl = f u n c d e c l ; } i f ( isFunctionMain ( f u n c d e c l ) ){ mainFuncDecl = f u n c d e c l ; } } i f ( b e g i n F u n c D e c l== NULL) { c e r r << ”FATAL ERROR: return ; } i f ( endFuncDecl== NULL ) { c e r r << ”FATAL ERROR: return ; } i f ( r e g F u n c D e c l== NULL) { c e r r << ”FATAL ERROR: return ; } i f ( mainFuncDecl== NULL) { c e r r << ”FATAL ERROR: return ; } couldn ’ t find function c a l l e d ” << ” t r a c e B e g i n F u n c P r o j ” << e n d l ; couldn ’ t find function c a l l e d ” << ” t r a c e E n d F u n c P r o j ” << e n d l ; couldn ’ t find function c a l l e d ” << ” t r a c e R e g i s t e r F u n c t i o n ” << e n d l ; couldn ’ t f i n d a main o r AMPI main f u n c t i o n ” << e n d l ; // I n s e r t t i m e r c a l l s a t t o p and b o t t o m o f a l l f u n c t i o n s l i s t <SgNode ∗> f u n c s = NodeQuery : : q u e r y S u b T r e e ( p r o j e c t , V SgFunctionDefinition ) ; l i s t <S g F u n c t i o n D e c l a r a t i o n ∗> f u n c t i o n s T o T r a c e = b u i l d F u n c t i o n D e f s T o D e p t h ( t r a c e d e p t h , f o r ( l i s t <S g F u n c t i o n D e c l a r a t i o n ∗ > : : i t e r a t o r f = f u n c t i o n s T o T r a c e . b e g i n ( ) ; ++f ) { c o u t << ” e x a m i n i n g a f u n c t i o n d e c l a r a t i o n ” << e n d l ; project ); f != f u n c t i o n s T o T r a c e . end ( ) ; i n s e r t T i m e r C a l l s ( ( ∗ f )−> g e t d e f i n i t i o n ( ) , b e g i n F u n c D e c l , endFuncDecl , r e g F u n c D e c l , mainFuncDecl ) ; } } i n t main ( i n t a r g c , char ∗ a r g v [ ] { int tracedepth ; ) c o u t << ”============================================” << e n d l ; c o u t << ” F u n c t i o n T r a c i n g i n s e r t i o n t o o l . \ n Use − t r a c e d e p t h n ” << e n d l ; 54 i f ( s t r i n g ( a r g v [ a r g c − 2 ] ) == s t r i n g ( ”− t r a c e d e p t h ” ) ) { c o u t << ” T r a c i n g t o d e p t h ” << a r g v [ a r g c − 1] << e n d l << e n d l ; tracedepth = a t o i ( argv [ argc − 1 ] ) ; } else { t r a c e d e p t h =4; } c o u t << ”============================================” << e n d l ; SgProject ∗ project = frontend ROSE ASSERT( p r o j e c t != NULL ) ; insertTimerCalls ( project , #i f ( argc , argv ) ; tracedepth ) ; 1 generateDOT ( ∗ p r o j e c t ) ; // generatePDF (∗ p r o j e c t ) ; #e n d i f return backend ( p r o j e c t ) ; } 55 Appendix C Automatic PUP Function Creation: Code Listing The following is the source code for the Automated PUP Creation tool described in Chapter 5. The main source file for this translator is insertPUPs.C. /∗ Created by Purpose : How : For e a c h c l a s s d e f i n e d i n t h e f i l e Create l i s t o f a l l c l a s s v a r i a b l e s ( p r i v a t e or C r e a t e a new f u n c t i o n d e c l a r a t i o n , and i n s e r t add a pup s t a t e m e n t f o r e a c h c l a s s v a r i a b l e Variations : Do we pup Do we pup Isaac Dooley pup routines for classes create public ) i t into the class all class inherited variables ? variables ? Notes : We w i l l u s e t h e MIDDLE LEVEL REWRITE mechanism number o f b u g s , e . g . m u l t i f i l e s u p p o r t . ∗/ #include #include #include #include #include #include < r o s e . h> <l i s t > <v e c t o r > <i o s t r e a m > <e x c e p t i o n > <s t r i n g > . T h i s mechanism still has a using namespace s t d ; void i n s e r t P U P I n C l a s s ( S g C l a s s D e f i n i t i o n ∗ c , SgType ∗ pupperType , SgFunctionRefExp ∗ p u p f u n c t i o n ) { / ∗ MIDDLELEVEL d o e s n ’ t w o r k s i n c e : 1 ) c l a s s e s a r e u n s u p p o r t e d a s n o d e s i n t o w h i c h you can i n s e r t codeA 2 ) i t c r e a t e s a f i l e , i n s e r t s a s t r i n g and t h e n p a r s e s i t w i t h EDG. T h i s f i l e d o e s n ’ t i n c l u d e t h e h e a d e r s w h i c h d e f i n e t h e PUP n a m e s p a c e ∗/ Sg File Info∗ f i l e i n f o = Sg File Info : : generateDefaultFileInfoForTransformationNode ( ) ; // C r e a t e new f u n c t i o n w h i c h w i l l b e i n s e r t e d a s a member f u n c t i o n o f c l a s s S g B a s i c B l o c k ∗ bb = new S g B a s i c B l o c k ( f i l e i n f o , NULL ) ; S g F u n c t i o n D e f i n i t i o n ∗ f u n c d e f = new S g F u n c t i o n D e f i n i t i o n ( f i l e i n f o , bb ) ; bb− s e t p a r e n t ( f u n c d e f ) ; > c // S e t u p p a r a m e t e r s f o r new f u n c t i o n S g R e f e r e n c e T y p e ∗ p u p p e r P o i n t e r T y p e = new S g R e f e r e n c e T y p e ( pupperType ) ; SgName n ( ”p” ) ; S g I n i t i a l i z e d N a m e ∗ puppername = new S g I n i t i a l i z e d N a m e ( n , p u p p e r P o i n t e r T y p e , 0 , 0 , 0 ) ; puppername− s e t s c o p e ( f u n c d e f ) ; > S g F u n c t i o n P a r a m e t e r L i s t ∗ f p l = new S g F u n c t i o n P a r a m e t e r L i s t ( f i l e i n f o ) ; f p l − a p p e n d a r g ( puppername ) ; > puppername− s e t p a r e n t ( f p l ) ; > // S e t u p t h e S g M e m b e r F u n c t i o n D e c l a r a t i o n w h i c h p u l l s t h e f u n c t i o n i n t o S g C t o r I n i t i a l i z e r L i s t ∗ c t o r = new S g C t o r I n i t i a l i z e r L i s t ( f i l e i n f o ) ; SgType ∗ r e t u r n t y p e = new SgTypeVoid ( ) ; SgFunctionType ∗ f u n c t y p e = new SgFunctionType ( r e t u r n t y p e , f a l s e ) ; SgName mfdname ( ”PUP” ) ; the class 56 S g M e m b e r F u n c t i o n D e c l a r a t i o n ∗ mfd = new S g M e m b e r F u n c t i o n D e c l a r a t i o n ( f i l e i n f o , mfdname , NULL, f u n c d e f ) ; mfd− s e t p a r e n t ( c ) ; > mfd− s e t C t o r I n i t i a l i z e r L i s t ( c t o r ) ; > mfd− s e t p a r a m e t e r L i s t ( f p l ) ; > mfd− s e t t y p e ( f u n c t y p e ) ; > mfd− s e t s c o p e ( c ) ; > f p l − s e t p a r e n t ( mfd ) ; > c t o r − s e t p a r e n t ( mfd ) ; > f u n c d e f − s e t p a r e n t ( mfd ) ; > f u n c d e f − s e t d e c l a r a t i o n ( mfd ) ; > // F i n a l l y add t h e member f u n c t i o n c− append member ( mfd ) ; > to the class // I n s e r t a pup c a l l f o r e a c h member v a r i a b l e o f t h e c l a s s l i s t <S g D e c l a r a t i o n S t a t e m e n t ∗> &members = c− g e t m e m b e r s ( ) ; > c o u t << ” There a r e ” << members . s i z e ( ) << ” d e c l a r a t i o n s i n t h e c l a s s ” << e n d l ; f o r ( l i s t <S g D e c l a r a t i o n S t a t e m e n t ∗ > : : i t e r a t o r i=members . b e g i n ( ) ; i != members . end ();++ i ) { SgVariableDeclaration ∗ vardecl ; i f ( v a r d e c l=i s S g V a r i a b l e D e c l a r a t i o n ( ∗ i ) ) { S g I n i t i a l i z e d N a m e P t r L i s t &a r g s = v a r d e c l − g e t v a r i a b l e s ( ) ; > a s s e r t ( a r g s . s i z e ( ) == 1 ) ; // assume t h a t t h e f r o n t =o n l y v a r i a b l e b e i n g d e c l a r e d i s t h e one we want SgInitializedName ∗ finalArg = args . front ( ) ; assert ( finalArg ); S g V a r i a b l e S y m b o l ∗ v a r i a b l e S y m b o l = new S g V a r i a b l e S y m b o l ( f i n a l A r g ) ; a s s e r t ( variableSymbol ) ; c o u t << ” f o u n d a v a r i a b l e member ” << v a r i a b l e S y m b o l − g e t n a m e ( ) . g e t S t r i n g ( ) << > endl ; // The p u p p e r i t s e l f S g V a r i a b l e S y m b o l ∗ pupvarsymbol = new S g V a r i a b l e S y m b o l ( puppername ) ; SgVarRefExp ∗ pupvar = new SgVarRefExp ( f i l e i n f o , pupvarsymbol ) ; // The v a r i a b l e t o b e p u p p e d SgVarRefExp ∗ varToPup = new SgVarRefExp ( f i l e i n f o , v a r i a b l e S y m b o l ) ; S g C l a s s S y m b o l ∗ c s = new S g C l a s s S y m b o l ( c− g e t d e c l a r a t i o n ( ) ) ; > SgThisExp ∗ t = new SgThisExp ( f i l e i n f o , c s , 0 ) ; SgArrowExp ∗ a = new SgArrowExp ( f i l e i n f o , t , varToPup , v a r i a b l e S y m b o l − g e t t y p e ( ) ) ; > S g E xp r L i s t E xp ∗ e x p r l i s t = new S g E xp r L i s t E xp ( f i l e i n f o ) ; exprlist − prepend expression (a ) ; > e x p r l i s t − p r e p e n d e x p r e s s i o n ( pupvar ) ; > S g F u n c t i o n C a l l E x p ∗ p f c = new S g F u n c t i o n C a l l E x p ( f i l e i n f o , pupfunction , exprlist , pupperType ) ; // Put a i n a n u l l e x p r e s s i o n s t a t e m e n t S g E x p r e s s i o n R o o t ∗ e x p r R o o t = new S g E x p r e s s i o n R o o t ( f i l e i n f o , p f c , pupperType SgExprStatement ∗ e x p r S t a t e m e n t = new SgExprStatement ( f i l e i n f o , e x p r R o o t ) ; bb− a p p e n d s t a t e m e n t ( e x p r S t a t e m e n t ) ; > ); } } } void t r a n s f o r m C l a s s e s A d d P U P s ( S g P r o j e c t ∗ p r o j e c t ) { bool done = f a l s e ; SgNamedType ∗ pupperType ; l i s t <SgNode∗> t y p e s = NodeQuery : : q u e r y S u b T r e e ( p r o j e c t , V SgType ) ; f o r ( l i s t <SgNode ∗ > : : i t e r a t o r i=t y p e s . b e g i n ( ) ; i != t y p e s . end ( ) && ! done;++ i ) { i f ( isSgNamedType ( ∗ i ) ) { const s t r i n g qname = isSgNamedType ( ∗ i )−> g e t q u a l i f i e d n a m e ( ) . g e t S t r i n g ( ) ; const s t r i n g dname = ”PUP : : e r ” ; i f ( qname == dname ) { c o u t << ” Found some t y p e c a l l e d PUP : : e r , pupperType = isSgNamedType ( ∗ i ) ; done=true ; } } } hopefully I got the right one . ” << e n d l ; // We f i r s t f i n d a f u n c t i o n d e c l a r a t i o n f o r o u r pup r o u t i n e // t h e n we d e r i v e an S g F u n c t i o n R e f E x p f o r i t Sg File Info ∗ f i l e i n f o = Sg File Info : : generateDefaultFileInfoForTransformationNode ( ) ; c o u t << ” L o o k i n g f o r a pup f u n c t i o n t o r e f e r e n c e ” << e n d l ; S g F u n c t i o n D e c l a r a t i o n ∗ p u p p e r f d e c l=NULL ; 57 l i s t <SgNode∗> f u n c s = NodeQuery : : q u e r y S u b T r e e ( p r o j e c t , V S g F u n c t i o n D e c l a r a t i o n ) ; c o u t << ” c r e a t e d a l i s t o f ” << f u n c s . s i z e ( ) << ” f u n c t i o n d e c l a r a t i o n s ” << e n d l ; done= f a l s e ; f o r ( l i s t <SgNode ∗ > : : i t e r a t o r i=f u n c s . b e g i n ( ) ; i != f u n c s . end ( ) && ! done;++ i ) { SgFunctionDeclaration ∗ f d e c l ; i f ( f d e c l = i s S g F u n c t i o n D e c l a r a t i o n (∗ i )){ const s t r i n g qname = f d e c l − g e t n a m e ( ) . g e t S t r i n g ( ) ; > const s t r i n g dname = ” o p e r a t o r | ” ; // Some w i l l b e c a l l e d ” o p e r a t o r | ” i f ( qname == dname ) { c o u t << ” Found some f u n c t i o n d e c l a r a t i o n c a l l e d ” << qname << e n d l ; c o u t << ” q u a l i f i e d name = ” << f d e c l − g e t q u a l i f i e d n a m e ( ) . g e t S t r i n g ( ) << e n d l ; > pupperfdecl = fdecl ; } } } c o u t << ” done iterating through list ” << e n d l ; assert ( pupperfdecl ) ; SgFunctionSymbol ∗ pupsymbol = new SgFunctionSymbol ( p u p p e r f d e c l ) ; SgFunctionType ∗ p u p f u n c t y p e = new SgFunctionType ( pupperType ) ; SgFunctionRefExp ∗ p u p f u n c t i o n = new SgFunctionRefExp ( f i l e i n f o , pupsymbol , pupfunctype ) ; l i s t <SgNode∗> c l a s s e s = NodeQuery : : q u e r y S u b T r e e ( p r o j e c t , V S g C l a s s D e f i n i t i o n ) ; c o u t << ”Number o f c l a s s e s a p p e a r i n g i n t h i s p r o j e c t : ” << c l a s s e s . s i z e ( ) << e n d l ; f o r ( l i s t <SgNode ∗ > : : i t e r a t o r i = c l a s s e s . b e g i n ( ) ; i != c l a s s e s . end ( ) ; ++i ) { // Add PUP t o t h i s c l a s s S g C l a s s D e f i n i t i o n ∗ c = i s S g C l a s s D e f i n i t i o n (∗ i ) ; i f ( c !=NULL) i n s e r t P U P I n C l a s s ( c , pupperType , p u p f u n c t i o n ) ; else c o u t << ”WARNING: NodeQuery : : q u e r y S u b T r e e ( g l o b a l S c o p e , V S g C l a s s D e f i n i t i o n ) ” s o m e t h i n g t h a t i s n o t a S g C l a s s D e f i n i t i o n ” << e n d l ; } } returned ” // ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ // MAIN PROGRAM // ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ i n t main ( i n t a r g c , char ∗ a r g v [ ] ) { // B u i l d t h e AST u s e d b y ROSE SgProject ∗ p r o j e c t = fr ont e nd ( argc , argv ) ; a s s e r t ( p r o j e c t != NULL ) ; c o u t << ” Automatic PUP c r e a t i o n t r a n s l a t o r ” << e n d l ; // t r a n s f o r m a p p l i c a t i o n a s r e q u i r e d transformClassesAddPUPs ( p r o j e c t ) ; generateDOT ( ∗ p r o j e c t ) ; generatePDF ( ∗ p r o j e c t ) ; // Code g e n e r a t i o n p h a s e ( w r i t e return backend ( p r o j e c t ) ; } o u t new a p p l i c a t i o n ” r o s e < i n p u t file name > ”) 58 Appendix D Common Shared Routines: Code Listing The following is the source code for functions used in multiple translators. This code is in a source file called globalVariableCommon.C. /∗ ∗ ∗ A s e t o f u s e f u l r o u t i n e s f o r i d e n t i f y i n g g l o b a l and s t a t i c ∗ Used b y b o t h g l o b a l V a r i a b l e R e w r i t e and g l o b a l V a r i a b l e F i n d ∗/ variables #include ” g l o b a l V a r i a b l e C o m m o n . h” using namespace s t d ; /∗ ∗ D e t e r m i n e i f a s t a t e m e n t i s i n a h e a d e r f i l e ∗/ bool i s S t a t e m e n t I n H e a d e r ( S g S t a t e m e n t ∗ s ) { char ∗ f i l e n a m e = s − g e t f i l e i n f o ()−> g e t f i l e n a m e ( ) ; > assert ( filename ) ; int len = s t r l e n ( filename ) ; i f ( f i l e n a m e [ l e n −1]== ’ h ’ && f i l e n a m e [ l e n −2]== ’ . ’ ) return true ; else return f a l s e ; } /∗ ∗ D e t e r m i n e i f a v a r i a b l e D e c l a r a t i o n i s s t a t i c o r n o t ∗/ bool i s V a r D e c l S t a t i c ( S g V a r i a b l e D e c l a r a t i o n ∗ v a r i a b l e D e c l a r a t i o n ) { // TODO: a d e c l a r a t i o n h a s t w o f l a g s w h i c h can s p e c i f y s t a t i c s . Add t h e o t h e r one a s w e l l a s s e r t ( v a r i a b l e D e c l a r a t i o n != NULL ) ; S g D e c l a r a t i o n M o d i f i e r &d e c l M o d i f i e r = v a r i a b l e D e c l a r a t i o n − g e t d e c l a r a t i o n M o d i f i e r ( ) ; > S g S t o r a g e M o d i f i e r &s t o r a g e M o d i f i e r = d e c l M o d i f i e r . g e t s t o r a g e M o d i f i e r ( ) ; return s t o r a g e M o d i f i e r . i s S t a t i c ( ) ; } /∗ ∗ D e t e r m i n e i f a v a r i a b l e D e c l a r a t i o n i s e x t e r n o r n o t ∗/ bool i s V a r D e c l E x t e r n ( S g V a r i a b l e D e c l a r a t i o n ∗ v a r i a b l e D e c l a r a t i o n ) { a s s e r t ( v a r i a b l e D e c l a r a t i o n != NULL ) ; S g D e c l a r a t i o n M o d i f i e r &d e c l M o d i f i e r = v a r i a b l e D e c l a r a t i o n − g e t d e c l a r a t i o n M o d i f i e r ( ) ; > S g S t o r a g e M o d i f i e r &s t o r a g e M o d i f i e r = d e c l M o d i f i e r . g e t s t o r a g e M o d i f i e r ( ) ; return s t o r a g e M o d i f i e r . i s E x t e r n ( ) ; } l i s t < S g I n i t i a l i z e d N a m e ∗> b u i l d L i s t O f S t a t i c V a r i a b l e s ( S g F i l e ∗ f i l e ) { // T h i s f u n c t i o n b u i l d s a l i s t o f s t a t i c v a r i a b l e s ( f r o m a S g F i l e ) . a s s e r t ( f i l e != NULL ) ; // r e t u r n v a r i a b l e l i s t < S g I n i t i a l i z e d N a m e ∗> s t a t i c V a r i a b l e L i s t ; SgNode ∗ node = f i l e ; l i s t <SgNode∗> n o d e L i s t = NodeQuery : : q u e r y S u b T r e e ( node , V SgVariableDeclaration ); l i s t <SgNode ∗ > : : i t e r a t o r i = n o d e L i s t . b e g i n ( ) ; while ( i != n o d e L i s t . end ( ) ) { S g V a r i a b l e D e c l a r a t i o n ∗ v a r i a b l e D e c l a r a t i o n = i s S g V a r i a b l e D e c l a r a t i o n (∗ i ) ; a s s e r t ( v a r i a b l e D e c l a r a t i o n != NULL ) ; i f ( isVarDeclStatic ( variableDeclaration )){ 59 l i s t < S g I n i t i a l i z e d N a m e ∗> & v a r i a b l e L i s t = v a r i a b l e D e c l a r a t i o n − g e t v a r i a b l e s ( ) ; > l i s t <S g I n i t i a l i z e d N a m e ∗ > : : i t e r a t o r v a r = v a r i a b l e L i s t . b e g i n ( ) ; while ( v a r != v a r i a b l e L i s t . end ( ) ) { a s s e r t ( ( ∗ v a r)−> g e t s c o p e ( ) ) ; s t a t i c V a r i a b l e L i s t . push back (∗ var ) ; v a r ++; } } else { // } c o u t << ” d i d n ’ t find a static ” << e n d l ; i ++; } return } staticVariableList ; l i s t < S g I n i t i a l i z e d N a m e ∗> b u i l d L i s t O f G l o b a l V a r i a b l e s ( S g F i l e ∗ f i l e ) { // T h i s f u n c t i o n b u i l d s a l i s t o f g l o b a l v a r i a b l e s ( f r o m a S g F i l e ) . a s s e r t ( f i l e != NULL ) ; l i s t < S g I n i t i a l i z e d N a m e ∗> g l o b a l V a r i a b l e L i s t ; SgGlobal ∗ g l o ba l S c o p e = f i l e − g e t g l o b a l S c o p e ( ) ; > a s s e r t ( g l o b a l S c o p e != NULL ) ; l i s t <S g D e c l a r a t i o n S t a t e m e n t ∗ > : : i t e r a t o r i = g l o b a l S c o p e − g e t d e c l a r a t i o n s ( ) . b e g i n ( ) ; > while ( i != g l o b a l S c o p e − g e t d e c l a r a t i o n s ( ) . end ( ) ) > { S g V a r i a b l e D e c l a r a t i o n ∗ v a r i a b l e D e c l a r a t i o n = i s S g V a r i a b l e D e c l a r a t i o n (∗ i ) ; i f ( v a r i a b l e D e c l a r a t i o n != NULL) i f ( ! isVarDeclExtern ( variableDeclaration )) { l i s t < S g I n i t i a l i z e d N a m e ∗> & v a r i a b l e L i s t = v a r i a b l e D e c l a r a t i o n − g e t v a r i a b l e s ( ) ; > l i s t <S g I n i t i a l i z e d N a m e ∗ > : : i t e r a t o r v a r ; f o r ( v a r=v a r i a b l e L i s t . b e g i n ( ) ; v a r != v a r i a b l e L i s t . end ( ) ; ++v a r ) { // Don ’ t i n c l u d e v a r i o u s g l o b a l s w h i c h come f r o m r o s e somehow // At one p o i n t one s h o w e d up c a l l e d April 12 2005 i f ( ! ( ∗ v a r)−> g e t f i l e i n f o ()−> i s C o m p i l e r G e n e r a t e d ( ) ) { a s s e r t ( ( ∗ v a r)−> g e t s c o p e ( ) ) ; g l o b a l V a r i a b l e L i s t . push back (∗ var ) ; } else { c e r r << ”WARNING: I g n o r i n g c o m p i l e r G e n e r a t e d v a r i a b l e ” << ( ∗ v a r)−> g e t n a m e ( ) . g e t S t r i n g ( ) << e n d l ; } } } i ++; } return g l o b a l V a r i a b l e L i s t ; } l i s t < S g I n i t i a l i z e d N a m e ∗> b u i l d L i s t O f G l o b a l V a r i a b l e s // T h i s f u n c t i o n b u i l d s a l i s t o f g l o b a l v a r i a b l e s l i s t < S g I n i t i a l i z e d N a m e ∗> g l o b a l V a r i a b l e L i s t ; SgFilePtrList ∗ f i l e L i s t = project− g e t f i l e L i s t ( ) ; > SgFilePtrList : : i t e r a t o r f i l e = f i l e L i s t − begin ( ) ; > // Loop o v e r t h e f i l e s i n t h e p r o j e c t ( m u l t i p l e f i l e s e x i s t // when m u l t i p l e s o u r c e f i l e s a r e p l a c e d on t h e command l i n e ) . while ( f i l e != f i l e L i s t − end ( ) ) > { l i s t < S g I n i t i a l i z e d N a m e ∗> f i l e G l o b a l V a r i a b l e L i s t = b u i l d L i s t O f G l o b a l V a r i a b l e s ( ∗ f i l e ) ; fileGlobalVariableList . sort (); g l o b a l V a r i a b l e L i s t . merge ( f i l e G l o b a l V a r i a b l e L i s t ) ; f i l e ++; } return g l o b a l V a r i a b l e L i s t ; } ( SgProject ∗ project ( from a S g P r o j e c t ) . ){ l i s t < S g I n i t i a l i z e d N a m e ∗> b u i l d L i s t O f S t a t i c V a r i a b l e s // T h i s f u n c t i o n b u i l d s a l i s t o f s t a t i c v a r i a b l e s l i s t < S g I n i t i a l i z e d N a m e ∗> s t a t i c V a r i a b l e L i s t ; SgFilePtrList ∗ f i l e L i s t = project− g e t f i l e L i s t ( ) ; > SgFilePtrList : : i t e r a t o r f i l e = f i l e L i s t − begin ( ) ; > ( SgProject ∗ project ( from a S g P r o j e c t ) . ){ 60 / / Loop o v e r t h e f i l e s i n t h e p r o j e c t ( m u l t i p l e f i l e s e x i s t // when m u l t i p l e s o u r c e f i l e s a r e p l a c e d on t h e command l i n e ) . while ( f i l e != f i l e L i s t − end ( ) ) > { l i s t < S g I n i t i a l i z e d N a m e ∗> f i l e S t a t i c V a r i a b l e L i s t = b u i l d L i s t O f S t a t i c V a r i a b l e s ( ∗ f i l e ) ; s t a t i c V a r i a b l e L i s t . merge ( f i l e S t a t i c V a r i a b l e L i s t ) ; f i l e ++; } return } staticVariableList ; void p r i n t G l o b a l s A n d S t a t i c s ( S g P r o j e c t ∗ p r o j e c t ) { // T h e s e a r e t h e g l o b a l v a r i a b l e s i n t h e i n p u t p r o g r a m ( p r o v i d e d a s h e l p f u l i n f o r m a t i o n ) l i s t < S g I n i t i a l i z e d N a m e ∗> g l o b a l V a r i a b l e s = b u i l d L i s t O f G l o b a l V a r i a b l e s ( p r o j e c t ) ; l i s t < S g I n i t i a l i z e d N a m e ∗> s t a t i c V a r i a b l e s = b u i l d L i s t O f S t a t i c V a r i a b l e s ( p r o j e c t ) ; c o u t << ” P r o j e c t Wide : g l o b a l v a r i a b l e s : ” << e n d l ; f o r ( l i s t <S g I n i t i a l i z e d N a m e ∗ > : : i t e r a t o r v a r = g l o b a l V a r i a b l e s . b e g i n ( ) ; v a r++) c o u t << ” ” << ( ∗ v a r)−> g e t n a m e ( ) . s t r ( ) << e n d l ; c o u t << e n d l ; v a r != g l o b a l V a r i a b l e s . end ( ) ; c o u t << ” P r o j e c t Wide : s t a t i c v a r i a b l e s : ” << e n d l ; f o r ( l i s t < S g I n i t i a l i z e d N a m e ∗ > : : i t e r a t o r v a r = s t a t i c V a r i a b l e s . b e g i n ( ) ; v a r != s t a t i c V a r i a b l e s . end ( ) ; v a r ++){ c o u t << ” ” << ( ∗ v a r)−> g e t n a m e ( ) . s t r ( ) << ” ; mangled =” << ( ∗ v a r)−> g e t m a n g l e d n a m e ( ) . s t r ( ) << e n d l ; S g F i l e I n f o ∗ f i l e i n f o =( ∗ v a r)−> g e t f i l e i n f o ( ) ; c o u t << ” was i n f i l e ” << f i l e i n f o − g e t f i l e n a m e S t r i n g ( ) << e n d l ; > } c o u t << e n d l ; } / ∗ ∗ main− l i k e f u n c t i o n s a r e s p e c i f i e d h e r e ∗ / bool i s F u n c t i o n M a i n ( S g F u n c t i o n D e c l a r a t i o n ∗ f u n c d e c l ) { char ∗ f u n c n a m e = f u n c d e c l − g e t n a m e ( ) . s t r ( ) ; > i f ( s t r c m p ( func name , ” main ” )==0) { c o u t << ” Main f u n c t i o n c a l l e d \ ” main \ ” ” << e n d l ; return true ; } i f ( s t r c m p ( func name , ”AMPI Main” )==0) { // T h i s one w i l l o c c u r c o u t << ” Main f u n c t i o n c a l l e d \ ”AMPI Main \ ” ” << e n d l ; return true ; } // T h i s one w i l l o c c u r i f ( s t r c m p ( func name , ” AMPI Main cpp ” )==0) { c o u t << ” Main f u n c t i o n c a l l e d \ ” AMPI Main cpp \ ” ” << e n d l ; return true ; } return f a l s e ; } f o r AMPI C p r o g r a m s . S e e mpi . h f o r AMPI C++ p r o g r a m s . S e e mpi . h /∗ ∗ I n s e r t a s i n g l e s t a t e m e n t a t t h e g i v e n t a r g e t n o d e u s i n g t h e l o w− l e v e l r e w r i t e i n t e r f a c e , e i t h e r b e f o r e o r a f t e r t h e t a r g e t . ∗/ void i n s e r t S t m t ( S g S t a t e m e n t ∗ t a r g e t , S g S t a t e m e n t ∗ stmt , bool i n s e r t B e f o r e ) { ROSE ASSERT ( t a r g e t && stmt ) ; SgStatementPtrList temp stmt list ; t e m p s t m t l i s t . p u s h f r o n t ( stmt ) ; LowLevelRewrite : : i n s e r t ( t a r g e t , t e m p s t m t l i s t , i n s e r t B e f o r e ) ; } / ∗ ∗ Remove d u p l i c a t e g l o b a l v a r i a b l e s f r o m t h e l i s t ∗ / void r e m o v e D u p l i c a t e s ( l i s t < S g I n i t i a l i z e d N a m e ∗> & g l o b a l V a r i a b l e s ) { l i s t < S g I n i t i a l i z e d N a m e ∗> temp ; l i s t <S g I n i t i a l i z e d N a m e ∗ > : : i t e r a t o r i , j ; f o r ( i=g l o b a l V a r i a b l e s . b e g i n ( ) ; i != g l o b a l V a r i a b l e s . end ();++ i ) { bool f o u n d = f a l s e ; // c h e c k i f t h i s i s i n t h e temp a r r a y y e t . I f n o t , i n s e r t i t f o r ( j=temp . b e g i n ( ) ; j != temp . end ();++ j ) { i f ( ( ∗ i )−> g e t n a m e ( ) . g e t S t r i n g ( ) == ( ∗ j )−> g e t n a m e ( ) . g e t S t r i n g ( ) f o u n d=true ; } } i f ( ! found ) temp . p u s h b a c k ( ∗ i ) ; ){ 61 } g l o b a l V a r i a b l e s = temp ; } void r e m o v e D u p l i c a t e s ( l i s t <S g F u n c t i o n D e c l a r a t i o n ∗> & f u n c s ) { l i s t <S g F u n c t i o n D e c l a r a t i o n ∗> temp ; l i s t <S g F u n c t i o n D e c l a r a t i o n ∗ > : : i t e r a t o r i , j ; f o r ( i=f u n c s . b e g i n ( ) ; i != f u n c s . end ();++ i ) { bool f o u n d = f a l s e ; // c h e c k i f t h i s i s i n t h e temp a r r a y y e t . I f n o t , i n s e r t i t f o r ( j=temp . b e g i n ( ) ; j != temp . end ();++ j ) { i f ( ( ∗ i )−> g e t n a m e ( ) . g e t S t r i n g ( ) == ( ∗ j )−> g e t n a m e ( ) . g e t S t r i n g ( ) f o u n d=true ; } } i f ( ! found ) temp . p u s h b a c k ( ∗ i ) ; } f u n c s = temp ; } ){ 62 References [1] Rose website. http://www.llnl.gov/CASC/rose/. [2] The weather research&forecasting model website. http://wrf-model.org/. [3] Milind Bhandarkar, L. V. Kale, Eric de Sturler, and Jay Hoeflinger. Object-Based Adaptive Load Balancing for MPI Programs. In Proceedings of the International Conference on Computational Science, San Francisco, CA, LNCS 2074, pages 108–117, May 2001. [4] MILC Collaboration. Mimd lattice computation (milc) collaboration home page. http://www.physics.indiana.edu/∼sg/milc.html. [5] Chao Huang. System support for checkpoint and restart of charm++ and ampi applications. Master’s thesis, Dept. of Computer Science, University of Illinois, 2004. [6] Chao Huang, Orion Lawlor, and L. V. Kal´. Adaptive MPI. In Proceedings of the 16th e International Workshop on Languages and Compilers for Parallel Computing (LCPC 2003), LNCS 2958, pages 306–322, College Station, Texas, October 2003. [7] Chao Huang, Gengbin Zheng, Sameer Kumar, and Laxmikant V. Kal´. Performance e evaluation of adaptive MPI. In Proceedings of ACM SIGPLAN Symposium on Principles and Practice of Parallel Programming 2006, March 2006. [8] Chris Lattner and Vikram Adve. Architecture for a Next-Generation GCC. In Proc. First Annual GCC Developers’ Summit, Ottawa, Canada, May 2003. [9] Chris Lattner and Vikram Adve. LLVM: A Compilation Framework for Lifelong Program Analysis & Transformation. In Proceedings of the 2004 International Symposium on Code Generation and Optimization (CGO’04), Palo Alto, California, Mar 2004. [10] Chris Lattner and Vikram Adve. The LLVM Compiler Framework and Infrastructure Tutorial. In LCPC’04 Mini Workshop on Compiler Research Infrastructures, West Lafayette, Indiana, Sep 2004. [11] Orion Lawlor, Milind Bhandarkar, and Laxmikant V. Kal´. Adaptive mpi. Technical e Report 02-05, Parallel Programming Laboratory, Department of Computer Science, University of Illinois at Urbana-Champaign, 2002. 63 [12] S. Lee, T. Johnson, and R. Eigenmann. Cetus - an extensible compiler infrastructure for source-to-source transformation, 2003. [13] Yunheung Paek and David A. Padua. Compiling for scalable multiprocessors with polaris. Parallel Processing Letters, 7(4):425–436, 1997. [14] D Quinlan, S. Ur, and R. Vuduc. An extensible open-source compiler infrastructure for testing. [15] Daniel Quinlan, Qing Yi, Gary Kumfert, Thomas Epperly, and Tamara Dahlgren. Toward the automated generation of components from existing source code. [16] Markus Schordan, , and Daniel Quinlan. A source-to-source architecture for user-defined optimizations. In Lecture Notes in Computer Science: Proc. of Joint Modular Languages Conference (JMLC03), volume 2789, pages 214–223. Springer-Verlag, June 2003. [17] W. C Skamarock, J. B. Klemp, J. Dudhia, D. O. Gill, D. M. Barker, W. Wang, and J. G. Powers. A description of the advanced research wrf version 2. Technical Report Technical Note NCAR/TN-468+STR, June 2005. 64 ...
View Full Document

Ask a homework question - tutors are online