![]() |
|||
|
|
Introduction
This
frequently asked question list
is intended for students that are required to program with Minipolaris.
The objective here is to get beginners up and running as soon as
possible
rather than present an indepth analysis. Readers are encouraged to
refer
the MAN pages on the various C++ classes that Minipolaris implements.
Frequently Asked Questions
1.
How do I list statements of the
Fortran Program that I'm compiling ?
2. How do
I list statements of a given
type ?
3. How do
I list expressions that
are present in my program ?
4. How can
I identify constants ?
5. How can
I replace an Expression
with another Expression ?
6. How do
I create new Expressions
?
7. How can
I create a nested loop
of Statements ?
8. When I
delete a Statement from
my Statement List, my program hangs, why ?
9. How do
I modify the Predirectives
?
10. Why do
I need a WorkSpace ?
1. How do I list statements of the Fortran Program that I'm compiling ?
The functions print() and write() are inherited and are available to almost all classes in MiniPolaris.
Print() outputs all revelant information along with the statment itself whereas Write() outputs only the statement.
Example Code:
StmtList
& statement_list=pgm.stmts();
:
:
cout<<endl<<"Using
print()";
Iterator
<Statement> iterate_statement=statement_list.iterator();
for(iterate_statement.reset();iterate_statement.valid();++iterate_statement)
{
cout<<endl;
Statement
& statement=iterate_statement.current();
statement.print(cout);
}
int
i=5;
cout<<endl<<"Using
write()";
for(iterate_statement.reset();iterate_statement.valid();++iterate_statement)
{
cout<<endl;
Statement
& statement=iterate_statement.current();
statement.write(cout,i,"
");
}
2. How do I list statements of a given type ?
The function stmts_of_type() available to objects of type StmtList returns an iterator over a give type of statement i.e. CALL STMT, ASSIGNMENT STMT, IF STMT etc. Upto 5 different types of statements can be isolated using this( Do a MAN Statement for a more details )
Example Code:
//This code will print out all statements of type CALL and PRINT
int
i=5;
Iterator<Statement>
iterate_statement=stl.stmts_of_type(CALL_STMT,PRINT_STMT);
for(iterate_statement.reset();iterate_statement.valid();++iterate_statement)
{
cout<<endl;
Statement
& statement=iterate_statement.current();
statement.write(cout,i,"
");
}
3. How do I list expressions that are present in my program ?
A simple way in which expression in a program can be listed is through the use of iterate_expressions() available to objects of type Statement. Alternatively the function arg_list() available to objects of type Expression can also be used to a limited extent once the RHS of an expression is obtained.
Example Code:
//
This section of code will
iterate through all the expressions in a program
cout<<endl<<"Printing
Expressions ";
Iterator<Statement>
iterate_statement=stl.iterator();
for(iterate_statement.reset();iterate_statement.valid();++iterate_statement)
{
cout<<endl;
Statement
& statement=iterate_statement.current();
Iterator<Expression>
iterate_expression=statement.iterate_expressions();
for(iterate_expression.reset();iterate_expression.valid();++iterate_expression)
{
iterate_expression.current().print(cout); //print the expressions
}
}
Note: Recursive techniques need to be employed to pickout the individual identifiers, a technique for doing this is explained in FAQ # 4
4. How can I identify constants ?
To identify constants or parameters as they are known in fortran, the individual identifiers that make up an expression need to be examined. For eg consider the following expression x=y+z.
'x' is the identifier expression on the lhs. 'y' and 'z' are identifier expressions on thr rhs.
The identifier expression Symbol class is then checked against an enumerated type to see if it is indeed a variable of type constant.
Example Code:
//Recursive
function that can
be used to find constant variables
void
find_constant(Expression
* expr)
{
if (expr->op()==ID_OP)
{
Symbol & sym=expr->symbol();
if(sym.sym_class()==SYMBOLIC_CONSTANT_CLASS)
{
cout<<endl<<"Constant :";
expr->print(cout);
}
}
else
{
Iterator<Expression> iterate_expr=expr->arg_list();
for(iterate_expr.reset();iterate_expr.valid();++iterate_expr)
{
find_constant(iterate_expr.current());
}
}
}
5. How can I replace an Expression with another Expression and how do I use Assign() and Pull() ?
This can be easily achieved by using a similar recursive function shown in FAQ #4. In addition, a Listable class Mutator which is similar to Iterator is used. Mutators are used when expressions need to be modified or changed. Due to the manner in which expressions are executed in 'C++' certain semantics have to be preserved in using Assign() and Pull() functions. For more detail refer to
man Iterator
Note: There are no manual pages on Mutator
Example Code:
//Recursive
function that can
be used to replace an expression with an
//other
one.
Expression
* replace_expression
(Expression * expr, Expression * old_expr, Expression * new_expr)
{
if
(expr->op()==ID_OP)
{
Symbol &
sym=expr->symbol();
if(expr==old_expr)
{
return(new_expr->clone());
}
}
else
{
Mutator<Expression>
mutate_expr=expr->arg_list();
for(mutate_expr.reset();mutate_expr.valid();++mutate_expr)
{
mutate.assign()=replace_expression(mutate_expr.pull(),
old_expr,new_expr);
}
}
return
expr;
}
6. How do I create new Expressions ?
In Minipolaris, expressions cannot be created directly and must be created via functions that are availbe to objects of type Expression. The following example will illustrate this
Example Code:
//The
objective is to create
a new expression using other 2 expressions
//The code
below will generate
an expression of the type "result=operand_1 + operand_2"
Expression
* operand_1=constant(1);
Expression
* operand_2=constant(2);
BinaryExpr
* result = new
BinaryExpr(ADD_OP,
expr_type(ADD_OP,
operand_1->type(), operand_2->type()), operand_1,
operand_2);
7. How can I create a nested loop of Statements ?
This is an example of code that is analogous to nested loops shown below
for(int
i=1;i<maximum;i++)
for(int
j=i-1;j<=maximum;j++)
Such loops become necessary when modifications made in a Statement have to be propagated through to the rest of the program. eg: constant propagation.
Example Code:
StmtList
& statement_list=pgm.stmts();
Statement
* firsto=statement_list.first_ref();
Statement
* lasto=statement_list.last_ref();
const char
* first_tag=firsto->tag();
const char
* last_tag=lasto->tag();
Statement
* stmto=stl.first_ref();
for(;strcmp(last_tag,stmto->next_ref()->tag());stmto=stmto->next_ref())
{
:
:
for(;strcmp(last_tag,stmti->tag());stmti=stmti->next_ref())
{
:
:
}
}
8. When I delete a Statement from my Statement List, my program hangs, why ?
A common mistake made by most programmers is to delete an item that it currently being pointed to by an iterator or pointer. Doing so will result in an assertion failed error or possibly a machine core dump. There are several ways of avoiding this and a simple method is outlined below. It involves the use of flags.
//Consider
the following
example code which WILL result in an ERROR
StmtList
& statement_list=pgm.stmts();
Iterator<Statement>
iterate_statement=statement_list.iterator();
for(iterate_statement.reset();iterate_statement.valid();++iterate
statement)
{
:
:
if(condition=TRUE)
statement_list(iterate_statement.current());
}
The reason why the above technique generates an error is that when the statement is deleted from the StatementList, the current iterator is pointing to void as the statement it was pointing to has been deleted.
As the code below suggests, a simple flag can be set when a condition for deletion of a statement is met. After the iterator has had a chance to point to the next statement, then through the use of prev_ref(), the previous statement can be safely deleted.
//Consider
the following
example code which NOT hang
int
delete_ok=0;
StmtList
& statement_list=pgm.stmts();
Iterator<Statement>
iterate_statement=statement_list.iterator();
for(iterate_statement.reset();iterate_statement.valid();++iterate
statement)
{
if(delete_ok==1)
{
stl.del(iterate_statement.current().prev_ref());
delete_ok=0;
}
:
:
if(condition=TRUE)
delete_ok=1;
}
9. How do I modify the predirectives ?
The predirectives are stored as a list for each statement. The example below illustrates how this list can be modified.
Example Code:
Iterator<Statement>
iterate_statement=stl.iteator();
for
(iterate_statement.reset();iterate_statement.valid();++iterate_statement)
{
Statement
& stmt=iterate_statement.current();
strstream
p;
p<<"C
--Addition to Predirective"<<ends;
StringElem
*x= new StringElem(p.str());
List<StringElem>
& pre_dirs=stmt.pre_directives();
pre_dirs.ins_last(x);
delete[]
p.str();
}
10. Why do I need a WorkSpace ?
A problem you will likely encounter is the inability to find what BasicBlock a randomly chosen Statement belongs to. Since you define the BasicBlock class, it is easy to include references to Statements and other objects. However, you do not define class Statement, so you cannot put a direct reference to the containing BasicBlock.
Fortunately, Polaris provides a class WorkSpace which provides a method to attach information to a previously defined class, such as Statement. To see the manual page, type
man WorkSpace
Example Code:
//
// Cog.h
//
// Sample
use of WorkSpace,
associating information about a Cog with a
//
Sprocket (fictional types.)
In this case, we know the following :
//
//
Sprocket :
// o
already defined in
the base (so we can't change it, but we
// want to
use it.)
// o
derived from type Listable
(so it has a WorkSpaceStack)
//
// Cog :
// o user
defined
// o
contains one or more
references to Sprocket type objects
//
// In our
system, we want
to know what Cog contains a particular Sprocket,
// but
since we cannot change
the Sprocket class, we need to store this
// in a
WorkSpace object.
//
// Cog :
// o user
defined
// o
contains one or more
references to Sprocket type objects
//
// In our
system, we want
to know what Cog contains a particular Sprocket,
// but
since we cannot change
the Sprocket class, we need to store this
// in a
WorkSpace object.
//
// the
following declarations
would belong in Cog.h -- the header file for
// the
class Cog
// add
these includes at
the top
#include
"WorkSpace.h"
#include
"WorkSpaceStack.h"
class Cog
: public Listable
{
// blah
blah blah
// this is
where you would
define type Cog
};
//
this should be defined
at the bottom, after you define the class Cog :
class
CogWork : public WorkSpace
{
private:
Cog * _cog;
public:
CogWork(CogWork
& other)
: _cog(other._cog), WorkSpace(other) { }
CogWork(int
tag, Cog * cog)
: _cog(cog), WorkSpace(tag) { }
Cog *
cog() { return (Cog
*) _cog; }
INLINE
Listable *listable_clone()
const;
// Needed
for Listable class.
INLINE
void print(ostream
&o) const;
// Needed
for Listable class.
INLINE int
structures_OK()
const;
}
};
INLINE
Listable * CogWork::listable_clone()
const
{
return new
CogWork((CogWork
&) *this);
};
INLINE
int CogWork::structures_OK()
const
{
return 1;
}
INLINE
void CogWork::print(ostream
&o) const
{
o
<< "CogWork : [
" << _cog << " ]";
}
//
// Cog.cc
//
// Sample
use of WorkSpace,
associating information about a Cog with a
//
Sprocket (fictional types.)
In this case, we know the following :
//
//
Sprocket :
// o
already defined in
the base (so we can't change it, but we
// want to
use it.)
// o
derived from type Listable
(so it has a WorkSpaceStack)
//
// Cog :
// o user
defined
// o
contains one or more
references to Sprocket type objects
//
// In our
system, we want
to know what Cog contains a particular Sprocket,
// but
since we cannot change
the Sprocket class, we need to store this
// in a
WorkSpace object.
//
// the
following code shows
and example of how to associate a Cog with a
//
Sprocket, then later
how to find the Cog given a random Sprocket
#include
"Cog.h"
// etc.
// this
would be some function
called from the driver most likely
ReturnType
pass_function(ProgramUnit
& pgm)
{
// PASStag
will be a unique
integer used by this entire pass of the
//
compiler -- so it should
be set only once
int
PASStag = create_pass_tag();
// .
// .
// .
// lots of
code in which
you are creating Cogs and putting references
// to
sprockets in them
// .
// .
// .
// now,
say you have the
objects :
//
Sprocket & mysprocket;
// Cog *
mycog; // mycog
= new Cog(...) earlier
// and you
have stored references
to mysprocket in mycog (so it is no
// problem
finding mysprocket
given mycog)
// to
store a reference
to mycog within mysprocket, create a WorkSpace
// object
and store it on
the stack.
mysprocket.work_stack().push(new
CogWork(PASStag, mycog));
// .
// .
// .
// lots of
code in which
you do lots of wonderful things with Cogs
// .
// .
// .
// now,
say you have a the
object :
//
Sprocket & randomsprocket;
// and you
want to find
the Cog which was originally associated with
// it
above :
CogWork *
cog_workspace
=
(CogWork
*) randomsprocket.work_stack().top_ref(PASStag);
Cog *
the_cog = cog_workspace.cog();
// .
// .
// .
// much
more brilliant code
// .
// .
// .
// now you
are ready to
finish your pass, so you need to clean up all
//
references to Cogs from
the Sprockets :
pgm.clean_workspace(PASStag);
return
fantastic_result;
}
Parasol Home | Research | People | General info | Seminars | Resources Parasol Lab, 301 Harvey R. Bright Bldg, 3112 TAMU, College Station, TX 77843-3112 Contact Webmaster Phone 979.458.0722 Fax 979.458.0718
Department of Computer Science and Engineering | Dwight Look College of Engineering | Texas A&M University Privacy statement: Computer Science and Engineering Engineering TAMU |