altivec patches

Geoff Keating geoffk@geoffk.org
Mon Nov 5 13:59:00 GMT 2001


> From: Aldy Hernandez <aldyh@redhat.com>
> Cc: Geoff Keating <geoffk@cygnus.com>
> Date: 05 Nov 2001 15:54:20 -0500

Hi Aldy,

> *************** extern int rs6000_debug_arg;		/* debug a
> *** 569,581 ****
>   #define PARM_BOUNDARY (TARGET_32BIT ? 32 : 64)
>   
>   /* Boundary (in *bits*) on which stack pointer should be aligned.  */
> ! #define STACK_BOUNDARY (TARGET_32BIT ? 64 : 128)
>   
>   /* Allocation boundary (in *bits*) for the code of a function.  */
>   #define FUNCTION_BOUNDARY 32
>   
>   /* No data type wants to be aligned rounder than this.  */
> ! #define BIGGEST_ALIGNMENT 64
>   
>   /* Handle #pragma pack.  */
>   #define HANDLE_PRAGMA_PACK 1
> --- 585,604 ----
>   #define PARM_BOUNDARY (TARGET_32BIT ? 32 : 64)
>   
>   /* Boundary (in *bits*) on which stack pointer should be aligned.  */
> ! #define STACK_BOUNDARY ((TARGET_32BIT && !TARGET_ALTIVEC_ABI) ? 64 : 128)
>   
>   /* Allocation boundary (in *bits*) for the code of a function.  */
>   #define FUNCTION_BOUNDARY 32
>   
>   /* No data type wants to be aligned rounder than this.  */
> ! #define BIGGEST_ALIGNMENT (TARGET_ALTIVEC_ABI ? 128 : 64)

I think you _don't_ want this to be dependent on the ABI.  Changing
this isn't an ABI change (I hope!), which is good because...

> ! 
> ! /* A C expression to compute the alignment for a variables in the
> !    local store.  TYPE is the data type, and ALIGN is the alignment
> !    that the object would ordinarily have.  */
> ! #define LOCAL_ALIGNMENT(TYPE, ALIGN)				\
> ! 	((TARGET_ALTIVEC_ABI		    			\
> ! 	  && TREE_CODE (TYPE)) == VECTOR_TYPE ? 128 : ALIGN)

...as altivec values have to be 128-bit aligned because of the
hardware, you don't want this ABI-dependent either.

> *************** extern int rs6000_debug_arg;		/* debug a
> *** 634,640 ****
>      a register, in order to work around problems in allocating stack storage
>      in inline functions.  */
>   
> ! #define FIRST_PSEUDO_REGISTER 77
>   
>   /* This must not decrease, for backwards compatibility.  If
>      FIRST_PSEUDO_REGISTER increases, this should as well.  */
> --- 659,665 ----
>      a register, in order to work around problems in allocating stack storage
>      in inline functions.  */
>   
> ! #define FIRST_PSEUDO_REGISTER 109
>   
>   /* This must not decrease, for backwards compatibility.  If
>      FIRST_PSEUDO_REGISTER increases, this should as well.  */

The DWARF_FRAME_REGISTERS change seems to have gone away, which is not
quite right:  it has to happen _only when the ABI is 'altivec'_.

This will be a bit tricky because DWARF_FRAME_REGISTERS is also used
in libgcc, so you have to #define something when the Altivec ABI is
chosen, and then key off that if IN_LIBGCC2.

I wonder if you could assume that the integrated cpplib will always be
used when compiling libgcc?  That would make things easier, because
then you wouldn't have muck with specs so much.

> *************** extern int rs6000_debug_arg;		/* debug a
> *** 655,661 ****
>      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
>      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
>      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
> !    0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1}
>   
>   /* 1 for registers not available across function calls.
>      These must include the FIXED_REGISTERS and also any
> --- 680,690 ----
>      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
>      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
>      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
> !    0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1,	   \
> !    /* AltiVec registers.  */			   \
> !    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
> !    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0  \
> ! }

This is correct, but doesn't there need to be a change to them in
CONDITIONAL_REGISTER_USAGE when the altivec ABI is chosen (in which
some altivec registers are call-saved)?

> *************** typedef struct rs6000_stack {
> *** 1338,1346 ****
> --- 1428,1442 ----
>   			? FP_ARG_AIX_MAX_REG : FP_ARG_V4_MAX_REG)
>   #define FP_ARG_NUM_REG (FP_ARG_MAX_REG - FP_ARG_MIN_REG + 1)
>   
> + /* Minimum and maximum AltiVec registers used to hold arguments.  */
> + #define ALTIVEC_ARG_MIN_REG 77
> + #define ALTIVEC_ARG_MAX_REG 88
> + #define ALTIVEC_ARG_NUM_REG (ALTIVEC_ARG_MAX_REG - ALTIVEC_ARG_MIN_REG + 1)

These should be based off FIRST_ALTIVEC_REGISTER rather than being
magic numbers...

