This is the mail archive of the
gcc-prs@gcc.gnu.org
mailing list for the GCC project.
Re: optimization/7690: gcc 2.95.3: argument destroyed under -O2 on IA32
- From: Chris Torek <torek at elf dot eng dot bsdi dot com>
- To: nobody at gcc dot gnu dot org
- Cc: gcc-prs at gcc dot gnu dot org,
- Date: 22 Aug 2002 23:56:00 -0000
- Subject: Re: optimization/7690: gcc 2.95.3: argument destroyed under -O2 on IA32
- Reply-to: Chris Torek <torek at elf dot eng dot bsdi dot com>
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