adam@UUNET.UU.NET (Adam R de Boor) (11/13/88)
the bug is even more widespread. The frame_info function in gdb fails for the same reason, and it's not even inside a loop. fp@(0,d2:l*1),sp@- ick. a
adam@UUNET.UU.NET (Adam R de Boor) (11/16/88)
Sorry, the letter was a follow-up to two previous letters that
detailed a bug in the reloading phase of the compiler, where it places
the address of the structure into which the function should return its
value in a volatile register (d0) and then uses fp@(0,d0:l*4) to
address the first field of the structure after the call, which is
wrong in two respects (d0 was the address, and it's marked as being
trashed on calls). To re-iterate (get it all in one place), the
program:
struct ick { int a, b, c; };
extern struct ick foop();
main()
{
struct ick beep;
while(1) {
beep = foop();
if (beep.a == 0) {
break;
}
}
}
causes gcc to generate bad code. The bad code isn't generated if the
call to foop() isn't in a loop (I guess it doesn't feel the need to
keep the address of beep around if the call isn't in a loop). Even if
you have a register variable that contains the address of the
structure, you will still get bad code if you refer to the first field
of the structure directly, nor is the pre-loaded register used in the
call to foop -- it still calculates the address in d0 and moves it
into a1 before the call.
The involved rtl code is transformed from
;; Function main
57 registers.
Register 56 used 2 times across 0 insns.
0 basic blocks.
;; Register 56 in 0.
(note 1 0 2 "" -1)
(note 2 1 3 "" -2)
(note 3 2 4 "" -4)
(code_label 4 3 5 2)
(note 5 4 6 "" -1)
(insn 6 5 7 (set (reg:SI 56)
(plus:SI (reg:SI 14)
(const_int -12))) 81 (nil)
(nil))
(insn 7 6 8 (set (reg:SI 9)
(reg:SI 56)) 33 (nil)
(nil))
(insn 8 7 9 (use (reg:SI 9)) -1 (nil)
(nil))
(call_insn 9 8 10 (call (mem:QI (symbol_ref:SI ("foop")))
(const_int 0)) 246 (nil)
(nil))
(insn 10 9 11 (set (cc0)
(mem/s:SI (plus:SI (reg:SI 14)
(const_int -12)))) 2 (nil)
(nil))
(jump_insn 11 10 12 (set (pc)
(if_then_else (eq (cc0)
(const_int 0))
(pc)
(label_ref 15))) 228 (nil)
(nil))
(note 12 11 13 "" -1)
(jump_insn 13 12 14 (set (pc)
(label_ref 19)) 242 (nil)
(nil))
(barrier 14 13 15)
(code_label 15 14 16 4)
(jump_insn 16 15 17 (set (pc)
(label_ref 4)) 242 (nil)
(nil))
(barrier 17 16 18)
(note 18 17 19 "" -5)
(code_label 19 18 20 3)
(note 20 19 21 "" -3)
(note 21 20 22 "" -6)
(code_label 22 21 0 1)
as the output of stupid register allocation (reg 56 has already been
assigned to d0) into
;; Function main
;; Register dispositions: 56 in 0
;; Hard regs used: 0 9 14
(note 1 0 2 ("q.c") 4)
(note 2 1 3 "" -1)
(note 3 2 4 "" -2)
(note 4 3 5 ("q.c") 6)
(note 5 4 6 "" -4)
(code_label 6 5 7 2)
(note 7 6 8 "" -1)
(note 8 7 29 ("q.c") 7)
(insn 29 8 9 (set (reg:SI 0) ; this sequence is weird
(const_int -12)) -1 (nil)
(nil))
(insn:QI 9 29 10 (set (reg:SI 0)
(plus:SI (reg:SI 0)
(reg:SI 14))) 81 (nil)
(nil))
(insn 10 9 11 (set (reg:SI 9) ; right down to here.
(reg:SI 0)) 33 (nil)
(nil))
(insn 11 10 12 (use (reg:SI 9)) -1 (nil)
(nil))
(call_insn 12 11 13 (call (mem:QI (symbol_ref:SI ("foop")))
(const_int 0)) 246 (nil)
(nil))
(note 13 12 14 ("q.c") 8)
(insn 14 13 15 (set (cc0)
(mem/s:SI (plus:SI (reg:SI 0) ; choke -- ardeb
(reg:SI 14)))) 2 (nil)
(nil))
(jump_insn 15 14 16 (set (pc)
(if_then_else (eq (cc0)
(const_int 0))
(pc)
(label_ref 20))) 228 (nil)
(nil))
(note 16 15 17 "" -1)
(note 17 16 18 ("q.c") 9)
(jump_insn 18 17 19 (set (pc)
(label_ref 24)) 242 (nil)
(nil))
(barrier 19 18 20)
(code_label 20 19 21 4)
(jump_insn 21 20 22 (set (pc)
(label_ref 6)) 242 (nil)
(nil))
(barrier 22 21 23)
(note 23 22 24 "" -5)
(code_label 24 23 25 3)
(note 25 24 26 "" -3)
(note 26 25 27 "" -6)
(note 27 26 28 ("q.c") 12)
(code_label 28 27 0 1)
Another question I have is why those three rtl expressions are
generated in the first place? A better expression would be
(set (reg:SI 9) (plus:SI (reg:SI 14) (const_int -12)))
this could be transformed into a simple
lea fp@(-12),a1
rather than
moveq #-12,d0
addl fp,d0
movl d0,a1
which has to take more time (same number of bytes, but...)
So, it's not a bug in gdb, but I found the bad code first the
find_saved_register function in gdb, and later in frame_info.
a