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]

Re: Alpha CPU-specific builtins


On Sun, May 26, 2002 at 05:16:19PM +0200, Falk Hueffner wrote:
> +  def_builtin ("__builtin_alpha_bic",     di_ftype_di_di, ALPHA_BUILTIN_BIC);
> +  def_builtin ("__builtin_alpha_eqv",     di_ftype_di_di, ALPHA_BUILTIN_EQV);
> +  def_builtin ("__builtin_alpha_ornot",   di_ftype_di_di, ALPHA_BUILTIN_ORNOT);

These are a waste of time.  They can be quite adequately described to
the compiler with C operators.  If the compiler replaces them with an
equivalent operation, then so be it.

> +  def_builtin ("__builtin_alpha_rpcc",	  di_ftype,	  ALPHA_BUILTIN_RPCC);

Ideally this should take an input.  While gas doesn't support the syntax
at the moment, the "unused" register (I forget whether its's RA or RB)
is considered an input on EV6, which means that you have a mechanism to
avoid having the RPCC instruction scheduled too early by the reorder buffer.

> +enum alpha_builtins {

No reason for this to be in the header.  I know that's where most of the
other targets have put this, but it's silly.  Leave it in the .c file.

> +(define_insn "zap"
> +  [(set (match_operand:DI 0 "register_operand" "=r")
> +	(unspec:DI [(match_operand:DI 1 "reg_or_0_operand" "rJ")
> +		    (match_operand:DI 2 "reg_or_8bit_operand" "rI")]
> +		   UNSPEC_ZAP))]
> +  ""
> +  "zap %r1,%2,%0"
> +  [(set_attr "type" "shift")])

A couple o points here.  First, if you see

	y = __builtin_zap (x, 0x55)

you should immediately expand this to 

	(set (reg:DI y)
	     (and:DI (reg:DI x)
		     (const_int 0xFF00FF00FF00FF00)))

so that you can show the compiler what is going on.  Similarly, 
since we know that only the low 3 bits are examined, we should
allow combine to put any appropriate value it likes in here.
So you're going to wind up with a sequence of patterns

(define_expand "zap"
  [(set (match_operand:DI 0 "register_operand" "")
	(and:DI (match_operand:DI 1 "reg_or_const_int_operand" "")
		(unspec:DI
		  [(match_operand:DI 2 "reg_or_const_int_operand" "")]
		  UNSPEC_ZAP)))]
  ""
{
  if (operands[1] == const0_rtx)
    {
      emit_move_insn (operands[0], operands[1]);
      DONE;
    }
  operands[1] = force_reg (DImode, operands[1]);

  if (GET_CODE (operands[2]) == CONST_INT)
    {
      HOST_WIDE_INT mask = alpha_expand_zap_mask (INTVAL (operands[2]));
      emit_insn (gen_anddi3 (operands[0], operands[1], GEN_INT (mask)));
      DONE;
    }
})

(define_insn "*zap_1"
  [(set (match_operand:DI 0 "register_operand" "=r,r,r,r")
	(and:DI (match_operand:DI 1 "reg_or_const_int_operand" "n,r,J,r")
		(unspec:DI
		  [(match_operand:DI 2 "reg_or_const_int_operand" "n,n,r,r")]
		  UNSPEC_ZAP)))]
  ""
  "@
   #
   #
   zap %r1,%2,%0"
  [(set_attr "type" "shift")])

(define_split
  [(set (match_operand:DI 0 "register_operand" "")
	(and:DI (match_operand:DI 1 "const_int_operand" "")
		(unspec:DI
		  [(match_operand:DI 2 "const_int_operand" "")]
		  UNSPEC_ZAP)))]
  ""
  [(const_int 0)]
{
  HOST_WIDE_INT mask = alpha_expand_zap_mask (INTVAL (operands[2]));
  operands[1] = gen_int_mode (INTVAL (operands[1]) & mask, DImode);
  emit_move_insn (operands[0], operands[1]);
  DONE;
})

(define_insn_and_split "*zap_2"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(and:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
		(unspec:DI
		  [(and:DI (match_operand:DI 2 "register_operand" "r")
			   (match_operand:DI 3 "const_int_operand" ""))]
		  UNSPEC_ZAP)))]
  "(INTVAL (operands[3]) & 7) == 7"
  "#"
  "&& 1"
  [(set (match_dup 0)
	(and:DI (match_dup 1)
		(unspec:DI [(match_dup 2)] UNSPEC_ZAP)))]
  ""
  [(set_attr "type" "shift")])

Where reg_or_const_int_operand and alpha_expand_zap_mask do
the obvious thing.

