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