This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
(gcc 4.2) how to create an ADDR_EXPR that refers to a linkage name?
- From: Gary Funck <gary at intrepid dot com>
- To: GCC List <gcc at gcc dot gnu dot org>
- Date: Sat, 1 Sep 2007 10:26:47 -0700
- Subject: (gcc 4.2) how to create an ADDR_EXPR that refers to a linkage name?
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