> +(define_insn "zapnot"

Similarly, except that you'd like to expose the invert as well.

(define_expand "zapnot"
  [(set (match_operand:DI 0 "register_operand" "")
	(and:DI (match_operand:DI 1 "reg_or_const_int_operand" "")
		(unspec:DI
		  [(not:DI (match_operand:DI 2 "reg_or_const_int_operand" ""))]
		  UNSPEC_ZAP)))]
  ""
{
  if (operands[1] == const0_rtx)
    {
      emit_move_insn (operands[0], operands[1]);
      DONE;
    }
  operands[1] = force_reg (DImode, operands[1]);

  if (GET_CODE (operands[2]) == CONST_INT)
    {
      HOST_WIDE_INT mask = alpha_expand_zap_mask (INTVAL (operands[2]));
      emit_insn (gen_anddi3 (operands[0], operands[1], GEN_INT (~mask)));
      DONE;
    }
})

(define_insn "*zapnot_1"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(and:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
                (unspec:DI
                  [(not:DI (match_operand:DI 2 "register_operand" "r"))]
                  UNSPEC_ZAP)))]
  ""
  "zapnot %r1,%2,%0"
  [(set_attr "type" "shift")])

(define_insn_and_split "*zapnot_2"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(and:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
                (unspec:DI
                  [(not:DI (and:DI
			     (match_operand:DI 2 "register_operand" "r")
			     (match_operand:DI 3 "const_int_operand" "")))]
                  UNSPEC_ZAP)))]
  "(INTVAL (operands[3]) & 7) == 7"
  "#"
  "&& 1"
  [(set (match_dup 0)
	(and:DI (match_dup 1)
		(unspec:DI [(not:DI (match_dup 2))])))]
  ""
  [(set_attr "type" "shift")])

(define_insn_and_split "*zapnot_3"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(and:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
                (unspec:DI
                  [(xor:DI (match_operand:DI 2 "register_operand" "r")
			   (match_operand:DI 3 "const_int_operand" ""))]
                  UNSPEC_ZAP)))]
  "(INTVAL (operands[3]) & 7) == 7"
  "#"
  "&& 1"
  [(set (match_dup 0)
	(and:DI (match_dup 1)
		(unspec:DI [(not:DI (match_dup 2))])))]
  ""
  [(set_attr "type" "shift")])

> +(define_insn "amask"
> +  [(set (match_operand:DI 0 "register_operand" "=r")
> +	(unspec:DI [(match_operand:DI 1 "reg_or_8bit_operand" "rI")]
> +		   UNSPEC_AMASK))]
> +  ""
> +  "amask %1,%0"
> +  [(set_attr "type" "misc")]) ; ??? can't find the correct class
> +
> +(define_insn "implver"
> +  [(set (match_operand:DI 0 "register_operand" "=r")
> +  	(unspec:DI [(const_int 0)] UNSPEC_IMPLVER))]
> +  ""
> +  "implver %0"
> +  [(set_attr "type" "misc")]) ; ??? can't find the correct class

Easy: look at the encoding.  They're ilog.

> +(define_insn "minub8"
> +  [(set (match_operand:DI 0 "register_operand" "=r")
> +	(unspec:DI [(match_operand:DI 1 "reg_or_0_operand" "%rJ")
> +		    (match_operand:DI 2 "reg_or_8bit_operand" "rI")]
> +		   UNSPEC_MINUB8))]
> +  ""
> +  "minub8 %r1,%2,%0"
> +  [(set_attr "type" "mvi")])

All of these can and should be described with vector modes.  E.g.

(define_insn "uminv8qi3"
  [(set (match_operand:V8QI 0 "register_operand" "=r")
	(umin:V8QI (match_operand:V8QI "reg_or_0_operand" "rJ")
		   (match_operand:V8QI "reg_or_0_operand" "rJ")))]
  "TARGET_MAX"
  "minub8 %r1,%r2,%0"
  [(set_attr "type" "mvi")])

(define_expand "minub8"
  [(match_operand:DI 0 "register_operand" "")
   (match_operand:DI 1 "reg_or_0_operand" "")
   (match_operand:DI 2 "reg_or_0_operand" "")]
  "TARGET_MAX"
{
  operands[0] = gen_lowpart (V8QImode, operands[0]);
  if (operands[1] == const0_rtx)
    operands[1] = CONST0_RTX (V8QImode);
  else
    operands[1] = gen_lowpart (V8QImode, operands[1]);
  if (operands[2] == const0_rtx)
    operands[2] = CONST0_RTX (V8QImode);
  else
    operands[2] = gen_lowpart (V8QImode, operands[2]);
  emit_insn (gen_uminv8qi3 (operands[0], operands[1], operands[2]));
  DONE;
})

Also note that you cannot enable these unless TARGET_MAX.  This
means you'll need to complicate alpha.c to either not register
these builtins or reject them at expansion time.


r~


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