[Prev][Next][Index]

Re: Problems with SgType::baseType()



Again, your problem is with the representation of the types. Getting
the truetype, even with the most restrictive options
(MASK_NO_DESCRIPTORS, DO_NOT_FOLLOW_TYPEDEFS) will still take care of
T_PTR(-1) -> T_PTR(+1) cancellation. 

The TrueType mailing explains the problems with types. I'm appending
it so you can figure out what I've been talking about. (I knew I had
some sort of writeup somewhere.)

/Andrew/


--- Cut Here for TrueType README ---
 
Who Needs this Patch?
=====================

If you are working with C code and do anything with types (including
declaring new variables!), you need this patch. 

If you are working with FORTRAN code, you should not call the
functions provided in this patch.


What Are TrueTypes? (And Why Should I Use Them?)
================================================

First, let's look at what is going on in Sage's internal
representation of types. This will lead into an explanation of
true types. 

A pointer to a double ("double *x") has the Sage++ type:
     T_PTR(+1) --> T_DOUBLE
This notation should be read "a pointer with indirection one that
points to a double". 

Now, given 
     double *x;
the type of the expression
     "*x"
should be T_DOUBLE, right? 

WRONG. The Sage++ internal representation of the type of "*x" is
     T_PTR(-1) --> T_PTR(+1) --> T_DOUBLE

This might be interpreted as "an inverse pointer (a pointer with
indirection negative one), pointing to a pointer with indirection one,
pointing to a double". 

A TrueType is merely a type with this sort of surprise removed. When
you look at a TrueType, you know that the first thing you see will be
meaningful, rather than some inverse pointer that needs to be canceled
out. 

Using truetypes everywhere makes the typing system behave much more as
expected. It also makes other Sage++ functions behave correctly. For
example, if you declare a temporary variable to hold "*x" in the
example above, and you declare it to be the same type as "*x", that
is:
     T_PTR(-1) --> T_PTR(+1) --> T_DOUBLE
then on unparse your temporary will appear as:
     double **tmp;
rather than the simple double that it should have been. This is
because the code in charge of declaring variables does not deal with
these funny "inverse pointers".


When Should I Use TrueTypes?
============================

I use TrueTypes everywhere. In my moderately-sized application, I have
33 calls to getTrueType.

You should use TrueTypes in any situation that you have not
specifically thought about dealing with inverse pointers and "useless"
descriptive types like `extern' (see technical discussion below).



How Can I Install the TrueType Patch?
=====================================

Add the code in ./Sage++/libSage++.C to the corresponding file in your
own Sage++ source tree. I inserted this code just after the
"SgType::SgType" constructor.

Add the code in ./lib/include/libSage++.h-part1 into your own
libSage++.h file, just before the SgType class definition. 

Add the code in ./lib/include/libSage++.h-part2 into your own
libSage++.h file, inside the SgType class definition. 

The libSage++.h-part2 code uses C++ "optional arguments". If your C++
compiler does not understand these, make the following two simple
changes: 

Change:
   SgType *maskDescriptors (int mask = MASK_MOST_DESCRIPTORS);
To:
   SgType *maskDescriptors (int mask);

Change:
   SgType *getTrueType (int mask = MASK_MOST_DESCRIPTORS, int follow_typedefs = DO_NOT_FOLLOW_TYPEDEFS);
To:
   SgType *getTrueType (int mask, int follow_typedefs);


NOTE: All of these changes have been included in the latest prerelase
Sage++ distribution from Indiana U., so there is no danger of your
code ceasing to function with future releases.


Who Supports This Patch?
========================

I have been using this exact code for at least three months, with no
problem. I will fix any bugs you find in it. Mail bug reports to
"mauer@mcs.anl.gov" with a copy to "sage-bugs@cica.indiana.edu". 


Technical Description
=====================

maskDescriptors
---------------

There is no need to call this function directly for basic TrueType
safety. It is used by getTrueType, but is useful in its own right in
some instances. To use it, one usually simply calls getTrueType with a
specified mask.

This function strips off various traits that are most likely not of
interest for your program. By default, this includes "extern",
"static", "register", "friend", "virtual", "inline", and
"typedef". Variables with a type containing one of these traits are
dangerous to clone because they retain the trait. The only traits that
are left in by default are: short, long, unsigned, signed, const,
volatile.

Example:
Consider this original program:
     extern double x;

     main ()
     {
	 double y,z;
         x = y = z;
     }
Suppose you attempt to clone the variable `x' in order to generate
this code:
     extern double x;

     main ()
     {
	 double y,z;
         double tmp;
         tmp = y = z;
         x = tmp;
     }
If you do not mask out the `extern' descriptor, you will end up with
the variable declaration
         extern double tmp;
which is definitely wrong.

The argument this function takes is one of:
     MASK_ALL_DESCRIPTORS = Strip off everything
     MASK_MOST_DESCRIPTORS = Strip off everything but short, long, 
            signed, unsigned, const, volatile. 
     MASK_NO_DESCRIPTORS = Treat all descriptors as having useful
            information; do not remove them.



getTrueType
-----------
This code provides support for:
(1) Handling the T_PTR(-1) --> T_PTR(+1) problem.
(2) Ignoring arrays with zero dimensions, as would appear one the left
    hand side of the expression:
       x[2] = 0.0;
(3) Optionally ignoring some descriptive types.
(4) Optionally following typedefs to their "base type". For example,
    the TrueType of "Double_Typedef" below would give "double".
       typedef double Double_Typedef;


The first argument indicates the descriptors to remove (see above
discussion of maskDescriptors), and the second argument indicates
whether or not typedefs should be followed to the type truly being
defined.

Example 1: See if a type is some kind of `float' or `double'.
           This is right from my application.

int
isFloatingType (SgType *a)
{
     // We mask all descriptors because we want to catch "unsigned float"
     // and "long double" as well as the regulars.
     SgType *true = a->getTrueType(MASK_ALL_DESCRIPTORS, DO_FOLLOW_TYPEDEFS);

     return ( (true->equivalentToType(*SgTypeDouble()))
              || (true->equivalentToType(*SgTypeFloat())));
}
------------------------------------------------------------------------

Example 2: Make a temporary variable of the right type to hold a given
           expression's result. This is untested "example code".

SgVarRefExp *
get_tmp_var (SgExpression *in_expr)
{
     SgType *expr_type = in_expr->type();
     if (expr_type == 0)
         return 0;

     /* This call to getTrueType uses the defaults 
        (C++ optional arguments). It is equivalent to 
        getTrueType(MASK_MOST_DESCRIPTORS, DO_NOT_FOLLOW_TYPEDEFS)
     */
     SgType *expr_true_type = expr_type->getTrueType(); 
	
     return get_temp_with_type(expr_true_type);
}
------------------------------------------------------------------------


About The Author
================
Andrew Mauer currently works at Argonne National Laboratory where he
is developing a tool for Automatic Differentiation of numerical C
codes. Information about this and other automatic differentiation
projects is available on the World Wide Web at:
      http://www.mcs.anl.gov/autodiff/index.html

Email: mauer@mcs.anl.gov. 


Disclaimer
==========
#include <std-disclaimer.h>
Use at your own risk.




Reference(s):