Bug 18683

Summary: [4.0 Regression] seg fault in local allocate
Product: gcc Reporter: Andrew Pinski <pinskia>
Component: middle-endAssignee: Not yet assigned to anyone <unassigned>
Severity: critical CC: gcc-bugs
Priority: P2 Keywords: ice-on-valid-code
Version: 4.0.0   
Target Milestone: 4.0.0   
Host: Target: powerpc-darwin
Build: Known to work: 3.3.2
Known to fail: 4.0.0 Last reconfirmed: 2004-11-29 01:31:18
Bug Depends on:    
Bug Blocks: 12850    

Description Andrew Pinski 2004-11-26 18:35:44 UTC
Using the code in PR 12850 at -O0, I get a seg fault on the mainline.  I think this is a recent regression 
but I don't know for sure.
Comment 1 Andrew Pinski 2004-11-29 01:31:17 UTC
Reduced down to:
typedef unsigned long long int uint64_t;
template<class _CharT>
struct char_traits;
template<typename _CharT, typename _Traits = char_traits<_CharT> >
class basic_ostream;
typedef basic_ostream<char> ostream;
template<typename _CharT, typename _Traits>
struct basic_ostream
  typedef basic_ostream<_CharT, _Traits> __ostream_type;
  operator<<(long long __n);
  operator<<(unsigned long long __n);
extern ostream cout;

template<class IntType>
struct linear_congruential
  template<class CharT, class Traits>
  friend basic_ostream<CharT,Traits>&
  operator<<(basic_ostream<CharT,Traits>& os,
             const linear_congruential& lcg)
    return os << lcg._x;
  uint64_t _x;
void instantiate_all()
  linear_congruential<uint64_t> lcf;
  uint64_t _x;
  cout << lcf;
Comment 2 Andrew Pinski 2004-11-29 01:41:12 UTC
Reduced a little further, note removing the templates make it go away:
template<typename _CharT>
struct basic_ostream
  basic_ostream& operator<<(int __n);
extern basic_ostream<char>  cout;
template<int> struct linear_congruential
  template<class CharT>
  friend basic_ostream<CharT>&
  operator<<(basic_ostream<CharT>& os,
             const linear_congruential& lcg)
    return os << 1;
void instantiate_all()
  linear_congruential<0> lcf;
  cout << lcf;


Here is the back trace:
#0  0x002723cc in block_alloc (b=0) at /Users/pinskia/src/local3/gcc/gcc/local-alloc.c:1629
#1  0x002720b8 in block_alloc (b=0) at /Users/pinskia/src/local3/gcc/gcc/local-alloc.c:1598
#2  0x002731a4 in local_alloc () at /Users/pinskia/src/local3/gcc/gcc/local-alloc.c:420
#3  0x0030bdb0 in rest_of_compilation () at /Users/pinskia/src/local3/gcc/gcc/passes.c:492
#4  0x000d3a54 in execute_pass_list (pass=0x40574eb8) at /Users/pinskia/src/local3/gcc/gcc/tree-
#5  0x000d3d48 in tree_rest_of_compilation (fndecl=0x4160146c) at /Users/pinskia/src/local3/gcc/
#6  0x0007e984 in expand_body (fn=0x4160146c) at /Users/pinskia/src/local3/gcc/gcc/cp/
#7  0x00331244 in cgraph_expand_function (node=0x424bdc80) at /Users/pinskia/src/local3/gcc/
#8  0x00331e34 in cgraph_optimize () at /Users/pinskia/src/local3/gcc/gcc/cgraphunit.c:1689
#9  0x00047d50 in cp_finish_file () at /Users/pinskia/src/local3/gcc/gcc/cp/decl2.c:3070
#10 0x000bb42c in c_common_parse_file (set_yydebug=3) at /Users/pinskia/src/local3/gcc/gcc/c-
#11 0x002ec6ec in toplev_main (argc=1112267904, argv=0x0) at /Users/pinskia/src/local3/gcc/gcc/
#12 0x000028e4 in _start (argc=1, argv=0x41600d00, envp=0x424bd880) at /SourceCache/Csu/Csu
#13 0x8fe1a558 in __dyld__dyld_start ()
Comment 3 Andrew Pinski 2004-11-29 01:54:28 UTC
Hmm, adding either -da, -fdump-tree-all, or -fdump-rtl-all, works.
Comment 4 Andrew Pinski 2004-11-29 02:03:49 UTC
We are seg faulting at:
1629              reg_renumber[i] = qty[q].phys_reg + reg_offset[i];

