[gnu.gcc.bug] more on structure passing

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