gcc in RC2 miscompiles ia64 0814 toolchain under ia32 with -O2 -fPIC. assign_file_positions_for_segments () in bfd/elf.c from ia64 0814 toolchain is miscompiled. Around line 2875: if (p->p_type == PT_LOAD) { bfd_signed_vma adjust; if ((flags & SEC_LOAD) != 0) { adjust = sec->lma - (p->p_paddr + p->p_memsz); if (adjust < 0) adjust = 0; } else if ((flags & SEC_ALLOC) != 0) { /* The section VMA must equal the file position modulo the page size. FIXME: I'm not sure if this adjustment is really necessary. We used to not have the SEC_LOAD case just above, and then this was necessary, but now I'm not sure. */ if ((abfd->flags & D_PAGED) != 0) adjust = (sec->vma - voff) % bed->maxpagesize; else adjust = (sec->vma - voff) % align; } else adjust = 0; if (adjust != 0) { if (i == 0) { (* _bfd_error_handler) (_("Error: First section in segment (%s) starts at 0x%x"), bfd_section_name (abfd, sec), sec->lma); (* _bfd_error_handler) (_(" whereas segment starts at 0x%x"), p->p_paddr); return false; } The line: adjust = sec->lma - (p->p_paddr + p->p_memsz); should set adjust to 0 if sec->lma == (p->p_paddr + p->p_memsz). However, with -O2 -fPIC, it is set to sec->lma. As the result, I got lt-ld-new: Error: First section in segment (.interp) starts at 0x1c8 lt-ld-new: whereas segment starts at 0x0 Compile with -O -fPIC or -O2 generates the corrent code. I couldn't find the smaller testcase. H.J.
Please see testcase at http://gcc.gnu.org/ml/gcc-bugs/2000-08/msg00526.html H.J.
Known bug: 32->64 bit cross compilers are broken in the current gcc.
Please see my testcase. It has very little to do with cross compiler. It is long long what is broken with -O2 -fPIC. H.J.
H.J. is right, this is serious problem in reload. I have spent some time on it yesterday, but haven't figured out where the bug is yet. BTW: The testcase can be trimmed down a little bit and -fpic is only interesting to it because it makes %ebx a fixed register, thus increasing register pressure.
I spent an hour to get that testcase. It has only 79 lines -).
I don't think this is a reload problem. I tracked it down to try_split (). Given an RTL (insn 83 291 254 (parallel[ (set (reg:DI 0 eax) (plus:DI (reg:DI 0 eax) (mem/s:DI (plus:SI (reg:SI 2 ecx) (const_int 20 [0x14])) 10))) (clobber (reg:CC 17 flags)) ] ) 108 {adddi3} (nil) (nil)) to (sequence[ (insn 292 0 293 (parallel[ (set (reg:CC 17 flags) (plus:CC (reg:SI 0 eax) (mem/s:SI (plus:SI (reg:SI 2 ecx) (const_int 20 [0x14])) 10))) (set (reg:SI 0 eax) (plus:SI (reg:SI 0 eax) (mem/s:SI (plus:SI (reg:SI 2 ecx) (const_int 20 [0x14])) 10))) ] ) -1 (nil) (nil)) (insn 293 292 0 (parallel[ (set (reg:SI 1 edx) (plus:SI (reg:SI 1 edx) (plus:SI (mem/s:SI (plus:SI (reg:SI 2 ecx) (const_int 24 [0x18])) 10) (ltu:SI (reg:CC 17 flags) (const_int 0 [0x0]))))) (clobber (reg:CC 17 flags)) ] ) -1 (nil) (nil)) ] ) The problem is edx is used in (insn 294 257 295 (set (reg:SI 1 edx) (mem/s:SI (reg:SI 4 esi) 10)) -1 (nil) (nil)) a few instructiions down. As the result, the second part of the sequence gets deleted later since edx is dead. H.J.
You are right. It is a reload bug. I don't think reload knows (reg/v:DI 1 edx) == (reg:DI 0 eax)) It turns (insn 86 257 87 (parallel[ (set (reg/v:DI 1 edx) (minus:DI (mem/s:DI (reg/v:SI 43) 10) (reg:DI 0 eax))) (clobber (reg:CC 17 flags)) ] ) 129 {subdi3} (insn_list 83 (nil)) (expr_list:REG_UNUSED (reg:CC 17 flags) (expr_list:REG_DEAD (reg:DI 0 eax) (nil)))) into (insn 257 85 260 (set (reg:SI 4 esi) (reg/v:SI 43)) -1 (nil) (nil)) (insn 260 257 86 (set (reg/v:DI 1 edx) (mem/s:DI (reg/v:SI 43) 10)) -1 (nil) (nil)) (insn 86 260 87 (parallel[ (set (reg/v:DI 1 edx) (minus:DI (mem/s:DI (reg/v:SI 43) 10) (reg:DI 0 eax))) (clobber (reg:CC 17 flags)) ] ) 129 {subdi3} (insn_list 83 (nil)) (expr_list:REG_UNUSED (reg:CC 17 flags) (expr_list:REG_DEAD (reg:DI 0 eax) (nil)))) From then on, everything goes downhill. I will take another look tomorror.
Created attachment 3122 [details] We should exclude edx for DImode.
Jakub, what do you think my patch? The problem is we cannot allocate edx for DImode since eax/edx is a fixed pair for DImode. When we allocate eax for DImode, we have implicitly allocated edx together with eax for DImode. I don't know how to express it. That is what I came up with. There must be a better fix.
Created attachment 3158 [details] A patch for find_reg ()
Jakub, what do you think my new patch? The problem is global_conflicts () is called before find_reg (). It misses the hard register conflicts introduced by find_reg (). I don't know if my patch is correct or not.
Created attachment 3178 [details] An updated patch for find_reg ().
I updated my patch. I changed if (reg && r >= 0 && r != regno && TEST_HARD_REG_BIT (used, r)) to if (reg && r >= 0 && r < regno && TEST_HARD_REG_BIT (used, r)) since a hard register r >= regno won't overlap with regno.