This is the mail archive of the gcc-prs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: optimization/7690: gcc 2.95.3: argument destroyed under -O2 on IA32


The following reply was made to PR optimization/7690; it has been noted by GNATS.

From: Chris Torek <torek@elf.eng.bsdi.com>
To: gcc-gnats@gcc.gnu.org, torek@bsdi.com
Cc:  
Subject: Re: optimization/7690: gcc 2.95.3: argument destroyed under -O2 on IA32
Date: Thu, 22 Aug 2002 17:54:31 -0600 (MDT)

 Various addenda/notes... (does mailing a reply even work?)
 
 By brutally whacking on the source code, I discovered that the
 culprit can be stopped in regmove.c.  Forcing that to pretend that
 -fexpensive-optimizations is off generates correct assembly.  I do
 not know whether the ultimate problem is in this file or elsewhere,
 however.  (So, let's take a look at the RTL...)
 
 With "#define flag_expensive_optimizations 0" and -dN, the
 regmove dump file reads:
 
 	;; Function bug
 
 	(note 2 0 70 "" NOTE_INSN_DELETED)
 
 	;; Start of basic block 0, registers live: 6 [bp] 7 [sp] 16 []
 	(note 70 2 4 [bb 0] NOTE_INSN_BASIC_BLOCK)
 
 	(insn 4 70 6 (set (reg/v:SI 22)
 		(mem/f:SI (reg:SI 16 %argp) 0)) 48 {movsi+2} (nil)
 	    (expr_list:REG_EQUIV (mem/f:SI (reg:SI 16 %argp) 0)
 		(nil)))
 
 	(insn 6 4 8 (set (reg/v:SI 23)
 		(mem/f:SI (plus:SI (reg:SI 16 %argp)
 			(const_int 4 [0x4])) 0)) 48 {movsi+2} (nil)
 	    (expr_list:REG_EQUIV (mem/f:SI (plus:SI (reg:SI 16 %argp)
 			(const_int 4 [0x4])) 0)
 		(nil)))
 
 	(note 8 6 10 "" NOTE_INSN_DELETED)
 
 	(note 10 8 30 "" NOTE_INSN_DELETED)
 
 	(insn 30 10 11 (set (reg/v:SI 27)
 		(mem/f:SI (plus:SI (reg:SI 16 %argp)
 			(const_int 12 [0xc])) 0)) 48 {movsi+2} (nil)
 	    (nil))
 
 	(note 11 30 12 "" NOTE_INSN_FUNCTION_BEG)
 
 	(note 12 11 14 "" NOTE_INSN_DELETED)
 
 	(note 14 12 17 0 NOTE_INSN_BLOCK_BEG)
 
 	(insn 17 14 19 (set (reg:SI 7 %esp)
 		(plus:SI (reg:SI 7 %esp)
 		    (const_int -4 [0xfffffffc]))) 205 {addsi3+1} (nil)
 	    (nil))
 
 	(insn 19 17 21 (set (mem:SI (pre_dec:SI (reg:SI 7 %esp)) 0)
 		(mem/f:SI (plus:SI (reg:SI 16 %argp)
 			(const_int 8 [0x8])) 0)) 45 {movsi-1} (nil)
 	    (nil))
 
 	(insn 21 19 23 (set (mem:SI (pre_dec:SI (reg:SI 7 %esp)) 0)
 		(reg/v:SI 23)) 44 {movsi-2} (insn_list 6 (nil))
 	    (nil))
 
 	(insn 23 21 25 (set (mem:SI (pre_dec:SI (reg:SI 7 %esp)) 0)
 		(reg/v:SI 22)) 44 {movsi-2} (insn_list 4 (nil))
 	    (nil))
 
 	(call_insn 25 23 27 (set (reg:DI 0 %eax)
 		(call (mem:QI (symbol_ref:SI ("f1")) 0)
 		    (const_int 16 [0x10]))) -1 (nil)
 	    (nil)
 	    (nil))
 
 	(insn 27 25 33 (set (reg/v:DI 26)
 		(reg:DI 0 %eax)) 79 {movdi+1} (insn_list 25 (nil))
 	    (expr_list:REG_DEAD (reg:DI 0 %eax)
 		(nil)))
 
 	(insn 33 27 35 (set (reg:SI 29)
 		(subreg:SI (reg/v:DI 26) 0)) 48 {movsi+2} (insn_list 27 (nil))
 	    (nil))
 
 	(note 35 33 36 "" NOTE_INSN_DELETED)
 
 	(insn 36 35 41 (set (mem/f:SI (plus:SI (reg/v:SI 22)
 			(reg:SI 29)) 0)
 		(reg/v:SI 27)) 48 {movsi+2} (insn_list 30 (insn_list 33 (nil)))
 	    (expr_list:REG_DEAD (reg/v:SI 27)
 		(expr_list:REG_DEAD (reg:SI 29)
 		    (expr_list:REG_DEAD (reg/v:SI 22)
 			(nil)))))
 
 	(insn 41 36 43 (set (reg:SI 7 %esp)
 		(plus:SI (reg:SI 7 %esp)
 		    (const_int -12 [0xfffffff4]))) 205 {addsi3+1} (nil)
 	    (nil))
 
 	(insn 43 41 44 (set (reg:SI 32)
 		(const_int 0 [0x0])) 48 {movsi+2} (nil)
 	    (expr_list:REG_EQUAL (const_int 0 [0x0])
 		(nil)))
 
 	(insn 44 43 46 (set (reg:DI 33)
 		(zero_extend:DI (reg/v:SI 23))) 98 {zero_extendsidi2} (nil)
 	    (expr_list:REG_DEAD (reg/v:SI 23)
 		(nil)))
 
 	(insn 46 44 47 (set (reg:SI 7 %esp)
 		(plus:SI (reg:SI 7 %esp)
 		    (const_int 16 [0x10]))) 205 {addsi3+1} (nil)
 	    (nil))
 
 	(insn:QI 47 46 48 (set (cc0)
 		(compare (subreg:SI (reg/v:DI 26) 1)
 		    (subreg:SI (reg:DI 33) 1))) 12 {cmpsi_1} (insn_list 44 (nil))
 	    (nil))
 
 	(jump_insn 48 47 71 (set (pc)
 		(if_then_else (gtu (cc0)
 			(const_int 0 [0x0]))
 		    (label_ref 60)
 		    (pc))) 349 {bleu+1} (nil)
 	    (nil))
 	;; End of basic block 0
 
 	;; Start of basic block 1, registers live: 6 [bp] 7 [sp] 26 32 33
 	(note 71 48 49 [bb 1] NOTE_INSN_BASIC_BLOCK)
 
 	(insn:QI 49 71 50 (set (cc0)
 		(compare (subreg:SI (reg/v:DI 26) 1)
 		    (subreg:SI (reg:DI 33) 1))) 12 {cmpsi_1} (nil)
 	    (nil))
 
 	(jump_insn 50 49 72 (set (pc)
 		(if_then_else (ne (cc0)
 			(const_int 0 [0x0]))
 		    (label_ref 57)
 		    (pc))) 349 {bleu+1} (nil)
 	    (nil))
 	;; End of basic block 1
 
 	;; Start of basic block 2, registers live: 6 [bp] 7 [sp] 26 32 33
 	(note 72 50 51 [bb 2] NOTE_INSN_BASIC_BLOCK)
 
 	(insn:QI 51 72 52 (set (cc0)
 		(compare (subreg:SI (reg/v:DI 26) 0)
 		    (subreg:SI (reg:DI 33) 0))) 12 {cmpsi_1} (nil)
 	    (expr_list:REG_DEAD (reg/v:DI 26)
 		(expr_list:REG_DEAD (reg:DI 33)
 		    (nil))))
 
 	(jump_insn 52 51 57 (set (pc)
 		(if_then_else (gtu (cc0)
 			(const_int 0 [0x0]))
 		    (label_ref 60)
 		    (pc))) 349 {bleu+1} (nil)
 	    (nil))
 	;; End of basic block 2
 
 	;; Start of basic block 3, registers live: 6 [bp] 7 [sp]
 	(code_label 57 52 73 4 "" [num uses: 1])
 
 	(note 73 57 59 [bb 3] NOTE_INSN_BASIC_BLOCK)
 
 	(insn 59 73 60 (set (reg:SI 32)
 		(const_int 1 [0x1])) 48 {movsi+2} (nil)
 	    (expr_list:REG_EQUAL (const_int 1 [0x1])
 		(nil)))
 	;; End of basic block 3
 
 	;; Start of basic block 4, registers live: 6 [bp] 7 [sp] 32
 	(code_label 60 59 74 3 "" [num uses: 2])
 
 	(note 74 60 62 [bb 4] NOTE_INSN_BASIC_BLOCK)
 
 	(insn 62 74 64 (set (mem:SI (pre_dec:SI (reg:SI 7 %esp)) 0)
 		(reg:SI 32)) 44 {movsi-2} (nil)
 	    (expr_list:REG_DEAD (reg:SI 32)
 		(nil)))
 
 	(call_insn 64 62 66 (call (mem:QI (symbol_ref:SI ("f2")) 0)
 		(const_int 16 [0x10])) -1 (nil)
 	    (nil)
 	    (nil))
 	;; End of basic block 4
 
 	(note 66 64 0 0 NOTE_INSN_BLOCK_END)
 
 Without this clumsy #define, so that the parameter at 16(%ebp) does
 get clobbered, the regmove dump file reads instead (diffs marked by
 hand):
 
 	;; Function bug
 
 +	Starting forward pass...
 	(note 2 0 70 "" NOTE_INSN_DELETED)
 
 	;; Start of basic block 0, registers live: 6 [bp] 7 [sp] 16 []
 	(note 70 2 4 [bb 0] NOTE_INSN_BASIC_BLOCK)
 
 	(insn 4 70 6 (set (reg/v:SI 22)
 		(mem/f:SI (reg:SI 16 %argp) 0)) 48 {movsi+2} (nil)
 	    (expr_list:REG_EQUIV (mem/f:SI (reg:SI 16 %argp) 0)
 		(nil)))
 
 !	(insn 6 4 8 (set (reg/v:DI 23)
 !		(zero_extend:DI (mem/f:SI (plus:SI (reg:SI 16 %argp)
 !			    (const_int 4 [0x4])) 0))) 98 {zero_extendsidi2} (nil)
 	    (expr_list:REG_EQUIV (mem/f:SI (plus:SI (reg:SI 16 %argp)
 			(const_int 4 [0x4])) 0)
 		(nil)))
 
 	(note 8 6 10 "" NOTE_INSN_DELETED)
 
 	(note 10 8 30 "" NOTE_INSN_DELETED)
 
 	(insn 30 10 11 (set (reg/v:SI 27)
 		(mem/f:SI (plus:SI (reg:SI 16 %argp)
 			(const_int 12 [0xc])) 0)) 48 {movsi+2} (nil)
 	    (nil))
 
 	(note 11 30 12 "" NOTE_INSN_FUNCTION_BEG)
 
 	(note 12 11 14 "" NOTE_INSN_DELETED)
 
 	(note 14 12 17 0 NOTE_INSN_BLOCK_BEG)
 
 	(insn 17 14 19 (set (reg:SI 7 %esp)
 		(plus:SI (reg:SI 7 %esp)
 		    (const_int -4 [0xfffffffc]))) 205 {addsi3+1} (nil)
 	    (nil))
 
 	(insn 19 17 21 (set (mem:SI (pre_dec:SI (reg:SI 7 %esp)) 0)
 		(mem/f:SI (plus:SI (reg:SI 16 %argp)
 			(const_int 8 [0x8])) 0)) 45 {movsi-1} (nil)
 	    (nil))
 
 	(insn 21 19 23 (set (mem:SI (pre_dec:SI (reg:SI 7 %esp)) 0)
 !		(subreg:SI (reg/v:DI 23) 0)) 44 {movsi-2} (insn_list 6 (nil))
 	    (nil))
 
 	(insn 23 21 25 (set (mem:SI (pre_dec:SI (reg:SI 7 %esp)) 0)
 		(reg/v:SI 22)) 44 {movsi-2} (insn_list 4 (nil))
 	    (nil))
 
 	(call_insn 25 23 27 (set (reg:DI 0 %eax)
 		(call (mem:QI (symbol_ref:SI ("f1")) 0)
 		    (const_int 16 [0x10]))) -1 (nil)
 	    (nil)
 	    (nil))
 
 	(insn 27 25 33 (set (reg/v:DI 26)
 		(reg:DI 0 %eax)) 79 {movdi+1} (insn_list 25 (nil))
 	    (expr_list:REG_DEAD (reg:DI 0 %eax)
 		(nil)))
 
 	(insn 33 27 35 (set (reg:SI 29)
 		(subreg:SI (reg/v:DI 26) 0)) 48 {movsi+2} (insn_list 27 (nil))
 	    (nil))
 
 	(note 35 33 36 "" NOTE_INSN_DELETED)
 
 	(insn 36 35 41 (set (mem/f:SI (plus:SI (reg/v:SI 22)
 			(reg:SI 29)) 0)
 		(reg/v:SI 27)) 48 {movsi+2} (insn_list 30 (insn_list 33 (nil)))
 	    (expr_list:REG_DEAD (reg/v:SI 27)
 		(expr_list:REG_DEAD (reg:SI 29)
 		    (expr_list:REG_DEAD (reg/v:SI 22)
 			(nil)))))
 
 	(insn 41 36 43 (set (reg:SI 7 %esp)
 		(plus:SI (reg:SI 7 %esp)
 		    (const_int -12 [0xfffffff4]))) 205 {addsi3+1} (nil)
 	    (nil))
 
 	(insn 43 41 44 (set (reg:SI 32)
 		(const_int 0 [0x0])) 48 {movsi+2} (nil)
 	    (expr_list:REG_EQUAL (const_int 0 [0x0])
 		(nil)))
 
 	(insn 44 43 46 (set (reg:DI 33)
 !		(reg/v:DI 23)) 79 {movdi+1} (nil)
 !	    (expr_list:REG_DEAD (reg/v:DI 23)
 		(nil)))
 
 	(insn 46 44 47 (set (reg:SI 7 %esp)
 		(plus:SI (reg:SI 7 %esp)
 		    (const_int 16 [0x10]))) 205 {addsi3+1} (nil)
 	    (nil))
 
 	(insn:QI 47 46 48 (set (cc0)
 		(compare (subreg:SI (reg/v:DI 26) 1)
 		    (subreg:SI (reg:DI 33) 1))) 12 {cmpsi_1} (insn_list 44 (nil))
 	    (nil))
 
 	(jump_insn 48 47 71 (set (pc)
 		(if_then_else (gtu (cc0)
 			(const_int 0 [0x0]))
 		    (label_ref 60)
 		    (pc))) 349 {bleu+1} (nil)
 	    (nil))
 	;; End of basic block 0
 
 	;; Start of basic block 1, registers live: 6 [bp] 7 [sp] 26 32 33
 	(note 71 48 49 [bb 1] NOTE_INSN_BASIC_BLOCK)
 
 	(insn:QI 49 71 50 (set (cc0)
 		(compare (subreg:SI (reg/v:DI 26) 1)
 		    (subreg:SI (reg:DI 33) 1))) 12 {cmpsi_1} (nil)
 	    (nil))
 
 	(jump_insn 50 49 72 (set (pc)
 		(if_then_else (ne (cc0)
 			(const_int 0 [0x0]))
 		    (label_ref 57)
 		    (pc))) 349 {bleu+1} (nil)
 	    (nil))
 	;; End of basic block 1
 
 	;; Start of basic block 2, registers live: 6 [bp] 7 [sp] 26 32 33
 	(note 72 50 51 [bb 2] NOTE_INSN_BASIC_BLOCK)
 
 	(insn:QI 51 72 52 (set (cc0)
 		(compare (subreg:SI (reg/v:DI 26) 0)
 		    (subreg:SI (reg:DI 33) 0))) 12 {cmpsi_1} (nil)
 	    (expr_list:REG_DEAD (reg/v:DI 26)
 		(expr_list:REG_DEAD (reg:DI 33)
 		    (nil))))
 
 	(jump_insn 52 51 57 (set (pc)
 		(if_then_else (gtu (cc0)
 			(const_int 0 [0x0]))
 		    (label_ref 60)
 		    (pc))) 349 {bleu+1} (nil)
 	    (nil))
 	;; End of basic block 2
 
 	;; Start of basic block 3, registers live: 6 [bp] 7 [sp]
 	(code_label 57 52 73 4 "" [num uses: 1])
 
 	(note 73 57 59 [bb 3] NOTE_INSN_BASIC_BLOCK)
 
 	(insn 59 73 60 (set (reg:SI 32)
 		(const_int 1 [0x1])) 48 {movsi+2} (nil)
 	    (expr_list:REG_EQUAL (const_int 1 [0x1])
 		(nil)))
 	;; End of basic block 3
 
 	;; Start of basic block 4, registers live: 6 [bp] 7 [sp] 32
 	(code_label 60 59 74 3 "" [num uses: 2])
 
 	(note 74 60 62 [bb 4] NOTE_INSN_BASIC_BLOCK)
 
 	(insn 62 74 64 (set (mem:SI (pre_dec:SI (reg:SI 7 %esp)) 0)
 		(reg:SI 32)) 44 {movsi-2} (nil)
 	    (expr_list:REG_DEAD (reg:SI 32)
 		(nil)))
 
 	(call_insn 64 62 66 (call (mem:QI (symbol_ref:SI ("f2")) 0)
 		(const_int 16 [0x10])) -1 (nil)
 	    (nil)
 	    (nil))
 	;; End of basic block 4
 
 	(note 66 64 0 0 NOTE_INSN_BLOCK_END)
 
 The RTL changes at the front actually look OK: we
 just replace reg/v:SI 23 with reg/v:DI 23, making pseudo 23 a
 double-wide and marking its top half as zero-extended.  Of course,
 "reg/v 23" just holds the 2nd parameter to bug() (C name "sz"):
 
     void bug(char *buf, size_t sz, const char *name, unsigned type)
     {
 	off_t off;
 
 	off = f1(buf, sz, name);
 	memcpy(buf + off, &type, sizeof(type));
 	f2(off <= sz);
     }
 
 so the point is presumably to zero-extend "sz" in advance of the
 call f2(off <= sz), to make the compare easier.
 
 This of course requires the change at insn 21, to add a subreg to
 push only the lower 32 bits of "sz" in the call to f1().  The rest
 of the call still looks OK.
 
 The last change at insn 44 looks OK too, we just move a DI instead
 of zero-extending an SI, then mark DI 23 (previously known as SI
 23) dead.  This rather implies the problem is elsewhere (what a
 surprise...).
 
 note to self: dump files that differ:
  flow2
  greg
  jump2
  lreg
  regmove
  stack
 
 another note to self: hard regs
  0 = eax
  1 = edx
  2 = ecx
  3 = ebx
  4 = esi
  5 = edi
  6 = ebp
  7 = esp
 
 Conclusion-jumping, to be verified later: in .greg, we see the code
 that has gone wrong: the widening of parameter "sz" has been
 programmed to occur via %eax+%edx; %eax is loaded, %edx is cleared;
 then reg:DI %eax is STORED BACK INTO MEMORY because we ASSUME that
 there is nothing after "sz" to be preserved, when in fact there is
 still the un-preserved value of "name" up there.  (So the problem
 is that C-code-variable registers should not be widened, ever, lest
 they be pushed back into memory?  Prohibiting that in regmove.c
 might solve the problem...)
 
 Chris


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]