This is the mail archive of the gcc-patches@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: Automatic MMX/x87 FPU mode switching


Quoting Richard Henderson <rth@redhat.com>:

> Both of these patterns need to use the registers of the opposite unit.
> Otherwise the registers won't be live; you'll instead get REG_UNUSED
> markers on the insn.  So:
> 
>    [(set (reg:ALLREGS FIRSTFP_REG)
> 	 (unspec_volatile:ALLREGS [(reg:ALLREGS FIRSTMMX_REG)]
> 				  UNSPECV_EFPU))]
> 
> You're also missing a change to EPILOGUE_USES to force the registers
> of the unit *not* active at the end of the function to be live.
> 
> Both of these are required in order to prevent the register allocator
> from allocating registers from the unit that is not active.

  I was experimenting a bit with changed patterns and EPILOGUE_USES. However,
there are problems when CALL_INSN is emitted between efpu and emms patterns.
This can be shown with following testcase:

--cut here--
#include <mmintrin.h>

extern __v8qi
aaa (__v8qi x, __v8qi y);

int test(int x)
{
  __v8qi mm0 = { 1,2,3,4,5,6,7,8 };
  __v8qi mm1 = { 11,12,13,14,15,16,17,18 };

  union ttt {
    __v8qi mm;
    char x[8];
  } temp;

  temp.mm = aaa (mm0, mm1);

  return temp.x[0];
}
--cut here--

The RTL sequence produced by 'gcc -O2 -mmmx' shows that CALL_INSN somehow kills
live registers:

;; Start of basic block 0, registers live: 6 [bp] 7 [sp] 20 [frame] 29 [mm0] 30
[mm1] 31 [mm2] 32 [mm3] 33 [mm4] 34 [mm5] 35 [mm6] 36 [mm7]
(note:HI 10 7 46 0 [bb 0] NOTE_INSN_BASIC_BLOCK)

...

(note 49 48 40 0 NOTE_INSN_PROLOGUE_END)

(insn 40 49 12 0 (set (reg:ALLREGS 8 st)
        (unspec_volatile:ALLREGS [
                (reg:ALLREGS 29 mm0)
            ] 2)) 871 {efpu} (nil)
    (expr_list:REG_DEAD (reg:ALLREGS 29 mm0)
        (expr_list:REG_UNUSED (reg:ALLREGS 8 st)    <<<<<<< here
            (nil))))

... (MMX stuff here) ...

(call_insn:HI 14 13 15 0 (set (reg:V8QI 29 mm0)
        (call (mem:QI (symbol_ref:SI ("aaa") [flags 0x41] <function_decl
0x4030bd80 aaa>) [0 S1 A8])
            (const_int 0 [0x0]))) 526 {*call_value_0} (insn_list:REG_DEP_TRUE 12
(insn_list:REG_DEP_TRUE 13 (nil)))
    (expr_list:REG_DEAD (reg:V8QI 30 mm1)
        (nil))
    (expr_list:REG_DEP_TRUE (use (reg:V8QI 29 mm0))
        (expr_list:REG_DEP_TRUE (use (reg:V8QI 30 mm1))
            (nil))))

... (some more MMX stuff) ...

(note:HI 21 17 39 0 NOTE_INSN_FUNCTION_END)

(insn 39 21 36 0 (set (reg:ALLREGS 29 mm0)
        (unspec_volatile:ALLREGS [
                (reg:ALLREGS 8 st)
            ] 5)) 872 {emms} (nil)
    (expr_list:REG_DEAD (reg:ALLREGS 8 st)
        (nil)))

... (other stuff) ...

;; End of basic block 0, registers live:
 0 [ax] 6 [bp] 7 [sp] 20 [frame] 29 [mm0] 30 [mm1] 31 [mm2] 32 [mm3] 33 [mm4] 34
[mm5] 35 [mm6] 36 [mm7]


Please note (expr_list:REG_UNUSED (reg:ALLREGS 8 st) in efpu pattern. If
call instructions are placed in various basic blocks, reg-stack.c compensations
start to insert various fstp/flds instructions (in case that reg-stack.c doesn't
ICE right away...).

It looks that we have to invent some other way to tell reg allocator, which
register set is active. Perhaps we could introduce a machine_function variable,
that is initialized depending on function start FPU mode and changed dynamically
by emms and efpu patterns? Can this variable then be then used in
CONDITIONAL_REGISTER_USAGE to switch between MMX and x87 sets?

Uros.


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