Difference between revisions of "GCC alwayszero function attribute"

From CDOT Wiki
Jump to: navigation, search
Line 28: Line 28:
 
== Possible Bug ==
 
== Possible Bug ==
  
Recognizing the call flags  
+
Calling gimple_call_flags on a gimple stmt representing an indirect call to a virtual method (with a function attribute) always returns 0. This is even though the correct nonzero value of the call flags can be recognized from other parts of gcc.
  
In tree-ssa-ccp.c:
+
For example:
 +
 
 +
tree-ssa-ccp.c modified with a debugging statement:
 
<pre>
 
<pre>
 
/* Compute a default value for variable VAR and store it in the
 
/* Compute a default value for variable VAR and store it in the
Line 111: Line 113:
 
</pre>
 
</pre>
  
In tree-optimize.c:
+
tree-optimize.c modified with a debugging statement:
  
 
<pre>
 
<pre>
Line 172: Line 174:
 
/* blah.h */
 
/* blah.h */
 
class Blah {
 
class Blah {
public:
+
public:
virtual int blah() __attribute__((nothrow));
+
  virtual int blah() __attribute__((nothrow));
 
};
 
};
  
 
/* blah.cpp */
 
/* blah.cpp */
 
#include "blah.h"
 
#include "blah.h"
 +
 
int Blah::blah() {
 
int Blah::blah() {
return 0;
+
  return 0;
 
}
 
}
  
Line 186: Line 189:
 
int main()
 
int main()
 
{
 
{
Blah b;
+
  Blah b;
Blah* p = &b;
+
  Blah* p = &b;
int x;
+
  int x;
x = p->blah();
+
  x = p->blah();
return 0;
+
  return 0;
 
}
 
}
 
</pre>
 
</pre>
Line 196: Line 199:
 
Compiling sample program with gcc trunk build containing above debugging statements:
 
Compiling sample program with gcc trunk build containing above debugging statements:
 
<pre>
 
<pre>
[ehren@australia 2]$ ~/gcc/dist/bin/g++ blah.cpp main.cpp -O2
+
$ ~/gcc/dist/bin/g++ blah.cpp main.cpp -O2
 
Call flags from tree-optimize.c: 64
 
Call flags from tree-optimize.c: 64
 
Call flags from tree-ssa-ccp: 0
 
Call flags from tree-ssa-ccp: 0

Revision as of 20:15, 23 October 2009

Project Name

GCC alwayszero function attribute

Project Description

This project involves extending gcc to support an alwayszero function attribute (see Bug #517370).

Project Leader(s)

Ehren Metcalfe

Project Contributor(s)

Project Details

Relevant blog posts:

A Gimple Call Flags Mystery

Adding a new function attribute to GCC

Popping My GIMPLES (a plan)

Building GCC from trunk

Possible Bug

Calling gimple_call_flags on a gimple stmt representing an indirect call to a virtual method (with a function attribute) always returns 0. This is even though the correct nonzero value of the call flags can be recognized from other parts of gcc.

For example:

tree-ssa-ccp.c modified with a debugging statement:

/* Compute a default value for variable VAR and store it in the
   CONST_VAL array.  The following rules are used to get default
   values:

   1- Global and static variables that are declared constant are
      considered CONSTANT.

   2- Any other value is considered UNDEFINED.  This is useful when
      considering PHI nodes.  PHI arguments that are undefined do not
      change the constant value of the PHI node, which allows for more
      constants to be propagated.

   3- Variables defined by statements other than assignments and PHI
      nodes are considered VARYING.

   4- Initial values of variables that are not GIMPLE registers are
      considered VARYING.  */

static prop_value_t
get_default_value (tree var)
{
  tree sym = SSA_NAME_VAR (var);
  prop_value_t val = { UNINITIALIZED, NULL_TREE };
  gimple stmt;

  stmt = SSA_NAME_DEF_STMT (var);



  /* My debugging statment */

  if (is_gimple_call (stmt))
    fprintf(stderr, "Call flags from tree-ssa-ccp.c: %d\n",
        gimple_call_flags (stmt));

  /* End My Debugging Statement */


  if (gimple_nop_p (stmt))
    {
      /* Variables defined by an empty statement are those used
   before being initialized.  If VAR is a local variable, we
   can assume initially that it is UNDEFINED, otherwise we must
   consider it VARYING.  */
      if (is_gimple_reg (sym) && TREE_CODE (sym) != PARM_DECL)
  val.lattice_val = UNDEFINED;
      else
  val.lattice_val = VARYING;
    }
  else if (is_gimple_assign (stmt)
     /* Value-returning GIMPLE_CALL statements assign to
        a variable, and are treated similarly to GIMPLE_ASSIGN.  */
     || (is_gimple_call (stmt)
         && gimple_call_lhs (stmt) != NULL_TREE)
     || gimple_code (stmt) == GIMPLE_PHI)
    {
      tree cst;
      if (gimple_assign_single_p (stmt)
    && DECL_P (gimple_assign_rhs1 (stmt))
    && (cst = get_symbol_constant_value (gimple_assign_rhs1 (stmt))))
  {
    val.lattice_val = CONSTANT;
    val.value = cst;
  }
      else
  /* Any other variable defined by an assignment or a PHI node
     is considered UNDEFINED.  */
  val.lattice_val = UNDEFINED;
    }
  else
    {
      /* Otherwise, VAR will never take on a constant value.  */
      val.lattice_val = VARYING;
    }

  return val;
}

tree-optimize.c modified with a debugging statement:

unsigned int
execute_fixup_cfg (void)
{
  basic_block bb;
  gimple_stmt_iterator gsi;
  int todo = gimple_in_ssa_p (cfun) ? TODO_verify_ssa : 0;

  if (cfun->eh)
    FOR_EACH_BB (bb)
      {
  for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
    {
      gimple stmt = gsi_stmt (gsi);
      tree decl = is_gimple_call (stmt)
                  ? gimple_call_fndecl (stmt)
      : NULL;


      /* My debugging statement */
      if (decl)
        fprintf(stderr, "Call flags from tree-optimize.c: %d\n",
            gimple_call_flags (stmt));
      /* End my debugging statement */


      if (decl
    && gimple_call_flags (stmt) & (ECF_CONST
                 | ECF_PURE 
                 | ECF_LOOPING_CONST_OR_PURE))
        {
    if (gimple_in_ssa_p (cfun))
      {
        todo |= TODO_update_ssa | TODO_cleanup_cfg;
        mark_symbols_for_renaming (stmt);
              update_stmt (stmt);
      }
        }

      maybe_clean_eh_stmt (stmt);
    }

  if (gimple_purge_dead_eh_edges (bb))
          todo |= TODO_cleanup_cfg;
      }

  /* Dump a textual representation of the flowgraph.  */
  if (dump_file)
    gimple_dump_cfg (dump_file, dump_flags);

  return todo;
}

Sample program:

/* blah.h */
class Blah {
 public:
  virtual int blah() __attribute__((nothrow));
};

/* blah.cpp */
#include "blah.h"

int Blah::blah() {
  return 0;
}

/* main.cpp */
#include "blah.h"
int main()
{
  Blah b;
  Blah* p = &b;
  int x;
  x = p->blah();
  return 0;
}

Compiling sample program with gcc trunk build containing above debugging statements:

$ ~/gcc/dist/bin/g++ blah.cpp main.cpp -O2
Call flags from tree-optimize.c: 64
Call flags from tree-ssa-ccp: 0
Call flags from tree-optimize.c: 64
Call flags from tree-optimize.c: 64