Working with GCC 4.0.1, we're implementing an experimental dialect of C, called UPC, which offers language extensions for parallel computing in a distributed shared memory setting (see: http://intrepid.com/upc). Generally, the work has proceeded well, and the language-specific callout in gimplify_expr() have been sufficient to implement UPC features by rewriting language extensions into C-like tree structures that can be further gimplified. However, we've run into a glitch, and I'm not quite certain where the fix should go, or how the fix should be implemented. UPC has a shared pointer that can address data in another process (called a thread in UPC terminology). A shared pointer has the following fields: struct shared_ptr_struct { unsigned long int phase : 48; unsigned int thread : 16; void *offset; }; typedef struct shared_ptr_struct shared_ptr_t; Two shared pointers are equal if all fields are equal: int cmp_ptr_eq (shared_ptr_t p1, shared_ptr_t p2) { return p1.offset == p2.offset && p1.phase == p2.phase && p1.thread == p2.thread; } The UPC-specific gimplify routine which implements shared pointer comparisons rewrites an expression like (p1 == p2) into the sort of code shown above. Here's the actual UPC-specific gimplify code: *expr_p = build_binary_op (TRUTH_ANDIF_EXPR, off_cmp, build_binary_op (TRUTH_ANDIF_EXPR, phase_cmp, offset_cmp, 0), 0); where off_cmp, thread_cmp and phase_cmp are expressions which evaluate the equality comparison for the offset, thread, and phase fields. For example, off0 = build3 (COMPONENT_REF, o_t, op0, upc_vaddr_field_node, NULL_TREE); off1 = build3 (COMPONENT_REF, o_t, op1, upc_vaddr_field_node, NULL_TREE); off_cmp = build_binary_op (code, off0, off1, 0); All this works pretty well, but ICE's on the following small UPC test program: shared int *p; int main(int argc, char **argv) { int errors = 0; if (p == NULL) { /* no action */ } else { errors = 1; } } % upc t.upc t.upc: In function 'main': t.upc:9: internal compiler error: in invert_truthvalue, at fold-const.c:3026 Please submit a full bug report, with preprocessed source if appropriate. See <URL:http://www.intrepid.com/upc/bugs.html> for instructions. It fails here: #1 0x00000000005c2c39 in invert_truthvalue (arg=0x2aaaae0bac30) at /upc/gcc-upc-4/src/gcc/fold-const.c:3026 3026 gcc_assert (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE); The type of the arg is integer_type, not boolean: (gdb) p arg->common.type $1 = 0x2aaaadecca90 (gdb) pt <integer_type 0x2aaaadecca90 int sizes-gimplified public SI size <integer_cst 0x2aaaadec6a80 type <integer_type 0x2aaaadecc5b0 bit_size_type> constant invariant 32> unit size <integer_cst 0x2aaaadec65a0 type <integer_type 0x2aaaadecc4e0 long unsigned int> constant invariant 4> align 32 symtab 0 alias set -1 precision 32 min <integer_cst 0x2aaaadec69f0 -2147483648> max <integer_cst 0x2aaaadec6a20 2147483647> pointer_to_this <pointer_type 0x2aaaadee44e0>> It is an integer type because the initial build_binary_op(TRUTH_ANDIF_EXPR ... uses the type of the result of the comparisons, which is integer_type. The TRUTH_ANDIF expr is gimplified in gimplify_boolean_expr: 3079 gimplify_boolean_expr (tree *expr_p) 3080 { 3081 /* Preserve the original type of the expression. */ 3082 tree type = TREE_TYPE (*expr_p); 3083 3084 *expr_p = build (COND_EXPR, type, *expr_p, 3085 convert (type, boolean_true_node), 3086 convert (type, boolean_false_node)); 3087 3088 return GS_OK; 3089 } basically a boolean expression b is converted into a true or false value by rewriting it as: (b) ? true : false However, as the comment states "Preserve the original type of the expression.", the original type of the expression, 'b', is kept. In this case, the type is integer_type not boolean type. Thus the original (EQ_EXPR p1 p2) is rewritten into (COND_EXPR integer_type (TRUTH_ANDIF_EXPR (EQ_EXPR p1.offset p2.offset) TRUTH_ANDIF_EXPR (EQ_EXPR p1.phase p2.phase) (EQ_EXPR p1.thread p2.thread))) (boolean_type true) (boolean_type false)) If we call the condition expression above, 'cond', then the test program has the following structure: (COND_EXPR (cond) (void) (MODIFY_EXPR (VAR_DECL errors) (constant 1))) Invert_truthvalue wants to rewrite the construct above into: (COND_EXPR (TRUTH_NOT_EXPR (cond)) (MODIFY_EXPR (VAR_DECL errors) (constant 1)) (void)) This runs into trouble when invert_truthvalue attempts to negate the condition 'cond', insisting that cond be a boolean expression. Under normal conditions this isn't a problem, because the normal flow of control of parsing if statemtns and then gimplifying them would have forced 'cond' to be of boolen type. The problem arises when UPC rewrites the EQ_EXPR into a TRUTH_ANDIF expr. The condition expression missed a chance to be converted to a boolean type in gimplify_boolean_expr(), because that function preserves the incoming (integer) type, and it misses an opportunity again when the 'cond' expression is sent to gimplify_cond_expr(). If the control flow in gimplify_cond_expr() had made it to here: 2193 /* Make sure the condition has BOOLEAN_TYPE. */ 2194 TREE_OPERAND (expr, 0) = gimple_boolify (TREE_OPERAND (expr, 0)); Then, the condition, 'cond' and its sub-parts, would've been converted to a boolean type. But, in the case described above, the logic exits early, just above the call to the call to gimple_boolify() above. The actual sequence of events within gimplify_cond_expr() for the case being discussed is: Breakpoint 5, gimplify_cond_expr (expr_p=0x2aaaae0a1a38, pre_p=0x7fffffac1550, post_p=0x7fffffac13f8, target=0x0, fallback=fb_rvalue) at /upc/gcc-upc-4/src/gcc/gimplify.c:2123 2123 tree expr = *expr_p; (gdb) n 2127 type = TREE_TYPE (expr); where type is an integer type: (gdb) pt <integer_type 0x2aaaadecca90 int sizes-gimplified public SI size <integer_cst 0x2aaaadec6a80 type <integer_type 0x2aaaadecc5b0 bit_size_type> constant invariant 32> unit size <integer_cst 0x2aaaadec65a0 type <integer_type 0x2aaaadecc4e0 long unsigned int> constant invariant 4> align 32 symtab 0 alias set -1 precision 32 min <integer_cst 0x2aaaadec69f0 -2147483648> max <integer_cst 0x2aaaadec6a20 2147483647> pointer_to_this <pointer_type 0x2aaaadee44e0>> the next step creates a gimple temp variable of the same type as the expression (integer type): 2133 else if (! VOID_TYPE_P (type)) (gdb) 2137 if (target) (gdb) 2146 else if ((fallback & fb_lvalue) == 0) (gdb) 2148 result = tmp2 = tmp = create_tmp_var (TREE_TYPE (expr), "iftmp"); A little more work is done, and then gimplify_cond_expr() returns, before getting to the call to gimple_boolify(). 2186 /* Move the COND_EXPR to the prequeue. */ 2187 gimplify_and_add (expr, pre_p); 2188 2189 *expr_p = result; 2190 return ret; Here's what expr looks like just before returning: <cond_expr 0x2aaaae0bc050 type <integer_type 0x2aaaadecca90 int sizes-gimplified public SI size <integer_cst 0x2aaaadec6a80 constant invariant 32> unit size <integer_cst 0x2aaaadec65a0 constant invariant 4> align 32 symtab 0 alias set -1 precision 32 min <integer_cst 0x2aaaadec69f0 -2147483648> max <integer_cst 0x2aaaadec6a20 2147483647> pointer_to_this <pointer_type 0x2aaaadee44e0>> side-effects arg 0 <truth_andif_expr 0x2aaaae0bc000 type <integer_type 0x2aaaadecca90 int> side-effects arg 0 <eq_expr 0x2aaaae0a1be0 type <integer_type 0x2aaaadecca90 int> side-effects arg 0 <component_ref 0x2aaaae0a1b40 type <pointer_type 0x2aaaadee59c0> side-effects arg 0 <save_expr 0x2aaaae0ac240 type <record_type 0x2aaaadf87b60 upc_shared_ptr_t> side-effects invariant arg 0 <view_convert_expr 0x2aaaae0ac200 type <record_type 0x2aaaadf87b60 upc_shared_ptr_t> arg 0 <var_decl 0x2aaaae0ba410 p>>> arg 1 <field_decl 0x2aaaadf87ea0 vaddr>> arg 1 <component_ref 0x2aaaae0a1b90 type <pointer_type 0x2aaaadee59c0> side-effects arg 0 <save_expr 0x2aaaae0ac280 type <record_type 0x2aaaadf87b60 upc_shared_ptr_t> side-effects invariant arg 0 <constructor 0x2aaaadf8b000 type <record_type 0x2aaaadf87b60 upc_shared_ptr_t> constant static arg 0 <tree_list 0x2aaaadf884e0 purpose <field_decl 0x2aaaadf87d00 phase> value <integer_cst 0x2aaaadedf720 0> chain <tree_list 0x2aaaadf884b0>>>> arg 1 <field_decl 0x2aaaadf87ea0 vaddr>>> arg 1 <truth_andif_expr 0x2aaaae0a1fa0 type <integer_type 0x2aaaadecca90 int> side-effects arg 0 <eq_expr 0x2aaaae0a1f50 type <integer_type 0x2aaaadecca90 int> side-effects arg 0 <bit_and_expr 0x2aaaae0a1f00 type <integer_type 0x2aaaadeccd00 long unsigned int> side-effects arg 0 <bit_field_ref 0x2aaaae0a1eb0 type <integer_type 0x2aaaadeccd00 long unsigned int> side-effects unsigned arg 0 <save_expr 0x2aaaae0ac240> arg 1 <integer_cst 0x2aaaae0b7ab0 constant invariant 64> arg 2 <integer_cst 0x2aaaadedf600 constant invariant 0>> arg 1 <integer_cst 0x2aaaae0b7a50 constant invariant 281474976710655>> arg 1 <bit_and_expr 0x2aaaae0a1e60 type <integer_type 0x2aaaadeccd00 long unsigned int> side-effects arg 0 <bit_field_ref 0x2aaaae0a1e10 type <integer_type 0x2aaaadeccd00 long unsigned int> side-effects unsigned arg 0 <save_expr 0x2aaaae0ac280> arg 1 <integer_cst 0x2aaaae0b7ab0 64> arg 2 <integer_cst 0x2aaaadedf600 0>> arg 1 <integer_cst 0x2aaaae0b7a50 281474976710655>>> arg 1 <eq_expr 0x2aaaae0a1cd0 type <integer_type 0x2aaaadecca90 int> side-effects arg 0 <component_ref 0x2aaaae0a1c30 type <integer_type 0x2aaaadecc9c0 short unsigned int> side-effects arg 0 <save_expr 0x2aaaae0ac240> arg 1 <field_decl 0x2aaaadf87dd0 thread>> arg 1 <component_ref 0x2aaaae0a1c80 type <integer_type 0x2aaaadecc9c0 short unsigned int> side-effects arg 0 <save_expr 0x2aaaae0ac280> arg 1 <field_decl 0x2aaaadf87dd0 thread>>>>> arg 1 <modify_expr 0x2aaaae0bc0a0 type <void_type 0x2aaaadee1c30 void VOID align 8 symtab 0 alias set -1 pointer_to_this <pointer_type 0x2aaaadee1d00>> side-effects arg 0 <var_decl 0x2aaaae0bac30 iftmp.0 type <integer_type 0x2aaaadecca90 int> used ignored SI file t.upc line 9 size <integer_cst 0x2aaaadec6a80 32> unit size <integer_cst 0x2aaaadec65a0 4> align 32 context <function_decl 0x2aaaae0b89c0 main>> arg 1 <integer_cst 0x2aaaadedf750 constant invariant 1>> arg 2 <modify_expr 0x2aaaae0bc0f0 type <void_type 0x2aaaadee1c30 void> side-effects arg 0 <var_decl 0x2aaaae0bac30 iftmp.0> arg 1 <integer_cst 0x2aaaadedf720 constant invariant 0>>> Notice how the type of arg0, the TRUTH_ANDIF_EXPR, is integer type, and not boolean. This will cause invert_truthvalue() to abort a bit later on. Possible fixes are: 1. Move the call to gimplify_boolean_expr() up to just before line 2137: 2135 tree result; 2136 2137 if (target) 2138 { 2139 ret = gimplify_expr (&target, pre_p, post_p, 2140 is_gimple_min_lval, fb_lvalue); 2141 if (ret != GS_ERROR) 2142 ret = GS_OK; 2143 result = tmp = target; 2144 tmp2 = unshare_expr (target); 2145 } 2146 else if ((fallback & fb_lvalue) == 0) 2. place the call to gimplify_boolean_expr() just before the call to invert_truthvalue(), in gimplify_cond_expr() - shown ifdef'ed out below: 2234 else if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 2))) 2235 /* Rewrite "if (a); else b" to "if (!a) b" */ 2236 { 2237 #if 0 2238 /* Make sure the condition has BOOLEAN_TYPE. */ 2239 TREE_OPERAND (expr, 0) = gimple_boolify (TREE_OPERAND (expr, 0)); 2240 #endif 2241 TREE_OPERAND (expr, 0) = invert_truthvalue (TREE_OPERAND (expr, 0)); 2242 ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL, 2243 is_gimple_condexpr, fb_rvalue); 3. Or call gimplify_boolean_expr() in the original language-specific expansion of pointer comparison. This strikes me as not a good solution because it may change the type semantics of the expression in an undersirable way. I've tested alternative #2 above, and it fixes the problem. I tried replicating the problem in regular C code, but cannot. I'd appreciate hearing from those who understand the gimplify logic, and can tell me if the language-specific hook is doing something wrong, or if a fix such #1 or #2 above makes sense?