>   /* Return registers */
>   #define GP_ARG_RETURN GP_ARG_MIN_REG
>   #define FP_ARG_RETURN FP_ARG_MIN_REG
> + #define ALTIVEC_ARG_RETURN 79

... this too.


> Index: sysv4.h
> ===================================================================
> RCS file: /cvs/uberbaum/gcc/config/rs6000/sysv4.h,v
> retrieving revision 1.67
> diff -c -p -r1.67 sysv4.h
> *** sysv4.h	2001/10/29 23:09:43	1.67
> --- sysv4.h	2001/11/05 19:49:24
> *************** do {									\
> *** 400,417 ****
>      one set of libraries with -mno-eabi instead of eabi libraries and non-eabi
>      versions, just use 64 as the stack boundary.  */
>   #undef	STACK_BOUNDARY
> ! #define	STACK_BOUNDARY	64
>   
>   /* Real stack boundary as mandated by the appropriate ABI.  */
> ! #define ABI_STACK_BOUNDARY ((TARGET_EABI) ? 64 : 128)
>   
>   /* No data type wants to be aligned rounder than this.  */
>   #undef	BIGGEST_ALIGNMENT
> ! #define BIGGEST_ALIGNMENT ((TARGET_EABI) ? 64 : 128)
>   
>   #undef  BIGGEST_FIELD_ALIGNMENT
>   #undef  ADJUST_FIELD_ALIGN
> - #undef  ROUND_TYPE_ALIGN
>   
>   /* Use ELF style section commands.  */
>   
> --- 400,430 ----
>      one set of libraries with -mno-eabi instead of eabi libraries and non-eabi
>      versions, just use 64 as the stack boundary.  */
>   #undef	STACK_BOUNDARY
> ! #define	STACK_BOUNDARY	(TARGET_ALTIVEC_ABI ? 128 : 64)
>   
>   /* Real stack boundary as mandated by the appropriate ABI.  */
> ! #define ABI_STACK_BOUNDARY ((TARGET_EABI && !TARGET_ALTIVEC_ABI) ? 64 : 128)
>   
>   /* No data type wants to be aligned rounder than this.  */
>   #undef	BIGGEST_ALIGNMENT
> ! #define BIGGEST_ALIGNMENT ((TARGET_EABI && !TARGET_ALTIVEC_ABI) ? 64 : 128)
>   
> + /* An expression for the alignment of a structure field FIELD if the
> +    alignment computed in the usual way is COMPUTED.  */
> + #define ADJUST_FIELD_ALIGN(FIELD, COMPUTED)				      \
> + 	((TARGET_ALTIVEC_ABI && TREE_CODE (TREE_TYPE (FIELD)) == VECTOR_TYPE) \
> + 	 ? 128 : COMPUTED)
> + 
> + /* Define this macro as an expression for the alignment of a type
> +    (given by TYPE as a tree node) if the alignment computed in the
> +    usual way is COMPUTED and the alignment explicitly specified was
> +    SPECIFIED.  */
> + #define ROUND_TYPE_ALIGN(TYPE, COMPUTED, SPECIFIED)			\
> + 	((TARGET_ALTIVEC_ABI && TREE_CODE (TYPE) == VECTOR_TYPE)	\
> + 	 ? 128 : MAX (COMPUTED, SPECIFIED))
> + 
>   #undef  BIGGEST_FIELD_ALIGNMENT
>   #undef  ADJUST_FIELD_ALIGN
>   
>   /* Use ELF style section commands.  */

This has the same comment as the equivalent stuff in rs6000.h.


> *************** function_arg_advance (cum, mode, type, n
> *** 2159,2165 ****
>   {
>     cum->nargs_prototype--;
>   
> !   if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS)
>       {
>         if (TARGET_HARD_FLOAT
>   	  && (mode == SFmode || mode == DFmode))
> --- 2242,2255 ----
>   {
>     cum->nargs_prototype--;
>   
> !   if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
> !     {
> !       if (cum->vregno <= ALTIVEC_ARG_MAX_REG)
> ! 	cum->vregno++;
> !       else
> ! 	cum->words += RS6000_ARG_SIZE (mode, type);
> !     }

Something you might not have seen in the ABI documentation: unnamed
vector arguments (passed to varargs functions after the '...') get
passed in memory, not in registers.  (I don't remember if this is just
the unnamed arguments or all the arguments to varargs functions, you
should check.)

> *************** print_operand (file, x, code)
> *** 4714,4719 ****
> --- 5287,5318 ----
>   		     reg_names[SMALL_DATA_REG]);
>   	}
>         return;
> + 
> +       /* Print AltiVec memory operand.  */
> +     case 'y':
> +       {
> + 	rtx tmp;
> + 
> + 	if (GET_CODE (x) != MEM)
> + 	  abort ();
> + 
> + 	tmp = XEXP (x, 0);
> + 
> + 	if (GET_CODE (tmp) == REG)
> + 	  fprintf (file, "0, %s", reg_names[REGNO (tmp)]);
> + 	else if (GET_CODE (tmp) == PLUS && GET_CODE (XEXP (tmp, 1)) == REG)
> + 	  {
> + 	    if (REGNO (XEXP (tmp, 0)) == 0)
> + 	      fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (tmp, 1)) ],
> + 		       reg_names[ REGNO (XEXP (tmp, 0)) ]);
> + 	    else
> + 	      fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (tmp, 0)) ],
> + 		       reg_names[ REGNO (XEXP (tmp, 1)) ]);
> + 	  }
> + 	else
> + 	  abort ();
> + 	break;
> +       }

