This is the mail archive of the gcc@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]

issues trying to add ColdFire v4e FPU support to gcc-20020107



I'm in the midst of adding FPU support to gcc-20020107 by lifting my
code form gcc-2.95.3, and I've runin to a problem...

Given the following code:

typedef double ftype;

ftype x(ftype *p, int y)
{
  return p[y];
}

The following code is generated by gcc-20020107 for -O -m68881:

x:
	link.w %a6,#0
	move.l 12(%a6),%d0
	lsl.l #3,%d0
	move.l 8(%a6),%a0
	fmove.d (%a0,%d0.l),%fp0
	unlk %a6
	rts

The .c.00.rtl dump for the insn 'fmove.d (%a0,%d0.l),%fp0' looks like:

(insn 18 16 20 (set (reg:DF 35)
        (mem:DF (plus:SI (reg:SI 33)
                (reg:SI 34)) [0 S8 A16])) -1 (nil)
    (nil))


My problem is that the ColdFire FPU doesn't support the 'address
register indirect with index' addressing mode.  I've mofidifued the
movdf pattern to look like:

(define_expand "movdf"
  [(set (match_operand:DF 0 "nonimmediate_operand" "")
	(match_operand:DF 1 "general_operand" ""))]
  ""
  "
{
  if (TARGET_CFV4E) {
    /* The ColdFire FPU can't deal with absolute addresses or double
     * constants, so push it to memory */
    if (CONSTANT_P (operands[1])) {
      operands[1] = force_const_mem(DFmode, operands[1]);
      if (! memory_address_p (DFmode, XEXP (operands[1], 0))
	  && ! reload_in_progress)
	operands[1] = change_address (operands[1], DFmode,
				      XEXP (operands[1], 0));
    }
    if (symbolic_operand(operands[0], SImode))
      operands[0] = force_reg(SImode, XEXP (operands[0], 0));
    if (symbolic_operand(operands[1], SImode))
      operands[1] = force_reg(SImode, XEXP (operands[1], 0));
  }
}")

and added the pattern:

(define_insn "movdf_v4e"
  [(set (match_operand:DF 0 "general_operand" "=f,<Q>U,r,f")
	(match_operand:DF 1 "general_operand" "f<Q>U,f,f,r"))]
  "TARGET_CFV4E"
  "*
{
  if (which_alternative == 2)
    return \"subq%.l %#8,%%sp\;fmove%.d %1,%@\;move%.l %+,%0\;move%.l %+,%R0\";
  if (which_alternative == 3)
    return \"move%.l %R1,%-\;move%.l %1,%-\;f%&move%.d %@,%0\;addq%.l #8,%%sp\";
  return \"fmove%.d %1,%0\";
}")

Where the constaint 'Q' is register indirect, and 'U' is register
indirect with offset, so I'd expect RTL that doesn't use (REG+REG).

But the dump with -mcfv4e turned on(and I've checked that TARGET_CFV4E
is true) *still* generats .c.00.rtl that has REG+REG addressing mode.

I then modified GO_IF_LEGITIMATE_ADDRESS to be:

/* If Coldfire and float, only accept addressing modes 2-5 */
#define GO_IF_CFV4E_LEGITIMATE_ADDRESS(MODE, X, ADDR)			\
{ if (LEGITIMATE_BASE_REG_P(X)						\
      || ((GET_CODE (X) == PRE_DEC || GET_CODE (X) == POST_INC)		\
          && LEGITIMATE_BASE_REG_P (XEXP (X, 0)))			\
      || ((GET_CODE (X) == PLUS) && LEGITIMATE_BASE_REG_P (XEXP (X, 0))	\
          && (GET_CODE (XEXP (X, 1)) == CONST_INT)			\
          && ((((unsigned) INTVAL (XEXP (X, 1)) + 0x8000) < 0x100000)))) \
  goto ADDR;}         

/* If pic, we accept INDEX+LABEL, which is what do_tablejump makes.  */
#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR)				\
{ if (TARGET_CFV4E && (GET_MODE_CLASS (MODE) == MODE_FLOAT))		\
 { GO_IF_CFV4E_LEGITIMATE_ADDRESS(MODE, X, ADDR);			\
 } else {								\
  GO_IF_NONINDEXED_ADDRESS (X, ADDR);					\
  GO_IF_INDEXED_ADDRESS (X, ADDR);					\
  if (flag_pic && MODE == CASE_VECTOR_MODE && GET_CODE (X) == PLUS	\
      && LEGITIMATE_INDEX_P (XEXP (X, 0))				\
      && GET_CODE (XEXP (X, 1)) == LABEL_REF)				\
    goto ADDR; } }


Which should reject any address for class FLOAT that isn't address
modes 2-5 (register indirect, predecrement, postincrement, register
indirect with offset).

I've also modified LEGITIMIZE_ADDRESS to be:

#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN)   \
{ register int ch = (X) != (OLDX);					\
  if (GET_CODE (X) == PLUS)						\
    { int copied = 0;							\
      if (GET_CODE (XEXP (X, 0)) == MULT)				\
	{ COPY_ONCE (X); XEXP (X, 0) = force_operand (XEXP (X, 0), 0);}	\
      if (GET_CODE (XEXP (X, 1)) == MULT)				\
	{ COPY_ONCE (X); XEXP (X, 1) = force_operand (XEXP (X, 1), 0);}	\
      if (ch && GET_CODE (XEXP (X, 1)) == REG				\
	  && GET_CODE (XEXP (X, 0)) == REG)				\
        { if (TARGET_CFV4E && GET_MODE_CLASS (MODE) == MODE_FLOAT)	\
          { COPY_ONCE (X); X = force_operand(X, 0); goto WIN;}		\
	if (ch) goto WIN; }						\
      if (ch) { GO_IF_LEGITIMATE_ADDRESS (MODE, X, WIN); }		\
      if (GET_CODE (XEXP (X, 0)) == REG					\
	       || (GET_CODE (XEXP (X, 0)) == SIGN_EXTEND		\
		   && GET_CODE (XEXP (XEXP (X, 0), 0)) == REG		\
		   && GET_MODE (XEXP (XEXP (X, 0), 0)) == HImode))	\
	{ register rtx temp = gen_reg_rtx (Pmode);			\
	  register rtx val = force_operand (XEXP (X, 1), 0);		\
	  emit_move_insn (temp, val);					\
	  COPY_ONCE (X);						\
	  XEXP (X, 1) = temp;						\
	  goto WIN; }							\
      else if (GET_CODE (XEXP (X, 1)) == REG				\
	       || (GET_CODE (XEXP (X, 1)) == SIGN_EXTEND		\
		   && GET_CODE (XEXP (XEXP (X, 1), 0)) == REG		\
		   && GET_MODE (XEXP (XEXP (X, 1), 0)) == HImode))	\
	{ register rtx temp = gen_reg_rtx (Pmode);			\
	  register rtx val = force_operand (XEXP (X, 0), 0);		\
	  emit_move_insn (temp, val);					\
	  COPY_ONCE (X);						\
	  XEXP (X, 0) = temp;						\
	  goto WIN; }}}


Note the check for TARGET_CFV4E and MODE_CLASS of FLOAT which forces
REG+REG into a register and uses indirect.

And *still* it generates:

(insn 18 16 20 (set (reg:DF 35)
        (mem:DF (plus:SI (reg:SI 33)
                (reg:SI 34)) [0 S8 A16])) -1 (nil)
    (nil))


Which causes the compilation to fail with:

/tmp/t.c:7: unrecognizable insn:
(insn 20 18 22 (set (reg:DF 35)
        (mem:DF (plus:SI (reg:SI 33)
                (reg:SI 36)) [0 S8 A16])) -1 (nil)
    (expr_list:REG_DEAD (reg:SI 33)
        (expr_list:REG_DEAD (reg:SI 36)
            (nil))))
/tmp/t.c:7: Internal compiler error in extract_insn, at recog.c:2129

In gcc-2.95.3, the rtl dump for this was the two instructions:

(insn 14 13 16 (set (reg:SI 34)
        (plus:SI (reg:SI 33)
            (reg/v:SI 29))) -1 (nil)
    (nil))

(insn 16 14 18 (set (reg:DF 35)
        (mem:DF (reg:SI 34) 0)) -1 (nil)
    (nil))


So my question is:

1) How does gcc decide that (REG+REG) is valid for the movdf instuction?

2) Is it considered valid for the compiler to generate RTL that the
   patterns constraints reject in the rtl generation pass and hope
   that GO_IF_LEGITIMATE_ADDRESS and LEGITIMIZE_ADDRESS will fix?

2) If the answer to 2 is true, should I split the instruction up
   in the expand of movdf if operand1 is of that addressing mode, or
   should I add a 'valid_fpu_src_operand' predicate in the movdf_v4e
   insn pattern to reject (REG+REG) addressing modes?

Thanks for any suggestions,

-- 
Peter Barada                                   Peter.Barada@motorola.com
Wizard                                         781-852-2768 (direct)
WaveMark Solutions(wholly owned by Motorola)   781-270-0193 (fax)


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