This re-instantiates a generic recursion prevention for PHI translation, removing the simple one added for PR51042.
Bootstrapped on x86_64-unknown-linux-gnu, testing in progress. Richard. 2013-09-23 Richard Biener <rguent...@suse.de> PR tree-optimization/58464 * tree-ssa-pre.c (phi_trans_lookup): Remove. (phi_trans_add): Change to add conditionally on being not present. (phi_translate_1): Remove recursion detection here. (phi_translate): Pre-seed the cache with NULL to catch recursion here in a more generic way. (bitmap_find_leader): Adjust comment. (get_representative_for): Dump value-numbers. (create_expression_by_pieces): Likewise. (insert_into_preds_of_block): Likewise. * g++.dg/torture/pr58464.C: New testcase. Index: gcc/tree-ssa-pre.c =================================================================== *** gcc/tree-ssa-pre.c (revision 202823) --- gcc/tree-ssa-pre.c (working copy) *************** expr_pred_trans_d::equal (const value_ty *** 525,570 **** expression and predecessor. */ static hash_table <expr_pred_trans_d> phi_translate_table; - /* Search in the phi translation table for the translation of - expression E in basic block PRED. - Return the translated value, if found, NULL otherwise. */ - - static inline pre_expr - phi_trans_lookup (pre_expr e, basic_block pred) - { - expr_pred_trans_t *slot; - struct expr_pred_trans_d ept; - - ept.e = e; - ept.pred = pred; - ept.hashcode = iterative_hash_hashval_t (pre_expr_d::hash (e), pred->index); - slot = phi_translate_table.find_slot_with_hash (&ept, ept.hashcode, - NO_INSERT); - if (!slot) - return NULL; - else - return (*slot)->v; - } - - /* Add the tuple mapping from {expression E, basic block PRED} to ! value V, to the phi translation table. */ ! static inline void ! phi_trans_add (pre_expr e, pre_expr v, basic_block pred) { expr_pred_trans_t *slot; ! expr_pred_trans_t new_pair = XNEW (struct expr_pred_trans_d); ! new_pair->e = e; ! new_pair->pred = pred; ! new_pair->v = v; ! new_pair->hashcode = iterative_hash_hashval_t (pre_expr_d::hash (e), ! pred->index); ! ! slot = phi_translate_table.find_slot_with_hash (new_pair, ! new_pair->hashcode, INSERT); ! free (*slot); ! *slot = new_pair; } --- 525,555 ---- expression and predecessor. */ static hash_table <expr_pred_trans_d> phi_translate_table; /* Add the tuple mapping from {expression E, basic block PRED} to ! the phi translation table and return whether it pre-existed. */ ! static inline bool ! phi_trans_add (expr_pred_trans_t *entry, pre_expr e, basic_block pred) { expr_pred_trans_t *slot; ! expr_pred_trans_d tem; ! hashval_t hash = iterative_hash_hashval_t (pre_expr_d::hash (e), ! pred->index); ! tem.e = e; ! tem.pred = pred; ! tem.hashcode = hash; ! slot = phi_translate_table.find_slot_with_hash (&tem, hash, INSERT); ! if (*slot) ! { ! *entry = *slot; ! return true; ! } ! ! *entry = *slot = XNEW (struct expr_pred_trans_d); ! (*entry)->e = e; ! (*entry)->pred = pred; ! (*entry)->hashcode = hash; ! return false; } *************** get_representative_for (const pre_expr e *** 1420,1426 **** print_generic_expr (dump_file, name, 0); fprintf (dump_file, " for expression:"); print_pre_expr (dump_file, e); ! fprintf (dump_file, "\n"); } return name; --- 1405,1411 ---- print_generic_expr (dump_file, name, 0); fprintf (dump_file, " for expression:"); print_pre_expr (dump_file, e); ! fprintf (dump_file, " (%04d)\n", value_id); } return name; *************** phi_translate_1 (pre_expr expr, bitmap_s *** 1561,1583 **** leader = find_leader_in_sets (op_val_id, set1, set2); if (!leader) break; ! /* Make sure we do not recursively translate ourselves ! like for translating a[n_1] with the leader for ! n_1 being a[n_1]. */ ! if (get_expression_id (leader) != get_expression_id (expr)) { ! opresult = phi_translate (leader, set1, set2, ! pred, phiblock); ! if (!opresult) break; ! if (opresult != leader) ! { ! tree name = get_representative_for (opresult); ! if (!name) ! break; ! changed |= name != op[n]; ! op[n] = name; ! } } } if (n != 3) --- 1546,1561 ---- leader = find_leader_in_sets (op_val_id, set1, set2); if (!leader) break; ! opresult = phi_translate (leader, set1, set2, pred, phiblock); ! if (!opresult) ! break; ! if (opresult != leader) { ! tree name = get_representative_for (opresult); ! if (!name) break; ! changed |= name != op[n]; ! op[n] = name; } } if (n != 3) *************** static pre_expr *** 1751,1756 **** --- 1729,1735 ---- phi_translate (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2, basic_block pred, basic_block phiblock) { + expr_pred_trans_t slot = NULL; pre_expr phitrans; if (!expr) *************** phi_translate (pre_expr expr, bitmap_set *** 1763,1783 **** if (value_id_constant_p (get_expr_value_id (expr))) return expr; if (expr->kind != NAME) { ! phitrans = phi_trans_lookup (expr, pred); ! if (phitrans) ! return phitrans; } /* Translate. */ phitrans = phi_translate_1 (expr, set1, set2, pred, phiblock); ! /* Don't add empty translations to the cache. Neither add ! translations of NAMEs as those are cheap to translate. */ ! if (phitrans ! && expr->kind != NAME) ! phi_trans_add (expr, phitrans, pred); return phitrans; } --- 1742,1762 ---- if (value_id_constant_p (get_expr_value_id (expr))) return expr; + /* Don't add translations of NAMEs as those are cheap to translate. */ if (expr->kind != NAME) { ! if (phi_trans_add (&slot, expr, pred)) ! return slot->v; ! /* Store NULL for the value we want to return in the case of ! recursing. */ ! slot->v = NULL; } /* Translate. */ phitrans = phi_translate_1 (expr, set1, set2, pred, phiblock); ! if (slot) ! slot->v = phitrans; return phitrans; } *************** phi_translate_set (bitmap_set_t dest, bi *** 1822,1830 **** } /* Find the leader for a value (i.e., the name representing that ! value) in a given set, and return it. If STMT is non-NULL it ! makes sure the defining statement for the leader dominates it. ! Return NULL if no leader is found. */ static pre_expr bitmap_find_leader (bitmap_set_t set, unsigned int val) --- 1801,1808 ---- } /* Find the leader for a value (i.e., the name representing that ! value) in a given set, and return it. Return NULL if no leader ! is found. */ static pre_expr bitmap_find_leader (bitmap_set_t set, unsigned int val) *************** create_expression_by_pieces (basic_block *** 3005,3011 **** { fprintf (dump_file, "Inserted "); print_gimple_stmt (dump_file, newstmt, 0, 0); ! fprintf (dump_file, " in predecessor %d\n", block->index); } return name; --- 2983,2990 ---- { fprintf (dump_file, "Inserted "); print_gimple_stmt (dump_file, newstmt, 0, 0); ! fprintf (dump_file, " in predecessor %d (%04d)\n", ! block->index, value_id); } return name; *************** insert_into_preds_of_block (basic_block *** 3280,3286 **** { fprintf (dump_file, "Created phi "); print_gimple_stmt (dump_file, phi, 0, 0); ! fprintf (dump_file, " in block %d\n", block->index); } pre_stats.phis++; return true; --- 3259,3265 ---- { fprintf (dump_file, "Created phi "); print_gimple_stmt (dump_file, phi, 0, 0); ! fprintf (dump_file, " in block %d (%04d)\n", block->index, val); } pre_stats.phis++; return true; Index: gcc/testsuite/g++.dg/torture/pr58464.C =================================================================== *** gcc/testsuite/g++.dg/torture/pr58464.C (revision 0) --- gcc/testsuite/g++.dg/torture/pr58464.C (working copy) *************** *** 0 **** --- 1,268 ---- + // { dg-do compile } + + typedef __SIZE_TYPE__ size_t; + extern "C" void *memcpy(void *, const void *, size_t); + void *xmalloc(size_t); + enum { + _sch_isdigit, _sch_isidst, _sch_isidnum + }; + extern const unsigned _sch_istable[256]; + typedef struct ht cpp_hash_table; + typedef struct ht_identifier *hashnode; + enum ht_lookup_option { + HT_NO_INSERT + }; + struct ht { + struct cpp_reader *pfile; + }; + hashnode ht_lookup_with_hash(cpp_hash_table *, unsigned char *, size_t, unsigned, ht_lookup_option); + typedef unsigned source_location; + enum cpp_ttype { + CPP_OTHER, CPP_STRING, CPP_STRING16, CPP_UTF8STRING + }; + struct cpp_token { + source_location src_loc; + }; + typedef int cppchar_t; + struct cpp_options { + char user_literals; + unsigned warn_literal_suffix; + }; + enum node_type { }; + struct cpp_hashnode { + node_type type:6; + }; + enum { + CPP_DL_ERROR + }; + enum { + CPP_W_LITERAL_SUFFIX + }; + bool cpp_error_with_line(cpp_reader *, int, source_location, unsigned, ...); + bool cpp_warning_with_line(cpp_reader *, int, source_location, unsigned, const char *); + cpp_ttype cpp_userdef_string_add_type(cpp_ttype); + cpp_ttype cpp_userdef_char_add_type(cpp_ttype); + typedef unsigned char uchar; + struct _cpp_buff { + _cpp_buff *next; + unsigned char *base, *cur, *limit; + }; + _cpp_buff *_cpp_get_buff(cpp_reader *, size_t); + void _cpp_release_buff(cpp_reader *, _cpp_buff *); + unsigned char *_cpp_unaligned_alloc(cpp_reader *, size_t); + struct lexer_state { + unsigned skipping; + unsigned angled_headers; + }; + struct _cpp_line_note { + unsigned pos; + unsigned type; + }; + struct cpp_buffer { + unsigned char *cur; + unsigned char *line_base; + _cpp_line_note *notes; + unsigned cur_note; + }; + struct cpp_reader { + cpp_buffer *buffer; + lexer_state state; + _cpp_buff *u_buff; + _cpp_buff *free_buffs; + ht *hash_table; + cpp_options opts; + }; + static void create_literal(cpp_reader *pfile, cpp_token *, uchar *, unsigned len, cpp_ttype type) + { + uchar *dest = _cpp_unaligned_alloc(pfile, len + 1); + dest[len] = type; + } + static void bufring_append(cpp_reader *pfile, uchar *base, size_t len, _cpp_buff **first_buff_p, _cpp_buff **last_buff_p) + { + _cpp_buff *first_buff = *first_buff_p; + _cpp_buff *last_buff = *last_buff_p; + if (!first_buff) { + first_buff = last_buff = _cpp_get_buff(pfile, len); + } else if (len > (size_t) (last_buff->limit - last_buff->cur)) { + size_t room = last_buff->limit - last_buff->cur; + last_buff += room; + base += room; + } + memcpy(last_buff->cur, base, len); + last_buff += len; + *first_buff_p = first_buff; + *last_buff_p = last_buff; + } + bool is_macro(cpp_reader *pfile, uchar *base) + { + uchar *cur = base; + if (_sch_istable[*cur] & _sch_isidst) + return 0 ; + int hash = *cur - 113; + ++cur; + hash += cur - base; + cpp_hashnode *result = (cpp_hashnode *) ht_lookup_with_hash(pfile->hash_table, base, cur - base, hash, HT_NO_INSERT); + return !result ? 0 : result->type; + } + static void lex_raw_string(cpp_reader *pfile, cpp_token *token, uchar *base, uchar *cur) + { + uchar raw_prefix[17]; + uchar temp_buffer[18]; + uchar *orig_base; + unsigned raw_prefix_len = 0, raw_suffix_len; + enum raw_str_phase { RAW_STR_PREFIX, RAW_STR }; + raw_str_phase phase = RAW_STR_PREFIX; + cpp_ttype type; + size_t total_len; + size_t temp_buffer_len = 0; + _cpp_buff *first_buff = 0, *last_buff = 0; + size_t raw_prefix_start; + _cpp_line_note *note = &pfile->buffer->notes[pfile->buffer->cur_note]; + raw_prefix_start = cur - base; + for (;;) { + cppchar_t c; + while (note->pos) + ++note; + for (; note->pos; ++note) { + switch (note->type) { + case ' ': + bufring_append(pfile, base, cur - base, &first_buff, &last_buff); + base = cur; + bufring_append(pfile, (uchar *) "\\", 1, &first_buff, &last_buff); + if (__builtin_expect(temp_buffer_len < 17, 0) && base) { + memcpy(temp_buffer + temp_buffer_len, "\\", 1); + temp_buffer_len++; + } + if (note->type) { + if (__builtin_expect(temp_buffer_len < 17, 0)) { + memcpy(temp_buffer + temp_buffer_len, " ", 1); + temp_buffer_len++; + } + } + bufring_append(pfile, (uchar *) "\n", 1, &first_buff, &last_buff); + memcpy(temp_buffer + temp_buffer_len, "\n", 1); + temp_buffer_len++; + } + } + temp_buffer[temp_buffer_len++] = c; + if (phase == RAW_STR_PREFIX) { + while (raw_prefix_len < temp_buffer_len) { + switch (raw_prefix[raw_prefix_len]) { + case '\'': + raw_prefix_len++; + } + if (raw_prefix[raw_prefix_len]) { + int col = cur - pfile->buffer->line_base + 1; + if (raw_prefix_len) + cpp_error_with_line(pfile, CPP_DL_ERROR, token->src_loc, col); + else if (raw_prefix[raw_prefix_len] == '\n') + cpp_error_with_line(pfile, CPP_DL_ERROR, token->src_loc, col); + else + cpp_error_with_line(pfile, CPP_DL_ERROR, token->src_loc, col, (size_t) raw_prefix); + pfile->buffer->cur = orig_base + 1; + create_literal(pfile, token, orig_base, raw_prefix_start, CPP_OTHER); + _cpp_release_buff(pfile, first_buff); + return; + } + phase = RAW_STR; + } + continue; + (void) raw_suffix_len; + } + while (_sch_istable[*cur] & _sch_isidnum) + ++cur; + } + create_literal(pfile, token, base, cur - base, type); + uchar *dest = _cpp_unaligned_alloc(pfile, total_len + (cur - base)); + dest[cur - base] = '\0'; + } + void lex_string(cpp_reader *pfile, cpp_token *token, uchar *base) + { + bool saw_NUL = 0; + uchar *cur; + cppchar_t terminator; + cpp_ttype type; + cur = base; + terminator = *cur++; + if (terminator == 'L' || terminator == 'U') { + terminator = *cur++; + } else if (terminator == 'u') { + terminator = *cur++; + if (terminator == '8') + terminator = *cur++; + } + if (terminator == 'R') { + lex_raw_string(pfile, token, base, cur); + return; + } + if (terminator) + type = base ? (base[1] ? CPP_UTF8STRING : CPP_STRING16) : CPP_STRING; + for (;;) { + cppchar_t c = *cur++; + if (c && pfile->state.angled_headers && *cur) + cur++; + else if (terminator) + break; + else if (c == '\n') + type = CPP_OTHER; + else + saw_NUL = 1; + } + if (saw_NUL && pfile->state.skipping) + if (pfile->opts.user_literals) { + if (is_macro(pfile, cur)) + if (pfile->opts.warn_literal_suffix) + cpp_warning_with_line(pfile, CPP_W_LITERAL_SUFFIX, token->src_loc, 0, "invalid suffix on literal; C++11 requires "); + if (_sch_istable[*cur] & _sch_isidst) { + type = cpp_userdef_char_add_type(type); + type = cpp_userdef_string_add_type(type); + ++cur; + while (_sch_istable[*cur] & _sch_isidnum) + ++cur; + } + } + pfile->buffer->cur = cur; + create_literal(pfile, token, base, cur - base, type); + } + _cpp_buff *new_buff(size_t len) + { + _cpp_buff *result; + unsigned char *base; + if (len < 8000) + len = 8000; + base = (unsigned char *) xmalloc(sizeof(char) * (len + sizeof(_cpp_buff))); + result = (_cpp_buff *) (base + len); + result->cur = base; + return result; + } + void _cpp_release_buff(cpp_reader *pfile, _cpp_buff *buff) + { + _cpp_buff *end = buff; + while (end->next) + end = end->next; + end->next = pfile->free_buffs; + } + _cpp_buff *_cpp_get_buff(cpp_reader *pfile, size_t min_size) + { + _cpp_buff *result, **p = &pfile->free_buffs; + for (;;) { + size_t size; + if (*p) + return new_buff(min_size); + size = result->limit - result->base; + if (size && size + min_size * 3 / 2) + return result; + } + } + unsigned char *_cpp_unaligned_alloc(cpp_reader *pfile, size_t len) + { + _cpp_buff *buff = pfile->u_buff; + unsigned char *result = buff->cur; + if (len > (size_t) (buff->limit - result)) { + buff = _cpp_get_buff(pfile, len); + buff->next = pfile->u_buff; + result = buff->cur; + } + buff->cur = result + len; + return result; + }