Do you really need this?  It looks just like the way a normal memory
operand is printed (for the cases that are allowed for altivec).

> Index: rs6000.md

Can you put the altivec insns in their own .md file and use the include
mechanism?  I believe this is what it was intended for.

> + ;; No code is needed to copy between vector registers.
> + (define_insn "*altivec_vec_move"
> +   [(set (match_operand 0 "altivec_register" "=v")
> + 	(match_operand 1 "altivec_register" "v"))]
> +   "TARGET_ALTIVEC"
> +   ""
> +   [(set_attr "type" "altivec")])

Um, that can't possibly be right.  Also, it should be part of
movv4si_internal, because reload needs all the move insns to be the
same pattern.

> + ;; Vector move instructions.
> + (define_expand "movv4si"
> +   [(set (match_operand:V4SI 0 "nonimmediate_operand" "")
> + 	(match_operand:V4SI 1 "any_operand" ""))]
> +   "TARGET_ALTIVEC"
> +   "{ rs6000_emit_move (operands[0], operands[1], V4SImode); DONE; }")
> + 
> + (define_insn "*movv4si_internal"
> +   [(set (match_operand:V4SI 0 "nonimmediate_operand" "=m,v")
> + 	(match_operand:V4SI 1 "input_operand" "v,m"))]
> +   "TARGET_ALTIVEC"
> +   "@
> +    stvx\t%1,%y0
> +    ldvx\t%0,%y1"
> +   [(set_attr "type" "altivec")])

Yes---this needs an alternative to copy a 'v' into a 'v'.  All the
ones below probably need it too.

> + (define_expand "movv8hi"
> +   [(set (match_operand:V8HI 0 "nonimmediate_operand" "")
> + 	(match_operand:V8HI 1 "any_operand" ""))]
> +   "TARGET_ALTIVEC"
> +   "{ rs6000_emit_move (operands[0], operands[1], V8HImode); DONE; }")
> + 
> + (define_insn "*movv8hi_internal1"
> +   [(set (match_operand:V8HI 0 "nonimmediate_operand" "=m,v")
> + 	(match_operand:V8HI 1 "input_operand" "v,m"))]
> +   "TARGET_ALTIVEC"
> +   "@
> +    stvx\t%1,%y0
> +    ldvx\t%0,%y1"
> +   [(set_attr "type" "altivec")])
> + 
> + (define_expand "movv16qi"
> +   [(set (match_operand:V16QI 0 "nonimmediate_operand" "")
> + 	(match_operand:V16QI 1 "any_operand" ""))]
> +   "TARGET_ALTIVEC"
> +   "{ rs6000_emit_move (operands[0], operands[1], V16QImode); DONE; }")
> + 
> + (define_insn "*movv16qi_internal1"
> +   [(set (match_operand:V16QI 0 "nonimmediate_operand" "=m,v")
> + 	(match_operand:V16QI 1 "input_operand" "v,m"))]
> +   "TARGET_ALTIVEC"
> +   "@
> +    stvx\t%1,%y0
> +    ldvx\t%0,%y1"
> +   [(set_attr "type" "altivec")])
> + 
> + (define_expand "movv4sf"
> +   [(set (match_operand:V4SF 0 "nonimmediate_operand" "")
> + 	(match_operand:V4SF 1 "any_operand" ""))]
> +   "TARGET_ALTIVEC"
> +   "{ rs6000_emit_move (operands[0], operands[1], V4SFmode); DONE; }")
> + 
> + (define_insn "*movv4sf_internal1"
> +   [(set (match_operand:V4SF 0 "nonimmediate_operand" "=m,v")
> + 	(match_operand:V4SF 1 "input_operand" "v,m"))]
> +   "TARGET_ALTIVEC"
> +   "@
> +    stvx\t%1,%y0
> +    ldvx\t%0,%y1"
> +   [(set_attr "type" "altivec")])
> + 
> + ;; Simple binary operations.
> + 
> 
> -- boring builtins deleted-- 
> 
> + (define_insn "altivec_vxor"
> +   [(set (match_operand:V4SI 0 "register_operand" "=v")
> +         (unspec:V4SI [(match_operand:V4SI 1 "register_operand" "v")
> +                       (match_operand:V4SI 2 "register_operand" "v")] 136))]
> +   "TARGET_ALTIVEC"
> +   "vxor\t%0,%1,%2"
> +   [(set_attr "type" "altivec")])

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



More information about the Gcc-patches mailing list