reg_renumber is null at this point.
Comment 5 Andrew Pinski 2004-12-12 03:18:36 UTC
Note without this fixed, I cannot help fix 12850 as I have to compile at -O1.
Comment 6 roger 2004-12-19 23:51:34 UTC
This is perhaps the most bizarre interaction I've yet come across in GCC.  Under
normal operation, reg_renumber is zero prior to register allocation, then in
rest_of_handle_old_regalloc, allocate_reg_info is called to allocate per-pseudo
information, which is used two or three function calls later by local_alloc (and
should remain valid for the remainder of the function's compilation).

Unfortunately, between allocate_reg_info and local_alloc we call "regclass"
which in this test case, unintentionally resets reg_renumber to zero!

The incomplete and abridged call stack is

reg_class -> scan_one_insn -> extract_insn -> recog_23 ->
current_file_function_operand -> make_decl_rtl -> decl_assembler_name ->
mangle_decl -> write_mangled_name -> write_encoding ->
get_mostly_instantiated_function_type -> pop_access_scope -> pop_from_top_level
 -> pop_context_function_from.

In the middle of pop_context_function_from is the line "reg_renumber = 0"!

This problem is either a (i) middle-end issue, (ii) an rs6000 backend issue, or
(iii) a C++ front-end issue.

(i) I don't think that pop_context_function_from should (or needs to) reset
reg_renumber to zero.  I would hope that with cgraph, there is only ever a
single function being expanded to RTL at a time, so reg_renumber can be left
as is.  Certainly, if we're not saving the value of reg_renumber (and the arrays
contents) in push_function_context_to, then we shouldn't attempt to restore it
afterwards.  I'm currently testing this fix.

(ii) This interaction can also be avoided if the rs6000's function
current_file_function_operand used DECL_RTL_SET_P to test whether an identifier
is local to a function prior to checking the result of DECL_RTL.  This avoids
the invocation of make_decl_rtl.  Presumably, if we don't know the assembler
name for this function, we can't be calling it :)  [I'll test this fix next].

(iii) The problem might well be in the C++ front-end and its interaction with
cgraph.  It's unclear whether DECL_RTL should already have been set on
current_function_decl prior to this point in rest_of_compilation.  Clearly,
this only appears to happen for C++ templates, so the rs6000 backend is perhaps
 reasonable in assuming DECL_RTL has been set by this point.

The above analysis also explains why enabling various tree dumps resolves the
segmentation fault, as we end up calling/caching decl_assembler_name for the
current function before reaching local register allocation (avoiding this
particular interaction).

This is probably fall-out from the recent cgraph/varasm reorganizations that
attempt to avoid calling decl_assembler_name until as late as physically
possible.  Calling it for the first time before or after local alloc probably
works fine, calling it during (as is done on rs6000 targets) has unanticipated
Comment 7 CVS Commits 2004-12-21 01:37:40 UTC
Subject: Bug 18683

CVSROOT:	/cvs/gcc
Module name:	gcc
Changes by:	sayle@gcc.gnu.org	2004-12-21 01:37:35

Modified files:
	gcc            : ChangeLog function.c 
	gcc/testsuite  : ChangeLog 
Added files:
	gcc/testsuite/g++.dg/opt: pr18683-1.C 

Log message:
	PR middle-end/18683
	* function.c (pop_function_context_from): Don't reset reg_renumber.
	* g++.dg/opt/pr18683-1.C: New test case.


Comment 8 CVS Commits 2004-12-21 03:18:59 UTC
Subject: Bug 18683

CVSROOT:	/cvs/gcc
Module name:	gcc
Changes by:	sayle@gcc.gnu.org	2004-12-21 03:18:51

Modified files:
	gcc            : ChangeLog 
	gcc/config/rs6000: rs6000.c 

Log message:
	PR middle-end/18683
	* config/rs6000/rs6000.c (current_file_function_operand): Only check
	current_function_decl's DECL_RTL if it has already been set.


Comment 9 Andrew Pinski 2004-12-21 03:33:03 UTC
Fixed, thanks Roger.