Base classes and functions of the Base library.
The base library of Nestor contains the definition of all the classes representing the differents syntactic elements of HPF 2.0, Fortran 90 and Fortran 77. The main purpose of this library is to provide the user an easy framework and programming tool to write source-to-source transformations of Fortran codes. Classes defined in the base library permit to create new object, i.e. new syntactic elements and then, to create a new source code from scratch. Secondly, a special class (NstComputationUnit) is used as an interface with the node library, creating a set of objects representing the parsed source code.A source code transformed by the base library into C++ objects can be seen as a syntactic tree where each node is an object with methods and attributes representing the syntactic element. These objects can be easily modified, replaced, moved at another place of the hierarchical structure. For instance, a list of statements is represented by a class derived from the standard C++ class list where it is easy to reorganize the order of the statements. Each object representing a syntactic element has its own constructor that allows the programmer to add new objects and then new statements, variables, procedures in the source code. Each object has its own output function, a redefinition of the C++ operator <<, permiting an easy unparse of every object or of the whole code. This output function can be configured, allowing to unparse in different languages (now, only HPF and Petit language are supported).
Suppose we want to create a program from scratch, i.e. creating a hierarchical structure of objects representing a source code. For instance, suppose we want to create the structure corresponding to the following code:
PROGRAM simple integer n parameter (n = 100) integer a(1:n) integer b(1:n) integer c(1:n) integer i do i = 2,n a(i) = b(i) c(i) = a(i-1) enddo endThere are two ways of creating such a structure. First, if this source code is in a file named 'simple_code.f', it is easy to write a program using the base library and the node library to parse the file and create the structure. Here is the C++ code:# include <nestor.H> int main(int ac, char **av) { NstComputationUnit program("simple_code.f"); cout << program; }The constructor of NstComputationUnit parses the file with the node library and then creates a hierarchical structure of objects representing the code in the object program. The command:cout << program;unparses the program with the methods of the base library on the standard output.Suppose now that we want to create this code from scratch, i.e we want to build the structure ourselves. This code can be found in the nestor directory under the directory src/doc and is called gene_code.cc. This code distributes a loop nest that contains two loop nests and creates two new loop nests. Try compiling this example by typing make.
// // gene_code distributes a loop nest with two statements inside. // // This file is part of Nestor. // Copyright (C) 1999 Georges-Andre Silber. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // # include <nestor.H> int comment_out(NstTree* t, void* i) { if (NstStatement* st = dynamic_cast<NstStatement*>(t)) st->is_commented = 1; return 0; } void distribute_single_loop_with_2_statements(NstStatementList& sl) { NstStatementList::iterator sli; for (sli = sl.begin(); sli != sl.end(); sli++) { if (NstStatementDo* do_loop = dynamic_cast<NstStatementDo*>(*sli)) { if (do_loop->body.size() == 2) { // Distribute NstStatementDo loop1 = *do_loop; NstStatementDo loop2 = *do_loop; loop1.info()->is_independent = 1; loop2.info()->is_independent = 1; loop1.body.pop_back(); loop2.body.pop_front(); // Insert into a region NstStatementNestor region; region.body.push_back(loop1); region.body.push_back(loop2); // Insert region before old loop sl.insert(sli, region); // Comment out loop do_loop->above_comment = "c Loop before distribution\n"; do_loop->traversal(comment_out); } } } } int main(int ac, char **av) { // Creates an empty program with the name "simple". NstUnitProgram program (NstIdentifier("simple")); // Creates a new parameter declaration. The parameter is called "N" and has // the value "100". NstTypeInteger ti; NstDefinitionVariable* n_def = new NstDefinitionVariable(NstIdentifier("N")); NstDeclarationVariable n_var (ti, *n_def); cout << n_var << endl; NstDeclarationParameter n_param (*n_var.definition(), NstExpressionConstant(NstInteger(100))); // Inserts the two declarations into the list of declarations of the // program. program.declarations.push_back(n_var); program.declarations.push_back(n_param); // Inserts the definition associated with the declaration into the table of // symbols of the program. Note that this definition will not be copied // because it is shared. In Nestor, the definition of a variable, parameter, // unit, etc... is shared and belongs to the declaration. program.definition()->symbols.push_back(*n_param.definition()); // Creates an access to the parameter "N" NstVariableUsed n_used (*n_param.definition()); // Creates an integer array type (integer (1:N)), one dimension. NstTypeArray array_type (ti); NstShapeExplicit shape(NstExpressionConstant(NstInteger(1)), NstExpressionVariable(n_used)); array_type.shapes.push_back(shape); // Declares three arrays A, B and C. NstDeclarationVariable a_var (array_type, NstDefinitionVariable(NstIdentifier("A"))); NstDeclarationVariable b_var (array_type, NstDefinitionVariable(NstIdentifier("B"))); NstDeclarationVariable c_var (array_type, NstDefinitionVariable(NstIdentifier("C"))); program.declarations.push_back(a_var); program.declarations.push_back(b_var); program.declarations.push_back(c_var); program.definition()->symbols.push_back(*a_var.definition()); program.definition()->symbols.push_back(*b_var.definition()); program.definition()->symbols.push_back(*c_var.definition()); // Creates threee array accesses. NstVariableUsed a_used (*a_var.definition()); NstVariableUsed b_used (*b_var.definition()); NstVariableUsed c_used (*c_var.definition()); // Declares the variable I. NstDeclarationVariable i_var (ti, NstDefinitionVariable(NstIdentifier("I"))); program.declarations.push_back(i_var); program.definition()->symbols.push_back(*i_var.definition()); // Create an access to the loop variable I. NstVariableLoop i_used (*i_var.definition()); // Creates DO loop statement. NstExpressionSlice slice(NstExpressionConstant(NstInteger(2)), NstExpressionVariable(n_used), NstExpressionDummy()); NstStatementDo i_loop (i_used, slice); // Adds a statement in the loop (a(i) = b(i)). // the left part of the assignment (a(i)) NstExpressionVariable i_exp (i_used); NstVariableIndexed lvalue1 (a_used); lvalue1.indexes.push_back(i_exp); // The right part (b(i)) NstVariableIndexed rvalue1 (b_used); rvalue1.indexes.push_back(i_exp); // Adds the assignment to the loop body. NstStatementBasic stat(NstInstructionAssign(lvalue1, NstExpressionVariable(rvalue1))); i_loop.body.push_back(stat); // Adds a second statement (c(i) = a(i-1)) // the left part of the assignment (c(i)) lvalue1.variable(c_used); // The right part (a(i-1)) NstVariableIndexed rvalue2 (a_used); NstExpressionBinary iminus1 (i_exp, NstExpressionConstant(NstInteger(1)), NstOpMinus()); rvalue2.indexes.push_back(iminus1); // Adds the assignment to the loop body. stat.instruction(NstInstructionAssign(lvalue1, NstExpressionVariable(rvalue2))); i_loop.body.push_back(stat); // Adds the loop to the program. program.statements.push_back(i_loop); // Unparse the code cout << program << endl; NstRDGVar dg(*program.statements.front()); if (dg.built()) { cout << "Dependences before distribution:\n"; cout << dg << endl; } distribute_single_loop_with_2_statements(program.statements); NstRDGVar dg2(*program.statements.front()); if (dg2.built()) { cout << "Dependences after distribution:\n"; cout << dg2 << endl; } cout << program << endl; }
this page has been generated automatically by doc++
(c)opyright by Malte Zöckler, Roland Wunderling
contact: doc++@zib.de