We are in the process of updating GCC/UPC's support for
the UPC dialect of C to version 4.2.0 of GCC.
GCC/UPC is described here: http://www.intrepid.com/upc.html

Generally, things are working.  However, at the moment,
all tests fail when optimizations are enabled.
For example:
test00.upc:35: internal compiler error:
   in referenced_var_check_and_insert, at tree-dfa.c:639

It is failing on this check:

(gdb) l
634
635       if (h)
636         {
637           /* DECL_UID has already been entered in the table.  Verify that 
it is
638              the same entry as TO.  See PR 27793.  */                       
    
639           gcc_assert (h->to == to);
640           return false;            
641         }                  
642
643       h = GGC_NEW (struct int_tree_map);
(gdb) p h->to
$1 = 0x2aaaae1ad160                 
(gdb) pt
 <var_decl 0x2aaaae1ad160 x1
    type <integer_type 0x2aaaaded5300 char public string-flag QI
        size <integer_cst 0x2aaaadec5810 constant invariant 8>
        unit size <integer_cst 0x2aaaadec5840 constant invariant 1>
        align 8 symtab 0 alias set -1 precision 8 min <integer_cst 
0x2aaaadec58d0 -128> max
<integer_cst 0x2aaaadec5990 127>
        pointer_to_this <pointer_type 0x2aaaadee8a80>>
    addressable used public static common QI defer-output file test00.upc line 
26 size
<integer_cst 0x2aaaadec5810 8> unit size <integer_cst 0x2aaaadec5840 1>
    align 8>
(gdb) p to
$2 = 0x2aaaae1b7630
(gdb) pt
 <var_decl 0x2aaaae1b7630 x1
    type <integer_type 0x2aaaaded5300 char public string-flag QI        
        size <integer_cst 0x2aaaadec5810 constant invariant 8>
        unit size <integer_cst 0x2aaaadec5840 constant invariant 1>
        align 8 symtab 0 alias set -1 precision 8 min <integer_cst 
0x2aaaadec58d0 -128> max
<integer_cst 0x2aaaadec5990 127>
        pointer_to_this <pointer_type 0x2aaaadee8a80>>
    addressable used public static common QI defer-output file test00.upc line 
26 size
<integer_cst 0x2aaaadec5810 8> unit size <integer_cst 0x2aaaadec5840 1>
    align 8>


Above, the two tree nodes are clones of each other created by the
following UPC-specific code:

1109    /* Convert shared variable reference VAR into a shared pointer
1110       value of the form {0, 0, &VAR} */
1111
1112    tree
1113    upc_build_shared_var_addr (tree type, tree var)
1114    {
1115      tree new_var, var_addr, val;
1116      if (!(TREE_CODE (var) == VAR_DECL && TREE_SHARED (var)))
1117        abort ();
1118      if (!(TREE_CODE (type) == POINTER_TYPE && TYPE_SHARED (TREE_TYPE 
(type))))
1119        abort ();
1120
1121      /* Create a VAR_DECL that is the same as VAR, but
1122         with qualifiers (esp. TYPE_QUAL_SHARED) removed so that
1123         we can create the actual address of the variable (in the shared
1124         section) without infinite recursion in the
1125         gimplification pass.  Make sure the new copy has
1126         the same UID as the old.  In the future, we might need
1127         to reference the symbol name directly. */
1128
1129      new_var = copy_node (var);
1130      DECL_UID (new_var) = DECL_UID (var);
1131      TREE_TYPE (new_var) = TYPE_MAIN_VARIANT (TREE_TYPE (var));
1132      TREE_SHARED (new_var) = 0;
1133      TREE_STRICT (new_var) = 0;
1134      TREE_RELAXED (new_var) = 0;
1135      var_addr = build_fold_addr_expr (new_var);
1136      TREE_CONSTANT (var_addr) = 1;
1137      val = upc_build_shared_ptr_value (type,
1138                                    integer_zero_node,
1139                                    integer_zero_node,
1140                                    var_addr);
1141      return val;
1142    }


As background, GCC/UPC adds a new qualifier, "shared" to
indicate that a value must be accessed remotely and that it
is shared across all UPC "threads" (which can be thought of
as processes all running the same program, but with
differing local copies of data).  The UPC specific aspects
of the language are translated by a gimplify pass into
normal gimple trees that are then passed to the middle
and back ends of GCC.  For example a reference to a value
of a type that is qualified as "shared" will result in a
call to a (possibly inlined) remote "get" library routine.

Where this gimplify pass can get confused is when it sees
a reference to a shared variable.  If it sees a reference to
a shared variable on the right hand side of an assignment,
it assumes that its value is needed and generates a remote
get call.  The address of a shared variable has three
parts (phase, thread, virtual address).  For declared
variables, the phase and thread are always 0.  A constructor
is used to create a shared address.  That's what
upc_build_shared_ptr_value() does above.  The virtual address
part of the shared address is simply the regular address of
the variable, because all shared variables are collected
together in their own "upc_shared" linkage section.  This
section is needed simply for address assignment purposes.
The actual shared data is located in a global shared
address region.

The code above clones a shared variable, stripping its type
qualifiers (most importantly the "shared" qualifier).  When
the address of the cloned variable is taken, its normal
C pointer-sized address will result, and the special
gimplify pass doesn't get confused, thinking that the
address of the variable is a shared address. 

The code above isn't clever.  It clones the variable
each time it needs to generate a shared address.  In GCC
4.2, this runs into problems in the optimization
pass that implements special checks for this sort of
inconsistency.

The discussion above is a (very) long lead up to a
request for ideas and suggestions for better
handling this situation.

One simple idea would be to leave the original VAR_DECL as
is, but create a tree node that is an address expression
which refers only to the variable's external name, and
thus doesn't refer to any VAR_DECL.  Is the possible?

Schematically, it might look like thins:

   ptr_to_main_variant = build_pointer_type (
                           TYPE_MAIN_VARIANT (TREE_TYPE (var)));

   var_addr = build_fold_addr_expr_with_type (DECL_NAME(var),
                                              ptr_to_main_variant);

but of course ADDR_EXPR doesn't allow a bare reference
to an identifier.  Is there some way to generate a tree
node that creates an address, using only the external
linkage name?

The other idea that I've experimented with is to
have the gimplify pass look for ADDR_EXPR of a shared
variable, and rather than transform this into a
3 part constructor (phase, thread, virtual address),
leave it as is, and then have a language-specific
routine create the 3 part address literal using
appropriate varasm constructs.  This seemed promising,
but runs into problems with various other
consistency checks in the compiler that I haven't
tried to figure out yet.

All suggestions/help appreciated, - Gary

Reply via email to