regression for 3.1: bad sign extension?

Geoff Keating geoffk@geoffk.org
Thu Mar 14 18:16:00 GMT 2002


> Date: Thu, 14 Mar 2002 17:11:44 -0800
> From: Bob Wilson <bwilson@tensilica.com>
> Organization: Tensilica, Inc.
> User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.9) Gecko/20020310
> X-Accept-Language: en-us, en
> CC: Geoff Keating <geoffk@geoffk.org>
> X-OriginalArrivalTime: 15 Mar 2002 01:11:45.0383 (UTC) FILETIME=[5FC18F70:01C1CBBE]
> 
> I think I need some help to figure out where this is going wrong.  Here 
> is what happens:
> 
> * The constant integer 0x8000 is used in an unsigned HImode comparison. 
>   As described in my previous message, in the 3.1 branch the constant is 
>   sign-extended when constructing the CONST_INT.
> 
> * The prepare_cmp_insn() function calls force_reg(), when 
> preserve_subexpressions_p() is true, to put the CONST_INT into a 
> register.  The sign-extended constant 0xffff8000 is put into the 
> constant pool as an SImode value (because Xtensa only supports SImode 
> constant pool values) and loaded into a register.  The register is then 
> zero-extended before being used in the comparison.  The RTL is:
> 
> (insn 56 53 57 (set (subreg:SI (reg:HI 54) 0)
>          (mem/u/f:SI (symbol_ref/u:SI ("*.LC0")) [6 S4 A32])) -1 (nil)
>      (nil))
> 
> (insn 57 56 58 (set (reg:SI 55)
>          (zero_extend:SI (reg:HI 53))) -1 (nil)
>      (nil))
> 
> (insn 58 57 59 (set (reg:SI 56)
>          (zero_extend:SI (reg:HI 54))) -1 (nil)
>      (nil))
> 
> (jump_insn 59 58 62 (set (pc)
>          (if_then_else (ne (reg:SI 55)
>                  (reg:SI 56))
>              (label_ref 65)
>              (pc))) -1 (nil)
>      (nil))
> 
> AFAIK, this is correct so far.  Note that when 
> preserve_subexpressions_p() is false, the zero-extend is folded into the 
> value put into the constant pool and there is no explicit zero-extend 
> for the constant.
> 
> * The combiner removes insn 58 and replaces the use of reg 56 with 
> "(subreg:SI (reg:HI 54) 0))".  The zero-extend is thus removed and value 
> used in the comparison is 0xffff8000, which is wrong.  I traced through 
> the combiner code that removes the zero-extend.  Here is a stack trace 
> showing where it happens:
> 
> #0  expand_compound_operation (x=0x401605f8) at ../../cvs/gcc/combine.c:5551
> #1  0x8187ef0 in combine_simplify_rtx (x=0x401605f8, op0_mode=HImode, 
> last=0,
>      in_dest=0) at ../../cvs/gcc/combine.c:4507
> #2  0x8186a7d in subst (x=0x401605f8, from=0x40016000, to=0x40016000,
>      in_dest=0, unique_copy=0) at ../../cvs/gcc/combine.c:3566
> #3  0x8184090 in try_combine (i3=0x40159bc0, i2=0x4015c540, i1=0x0,
>      new_direct_jump_p=0xbffff3fc) at ../../cvs/gcc/combine.c:1894
> 
> The comment in try_combine here is:
> 
> /* It is possible that the source of I2 or I1 may be performing an 
> unneeded operation, such as a ZERO_EXTEND of something that is known to 
> have the high part zero.  Handle that case by letting subst look at the 
> innermost one of them....
> */
> 
> Roughly the expand_compound_operation first generates an ASHIFT by 16 
> and then an LSHIFTRT by 16 and simplify_shift_const reduces the whole 
> thing down to "(subreg:SI (reg:HI 54) 0))".  I'm not sure if this is 
> correct or not.  It certainly doesn't fit the description in the comment 
> of "something that is known to have the high parts zero".

Yes, this is certainly incorrect.  '(set (subreg:SI (reg:HI 54) 0)'
implies 'clobber the high 16 bits of reg 54', and we don't want to
clobber them, we want to set them to 0.  [This assumes your words are
>= 32 bits wide.]  It would be worthwhile checking that
expand_compound_operation is doing the shifts in SImode not HImode.

> There are really two issues here:
> 
> 1) If the value in the constant pool is sign extended, then an explicit 
> zero-extend is required somewhere.  It's currently being removed.
> 
> 2) Using an explicit zero-extend here is poor code generation.  From my 
> point of view, it would be easier to avoid the sign-extension in the 
> first place.  Geoff's previous comment suggests that is not the right 
> thing.  Perhaps I should change the combiner to detect a zero-extend of 
> a value loaded from the constant pool and combine those two ops by 
> putting a new zero-extended value in the pool.  Would that be a good 
> solution?  Any better ideas?

Yes, the right thing is to have the equivalent of:

(set (reg:SI 56) (const_int 0x00008000))

if that's cheaper than the original code.

-- 
- Geoffrey Keating <geoffk@geoffk.org> <geoffk@redhat.com>



More information about the Gcc mailing list