X86_64_COMPLEX_X87_CLASS,
X86_64_MEMORY_CLASS
};
-static const char * const x86_64_reg_class_name[] =
- {"no", "integer", "integerSI", "sse", "sseSF", "sseDF", "sseup", "x87", "x87up", "cplx87", "no"};
+static const char * const x86_64_reg_class_name[] = {
+ "no", "integer", "integerSI", "sse", "sseSF", "sseDF",
+ "sseup", "x87", "x87up", "cplx87", "no"
+};
#define MAX_CLASSES 4
-static int classify_argument (enum machine_mode, tree,
- enum x86_64_reg_class [MAX_CLASSES], int);
-static int examine_argument (enum machine_mode, tree, int, int *, int *);
-static rtx construct_container (enum machine_mode, tree, int, int, int,
- const int *, int);
-static enum x86_64_reg_class merge_classes (enum x86_64_reg_class,
- enum x86_64_reg_class);
/* Table of constants used by fldpi, fldln2, etc.... */
static REAL_VALUE_TYPE ext_80387_constants_table [5];
return;
}
+/* Return the "natural" mode for TYPE. In most cases, this is just TYPE_MODE.
+ But in the case of vector types, it is some vector mode.
+
+ When we have only some of our vector isa extensions enabled, then there
+ are some modes for which vector_mode_supported_p is false. For these
+ modes, the generic vector support in gcc will choose some non-vector mode
+ in order to implement the type. By computing the natural mode, we'll
+ select the proper ABI location for the operand and not depend on whatever
+ the middle-end decides to do with these vector types. */
+
+static enum machine_mode
+type_natural_mode (tree type)
+{
+ enum machine_mode mode = TYPE_MODE (type);
+
+ if (TREE_CODE (type) == VECTOR_TYPE && !VECTOR_MODE_P (mode))
+ {
+ HOST_WIDE_INT size = int_size_in_bytes (type);
+ if ((size == 8 || size == 16)
+ /* ??? Generic code allows us to create width 1 vectors. Ignore. */
+ && TYPE_VECTOR_SUBPARTS (type) > 1)
+ {
+ enum machine_mode innermode = TYPE_MODE (TREE_TYPE (type));
+
+ if (TREE_CODE (TREE_TYPE (type)) == REAL_TYPE)
+ mode = MIN_MODE_VECTOR_FLOAT;
+ else
+ mode = MIN_MODE_VECTOR_INT;
+
+ /* Get the mode which has this inner mode and number of units. */
+ for (; mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode))
+ if (GET_MODE_NUNITS (mode) == TYPE_VECTOR_SUBPARTS (type)
+ && GET_MODE_INNER (mode) == innermode)
+ return mode;
+
+ abort ();
+ }
+ }
+
+ return mode;
+}
+
+/* We want to pass a value in REGNO whose "natural" mode is MODE. However,
+ this may not agree with the mode that the type system has chosen for the
+ register, which is ORIG_MODE. If ORIG_MODE is not BLKmode, then we can
+ go ahead and use it. Otherwise we have to build a PARALLEL instead. */
+
+static rtx
+gen_reg_or_parallel (enum machine_mode mode, enum machine_mode orig_mode,
+ unsigned int regno)
+{
+ rtx tmp;
+
+ if (orig_mode != BLKmode)
+ tmp = gen_rtx_REG (orig_mode, regno);
+ else
+ {
+ tmp = gen_rtx_REG (mode, regno);
+ tmp = gen_rtx_EXPR_LIST (VOIDmode, tmp, const0_rtx);
+ tmp = gen_rtx_PARALLEL (orig_mode, gen_rtvec (1, tmp));
+ }
+
+ return tmp;
+}
+
/* x86-64 register passing implementation. See x86-64 ABI for details. Goal
of this code is to classify each 8bytes of incoming argument by the register
class and assign registers accordingly. */
}
return 1;
}
+
/* Construct container for the argument used by GCC interface. See
FUNCTION_ARG for the detailed description. */
+
static rtx
-construct_container (enum machine_mode mode, tree type, int in_return,
- int nintregs, int nsseregs, const int * intreg,
- int sse_regno)
+construct_container (enum machine_mode mode, enum machine_mode orig_mode,
+ tree type, int in_return, int nintregs, int nsseregs,
+ const int *intreg, int sse_regno)
{
enum machine_mode tmpmode;
int bytes =
}
if (!n)
return NULL;
- if (!examine_argument (mode, type, in_return, &needed_intregs, &needed_sseregs))
+ if (!examine_argument (mode, type, in_return, &needed_intregs,
+ &needed_sseregs))
return NULL;
if (needed_intregs > nintregs || needed_sseregs > nsseregs)
return NULL;
case X86_64_SSE_CLASS:
case X86_64_SSESF_CLASS:
case X86_64_SSEDF_CLASS:
- return gen_rtx_REG (mode, SSE_REGNO (sse_regno));
+ return gen_reg_or_parallel (mode, orig_mode, SSE_REGNO (sse_regno));
case X86_64_X87_CLASS:
case X86_64_COMPLEX_X87_CLASS:
return gen_rtx_REG (mode, FIRST_STACK_REG);
(TYPE is null for libcalls where that information may not be available.) */
void
-function_arg_advance (CUMULATIVE_ARGS *cum, /* current arg information */
- enum machine_mode mode, /* current arg mode */
- tree type, /* type of the argument or 0 if lib support */
- int named) /* whether or not the argument was named */
+function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+ tree type, int named)
{
int bytes =
(mode == BLKmode) ? int_size_in_bytes (type) : (int) GET_MODE_SIZE (mode);
int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
if (TARGET_DEBUG_ARG)
- fprintf (stderr,
- "function_adv (sz=%d, wds=%2d, nregs=%d, ssenregs=%d, mode=%s, named=%d)\n\n",
- words, cum->words, cum->nregs, cum->sse_nregs, GET_MODE_NAME (mode), named);
+ fprintf (stderr, "function_adv (sz=%d, wds=%2d, nregs=%d, ssenregs=%d, "
+ "mode=%s, named=%d)\n\n",
+ words, cum->words, cum->nregs, cum->sse_nregs,
+ GET_MODE_NAME (mode), named);
if (TARGET_64BIT)
{
int int_nregs, sse_nregs;
return;
}
-/* A subroutine of function_arg. We want to pass a parameter whose nominal
- type is MODE in REGNO. We try to minimize ABI variation, so MODE may not
- actually be valid for REGNO with the current ISA. In this case, ALT_MODE
- is used instead. It must be the same size as MODE, and must be known to
- be valid for REGNO. Finally, ORIG_MODE is the original mode of the
- parameter, as seen by the type system. This may be different from MODE
- when we're mucking with things minimizing ABI variations.
-
- Returns a REG or a PARALLEL as appropriate. */
-
-static rtx
-gen_reg_or_parallel (enum machine_mode mode, enum machine_mode alt_mode,
- enum machine_mode orig_mode, unsigned int regno)
-{
- rtx tmp;
-
- if (HARD_REGNO_MODE_OK (regno, mode))
- tmp = gen_rtx_REG (mode, regno);
- else
- {
- tmp = gen_rtx_REG (alt_mode, regno);
- tmp = gen_rtx_EXPR_LIST (VOIDmode, tmp, const0_rtx);
- tmp = gen_rtx_PARALLEL (orig_mode, gen_rtvec (1, tmp));
- }
-
- return tmp;
-}
-
/* Define where to put the arguments to a function.
Value is zero to push the argument on the stack,
or a hard register in which to store the argument.
/* To simplify the code below, represent vector types with a vector mode
even if MMX/SSE are not active. */
- if (type
- && TREE_CODE (type) == VECTOR_TYPE
- && (bytes == 8 || bytes == 16)
- && GET_MODE_CLASS (TYPE_MODE (type)) != MODE_VECTOR_INT
- && GET_MODE_CLASS (TYPE_MODE (type)) != MODE_VECTOR_FLOAT)
- {
- enum machine_mode innermode = TYPE_MODE (TREE_TYPE (type));
- enum machine_mode newmode
- = TREE_CODE (TREE_TYPE (type)) == REAL_TYPE
- ? MIN_MODE_VECTOR_FLOAT : MIN_MODE_VECTOR_INT;
-
- /* Get the mode which has this inner mode and number of units. */
- for (; newmode != VOIDmode; newmode = GET_MODE_WIDER_MODE (newmode))
- if (GET_MODE_NUNITS (newmode) == TYPE_VECTOR_SUBPARTS (type)
- && GET_MODE_INNER (newmode) == innermode)
- {
- mode = newmode;
- break;
- }
- }
+ if (type && TREE_CODE (type) == VECTOR_TYPE)
+ mode = type_natural_mode (type);
/* Handle a hidden AL argument containing number of registers for varargs
x86-64 functions. For i386 ABI just return constm1_rtx to avoid
return constm1_rtx;
}
if (TARGET_64BIT)
- ret = construct_container (mode, type, 0, cum->nregs, cum->sse_nregs,
+ ret = construct_container (mode, orig_mode, type, 0, cum->nregs,
+ cum->sse_nregs,
&x86_64_int_parameter_registers [cum->regno],
cum->sse_regno);
else
"changes the ABI");
}
if (cum->sse_nregs)
- ret = gen_reg_or_parallel (mode, TImode, orig_mode,
+ ret = gen_reg_or_parallel (mode, orig_mode,
cum->sse_regno + FIRST_SSE_REG);
}
break;
"changes the ABI");
}
if (cum->mmx_nregs)
- ret = gen_reg_or_parallel (mode, DImode, orig_mode,
+ ret = gen_reg_or_parallel (mode, orig_mode,
cum->mmx_regno + FIRST_MMX_REG);
}
break;
{
if (TARGET_64BIT)
{
- rtx ret = construct_container (TYPE_MODE (valtype), valtype, 1,
- REGPARM_MAX, SSE_REGPARM_MAX,
+ rtx ret = construct_container (type_natural_mode (valtype),
+ TYPE_MODE (valtype), valtype,
+ 1, REGPARM_MAX, SSE_REGPARM_MAX,
x86_64_int_return_registers, 0);
- /* For zero sized structures, construct_container return NULL, but we need
- to keep rest of compiler happy by returning meaningful value. */
+ /* For zero sized structures, construct_container return NULL, but we
+ need to keep rest of compiler happy by returning meaningful value. */
if (!ret)
ret = gen_rtx_REG (TYPE_MODE (valtype), 0);
return ret;
size = int_size_in_bytes (type);
rsize = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
- container = construct_container (TYPE_MODE (type), type, 0,
- REGPARM_MAX, SSE_REGPARM_MAX, intreg, 0);
- /*
- * Pull the value out of the saved registers ...
- */
+ container = construct_container (type_natural_mode (type), TYPE_MODE (type),
+ type, 0, REGPARM_MAX, SSE_REGPARM_MAX,
+ intreg, 0);
+
+ /* Pull the value out of the saved registers. */
addr = create_tmp_var (ptr_type_node, "addr");
DECL_POINTER_ALIAS_SET (addr) = get_varargs_alias_set ();
return VALID_FP_MODE_P (mode);
if (SSE_REGNO_P (regno))
{
- if (TARGET_SSE2 && VALID_SSE2_REG_MODE (mode))
- return 1;
- if (TARGET_SSE && VALID_SSE_REG_MODE (mode))
- return 1;
- return 0;
+ /* We implement the move patterns for all vector modes into and
+ out of SSE registers, even when no operation instructions
+ are available. */
+ return (VALID_SSE_REG_MODE (mode)
+ || VALID_SSE2_REG_MODE (mode)
+ || VALID_MMX_REG_MODE (mode)
+ || VALID_MMX_REG_MODE_3DNOW (mode));
}
if (MMX_REGNO_P (regno))
{
- if (TARGET_3DNOW && VALID_MMX_REG_MODE_3DNOW (mode))
- return 1;
- if (TARGET_MMX && VALID_MMX_REG_MODE (mode))
- return 1;
+ /* We implement the move patterns for 3DNOW modes even in MMX mode,
+ so if the register is available at all, then we can move data of
+ the given mode into or out of it. */
+ return (VALID_MMX_REG_MODE (mode)
+ || VALID_MMX_REG_MODE_3DNOW (mode));
}
/* We handle both integer and floats in the general purpose registers.
In future we should be able to handle vector modes as well. */
;; Main data type used by the insn
(define_attr "mode"
- "unknown,none,QI,HI,SI,DI,SF,DF,XF,TI,V4SF,V2DF,V2SF"
+ "unknown,none,QI,HI,SI,DI,SF,DF,XF,TI,V4SF,V2DF,V2SF,V1DF"
(const_string "unknown"))
;; The CPU unit operations uses.
(set_attr "length_immediate" "1")])
(define_insn "*movsi_1"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=r,m,!*y,!rm,!*y,!*Y,!rm,!*Y")
- (match_operand:SI 1 "general_operand" "rinm,rin,*y,*y,rm,*Y,*Y,rm"))]
+ [(set (match_operand:SI 0 "nonimmediate_operand"
+ "=r ,m ,!*y,!rm,!*y,!*x,!rm,!*x")
+ (match_operand:SI 1 "general_operand"
+ "rinm,rin,*y ,*y ,rm ,*x ,*x ,rm"))]
"(TARGET_INTER_UNIT_MOVES || optimize_size)
&& (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
{
(set_attr "mode" "SI,SI,DI,SI,SI,TI,SI,SI")])
(define_insn "*movsi_1_nointernunit"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=r,m,!*y,!m,!*y,!*Y,!m,!*Y")
- (match_operand:SI 1 "general_operand" "rinm,rin,*y,*y,m,*Y,*Y,m"))]
+ [(set (match_operand:SI 0 "nonimmediate_operand"
+ "=r ,m ,!*y,!m,!*y,!*x,!m,!*x")
+ (match_operand:SI 1 "general_operand"
+ "rinm,rin,*y ,*y,m ,*x ,*x,m"))]
"(!TARGET_INTER_UNIT_MOVES && !optimize_size)
&& (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
{
"!TARGET_64BIT"
"#")
-(define_insn "pushdi2_rex64"
+(define_insn "*pushdi2_rex64"
[(set (match_operand:DI 0 "push_operand" "=<,!<")
(match_operand:DI 1 "general_no_elim_operand" "re*m,n"))]
"TARGET_64BIT"
(set_attr "length_immediate" "1")])
(define_insn "*movdi_2"
- [(set (match_operand:DI 0 "nonimmediate_operand" "=r,o,!m*y,!*y,!m,!*Y,!*Y")
- (match_operand:DI 1 "general_operand" "riFo,riF,*y,m,*Y,*Y,m"))]
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=r,o,!m*y,!*y,!m,!*x,!*x")
+ (match_operand:DI 1 "general_operand" "riFo,riF,*y,m,*x,*x,m"))]
"!TARGET_64BIT
&& (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
"@
"ix86_split_long_move (operands); DONE;")
(define_insn "*movdi_1_rex64"
- [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,mr,!mr,!*y,!rm,!*y,!*Y,!rm,!*Y,!*Y,!*y")
- (match_operand:DI 1 "general_operand" "Z,rem,i,re,n,*y,*y,rm,*Y,*Y,rm,*y,*Y"))]
+ [(set (match_operand:DI 0 "nonimmediate_operand"
+ "=r,r ,r,mr,!mr,!*y,!rm,!*y,!*x,!rm,!*x,!*x,!*y")
+ (match_operand:DI 1 "general_operand"
+ "Z ,rem,i,re,n ,*y ,*y ,rm ,*x ,*x ,rm ,*y ,*x"))]
"TARGET_64BIT
&& (TARGET_INTER_UNIT_MOVES || optimize_size)
&& (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
(set_attr "mode" "SI,DI,DI,DI,SI,DI,DI,DI,TI,DI,DI,DI,DI")])
(define_insn "*movdi_1_rex64_nointerunit"
- [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,mr,!mr,!*y,!m,!*y,!*Y,!m,!*Y")
- (match_operand:DI 1 "general_operand" "Z,rem,i,re,n,*y,*y,m,*Y,*Y,m"))]
+ [(set (match_operand:DI 0 "nonimmediate_operand"
+ "=r,r ,r,mr,!mr,!*y,!m,!*y,!*Y,!m,!*Y")
+ (match_operand:DI 1 "general_operand"
+ "Z,rem,i,re,n ,*y ,*y,m ,*Y ,*Y,m"))]
"TARGET_64BIT
&& (!TARGET_INTER_UNIT_MOVES && !optimize_size)
&& (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
(set (mem:SF (reg:DI SP_REG)) (match_dup 1))])
(define_insn "*movsf_1"
- [(set (match_operand:SF 0 "nonimmediate_operand" "=f#xr,m,f#xr,r#xf,m,x#rf,x#rf,x#rf,m,!*y,!rm,!*y")
- (match_operand:SF 1 "general_operand" "fm#rx,f#rx,G,rmF#fx,Fr#fx,C,x,xm#rf,x#rf,rm,*y,*y"))]
+ [(set (match_operand:SF 0 "nonimmediate_operand"
+ "=f#xr,m ,f#xr,r#xf ,m ,x#rf,x#rf,x#rf ,m ,!*y,!rm,!*y")
+ (match_operand:SF 1 "general_operand"
+ "fm#rx,f#rx,G ,rmF#fx,Fr#fx,C ,x ,xm#rf,x#rf,rm ,*y ,*y"))]
"(TARGET_INTER_UNIT_MOVES || optimize_size)
&& (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
&& (reload_in_progress || reload_completed
(const_string "SF")))])
(define_insn "*movsf_1_nointerunit"
- [(set (match_operand:SF 0 "nonimmediate_operand" "=f#xr,m,f#xr,r#xf,m,x#rf,x#rf,x#rf,m,!*y,!m,!*y")
- (match_operand:SF 1 "general_operand" "fm#rx,f#rx,G,rmF#fx,Fr#fx,C,x,xm#rf,x#rf,m,*y,*y"))]
+ [(set (match_operand:SF 0 "nonimmediate_operand"
+ "=f#xr,m ,f#xr,r#xf ,m ,x#rf,x#rf,x#rf ,m ,!*y,!m,!*y")
+ (match_operand:SF 1 "general_operand"
+ "fm#rx,f#rx,G ,rmF#fx,Fr#fx,C ,x ,xm#rf,x#rf,m ,*y,*y"))]
"(!TARGET_INTER_UNIT_MOVES && !optimize_size)
&& (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
&& (reload_in_progress || reload_completed
(const_string "SF")))])
(define_insn "*swapsf"
- [(set (match_operand:SF 0 "register_operand" "+f")
- (match_operand:SF 1 "register_operand" "+f"))
+ [(set (match_operand:SF 0 "fp_register_operand" "+f")
+ (match_operand:SF 1 "fp_register_operand" "+f"))
(set (match_dup 1)
(match_dup 0))]
- "reload_completed || !TARGET_SSE"
+ "reload_completed || TARGET_80387"
{
if (STACK_TOP_P (operands[0]))
return "fxch\t%1";
;; when optimizing for size.
(define_insn "*movdf_nointeger"
- [(set (match_operand:DF 0 "nonimmediate_operand" "=f#Y,m,f#Y,*r,o,Y#f,Y#f,Y#f,m")
- (match_operand:DF 1 "general_operand" "fm#Y,f#Y,G,*roF,F*r,C,Y#f,YHm#f,Y#f"))]
+ [(set (match_operand:DF 0 "nonimmediate_operand"
+ "=f#x,m ,f#x,*r ,o ,x#f,x#f,x#f ,m")
+ (match_operand:DF 1 "general_operand"
+ "fm#x,f#x,G ,*roF,F*r,C ,x#f,xHm#f,x#f"))]
"(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
&& ((optimize_size || !TARGET_INTEGER_DFMODE_MOVES) && !TARGET_64BIT)
&& (reload_in_progress || reload_completed
abort ();
}
case 6:
+ case 7:
+ case 8:
switch (get_attr_mode (insn))
{
case MODE_V4SF:
return "movaps\t{%1, %0|%0, %1}";
case MODE_V2DF:
return "movapd\t{%1, %0|%0, %1}";
+ case MODE_TI:
+ return "movdqa\t{%1, %0|%0, %1}";
+ case MODE_DI:
+ return "movq\t{%1, %0|%0, %1}";
case MODE_DF:
return "movsd\t{%1, %0|%0, %1}";
+ case MODE_V1DF:
+ return "movlpd\t{%1, %0|%0, %1}";
default:
abort ();
}
- case 7:
- if (get_attr_mode (insn) == MODE_V2DF)
- return "movlpd\t{%1, %0|%0, %1}";
- else
- return "movsd\t{%1, %0|%0, %1}";
- case 8:
- return "movsd\t{%1, %0|%0, %1}";
default:
abort();
(set (attr "mode")
(cond [(eq_attr "alternative" "3,4")
(const_string "SI")
+
+ /* For SSE1, we have many fewer alternatives. */
+ (eq (symbol_ref "TARGET_SSE2") (const_int 0))
+ (cond [(eq_attr "alternative" "5,6")
+ (if_then_else
+ (ne (symbol_ref "optimize_size") (const_int 0))
+ (const_string "V4SF")
+ (const_string "TI"))
+ ]
+ (const_string "DI"))
+
/* xorps is one byte shorter. */
(eq_attr "alternative" "5")
(cond [(ne (symbol_ref "optimize_size")
(const_string "V4SF")
(ne (symbol_ref "TARGET_SSE_LOAD0_BY_PXOR")
(const_int 0))
- (const_string "TI")]
+ (const_string "TI")
+ ]
(const_string "V2DF"))
+
/* For architectures resolving dependencies on
whole SSE registers use APD move to break dependency
chains, otherwise use short move to avoid extra work.
movaps encodes one byte shorter. */
(eq_attr "alternative" "6")
(cond
- [(ne (symbol_ref "optimize_size")
- (const_int 0))
- (const_string "V4SF")
- (ne (symbol_ref "TARGET_SSE_PARTIAL_REG_DEPENDENCY")
- (const_int 0))
- (const_string "V2DF")]
+ [(ne (symbol_ref "optimize_size")
+ (const_int 0))
+ (const_string "V4SF")
+ (ne (symbol_ref "TARGET_SSE_PARTIAL_REG_DEPENDENCY")
+ (const_int 0))
+ (const_string "V2DF")
+ ]
(const_string "DF"))
/* For architectures resolving dependencies on register
parts we may avoid extra work to zero out upper part
(if_then_else
(ne (symbol_ref "TARGET_SSE_PARTIAL_REGS")
(const_int 0))
- (const_string "V2DF")
- (const_string "DF"))]
- (const_string "DF")))])
+ (const_string "V1DF")
+ (const_string "DF"))
+ ]
+ (const_string "DF")))])
(define_insn "*movdf_integer"
- [(set (match_operand:DF 0 "nonimmediate_operand" "=f#Yr,m,f#Yr,r#Yf,o,Y#rf,Y#rf,Y#rf,m")
- (match_operand:DF 1 "general_operand" "fm#Yr,f#Yr,G,roF#Yf,Fr#Yf,C,Y#rf,Ym#rf,Y#rf"))]
+ [(set (match_operand:DF 0 "nonimmediate_operand"
+ "=f#Yr,m ,f#Yr,r#Yf ,o ,Y#rf,Y#rf,Y#rf ,m")
+ (match_operand:DF 1 "general_operand"
+ "fm#Yr,f#Yr,G ,roF#Yf,Fr#Yf,C ,Y#rf,Ym#rf,Y#rf"))]
"(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
&& ((!optimize_size && TARGET_INTEGER_DFMODE_MOVES) || TARGET_64BIT)
&& (reload_in_progress || reload_completed
abort ();
}
case 6:
+ case 7:
+ case 8:
switch (get_attr_mode (insn))
{
case MODE_V4SF:
return "movaps\t{%1, %0|%0, %1}";
case MODE_V2DF:
return "movapd\t{%1, %0|%0, %1}";
+ case MODE_TI:
+ return "movdqa\t{%1, %0|%0, %1}";
+ case MODE_DI:
+ return "movq\t{%1, %0|%0, %1}";
case MODE_DF:
return "movsd\t{%1, %0|%0, %1}";
+ case MODE_V1DF:
+ return "movlpd\t{%1, %0|%0, %1}";
default:
abort ();
}
- case 7:
- if (get_attr_mode (insn) == MODE_V2DF)
- return "movlpd\t{%1, %0|%0, %1}";
- else
- return "movsd\t{%1, %0|%0, %1}";
- case 8:
- return "movsd\t{%1, %0|%0, %1}";
default:
abort();
(set (attr "mode")
(cond [(eq_attr "alternative" "3,4")
(const_string "SI")
+
+ /* For SSE1, we have many fewer alternatives. */
+ (eq (symbol_ref "TARGET_SSE2") (const_int 0))
+ (cond [(eq_attr "alternative" "5,6")
+ (if_then_else
+ (ne (symbol_ref "optimize_size") (const_int 0))
+ (const_string "V4SF")
+ (const_string "TI"))
+ ]
+ (const_string "DI"))
+
/* xorps is one byte shorter. */
(eq_attr "alternative" "5")
(cond [(ne (symbol_ref "optimize_size")
(const_string "V4SF")
(ne (symbol_ref "TARGET_SSE_LOAD0_BY_PXOR")
(const_int 0))
- (const_string "TI")]
+ (const_string "TI")
+ ]
(const_string "V2DF"))
+
/* For architectures resolving dependencies on
whole SSE registers use APD move to break dependency
- chains, otherwise use short move to avoid extra work.
+ chains, otherwise use short move to avoid extra work.
movaps encodes one byte shorter. */
(eq_attr "alternative" "6")
(cond
- [(ne (symbol_ref "optimize_size")
- (const_int 0))
- (const_string "V4SF")
- (ne (symbol_ref "TARGET_SSE_PARTIAL_REG_DEPENDENCY")
- (const_int 0))
- (const_string "V2DF")]
+ [(ne (symbol_ref "optimize_size")
+ (const_int 0))
+ (const_string "V4SF")
+ (ne (symbol_ref "TARGET_SSE_PARTIAL_REG_DEPENDENCY")
+ (const_int 0))
+ (const_string "V2DF")
+ ]
(const_string "DF"))
/* For architectures resolving dependencies on register
parts we may avoid extra work to zero out upper part
(if_then_else
(ne (symbol_ref "TARGET_SSE_PARTIAL_REGS")
(const_int 0))
- (const_string "V2DF")
- (const_string "DF"))]
- (const_string "DF")))])
+ (const_string "V1DF")
+ (const_string "DF"))
+ ]
+ (const_string "DF")))])
(define_split
[(set (match_operand:DF 0 "nonimmediate_operand" "")
"ix86_split_long_move (operands); DONE;")
(define_insn "*swapdf"
- [(set (match_operand:DF 0 "register_operand" "+f")
- (match_operand:DF 1 "register_operand" "+f"))
+ [(set (match_operand:DF 0 "fp_register_operand" "+f")
+ (match_operand:DF 1 "fp_register_operand" "+f"))
(set (match_dup 1)
(match_dup 0))]
- "reload_completed || !TARGET_SSE2"
+ "reload_completed || TARGET_80387"
{
if (STACK_TOP_P (operands[0]))
return "fxch\t%1";
(match_operand:XF 1 "register_operand" "+f"))
(set (match_dup 1)
(match_dup 0))]
- ""
+ "TARGET_80387"
{
if (STACK_TOP_P (operands[0]))
return "fxch\t%1";
;; Moves for SSE/MMX regs.
-(define_insn "movv4sf_internal"
+(define_insn "*movv4sf_internal"
[(set (match_operand:V4SF 0 "nonimmediate_operand" "=x,x,m")
(match_operand:V4SF 1 "vector_move_operand" "C,xm,x"))]
"TARGET_SSE"
operands[2] = CONST0_RTX (V4SFmode);
})
-(define_insn "movv4si_internal"
+(define_insn "*movv4si_internal"
[(set (match_operand:V4SI 0 "nonimmediate_operand" "=x,x,m")
(match_operand:V4SI 1 "vector_move_operand" "C,xm,x"))]
"TARGET_SSE"
(const_string "TI"))]
(const_string "TI")))])
-(define_insn "movv2di_internal"
+(define_insn "*movv2di_internal"
[(set (match_operand:V2DI 0 "nonimmediate_operand" "=x,x,m")
(match_operand:V2DI 1 "vector_move_operand" "C,xm,x"))]
"TARGET_SSE"
operands[2] = CONST0_RTX (V2DFmode);
})
-(define_insn "movv8qi_internal"
+(define_insn "*movv8qi_internal"
[(set (match_operand:V8QI 0 "nonimmediate_operand" "=y,y,m,!y,!*Y,?*Y,?m")
(match_operand:V8QI 1 "vector_move_operand" "C,ym,y,*Y,y,*Ym,*Y"))]
"TARGET_MMX
[(set_attr "type" "mmxmov,mmxmov,mmxmov,ssecvt,ssecvt,ssemov,ssemov")
(set_attr "mode" "DI")])
-(define_insn "movv4hi_internal"
+(define_insn "*movv4hi_internal"
[(set (match_operand:V4HI 0 "nonimmediate_operand" "=y,y,m,!y,!*Y,?*Y,?m")
(match_operand:V4HI 1 "vector_move_operand" "C,ym,y,*Y,y,*Ym,*Y"))]
"TARGET_MMX
[(set_attr "type" "mmxmov,mmxmov,mmxmov,ssecvt,ssecvt,ssemov,ssemov")
(set_attr "mode" "DI")])
-(define_insn "movv2sf_internal"
+(define_insn "*movv2sf_internal"
[(set (match_operand:V2SF 0 "nonimmediate_operand" "=y,y,m,!y,!*Y,?*x,?m")
(match_operand:V2SF 1 "vector_move_operand" "C,ym,y,*Y,y,*xm,*x"))]
- "TARGET_3DNOW
+ "TARGET_MMX
&& (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
"@
pxor\t%0, %0
(match_operand:TF 1 "nonimmediate_operand" ""))]
"TARGET_64BIT"
{
- if (TARGET_64BIT)
- ix86_expand_move (TFmode, operands);
- else
- ix86_expand_vector_move (TFmode, operands);
+ ix86_expand_move (TFmode, operands);
DONE;
})
-(define_insn "movv2df_internal"
+(define_insn "*movv2df_internal"
[(set (match_operand:V2DF 0 "nonimmediate_operand" "=x,x,m")
(match_operand:V2DF 1 "vector_move_operand" "C,xm,x"))]
- "TARGET_SSE2
+ "TARGET_SSE
&& (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
{
switch (which_alternative)
}
[(set_attr "type" "ssemov")
(set (attr "mode")
- (cond [(eq_attr "alternative" "0,1")
+ (cond [(eq (symbol_ref "TARGET_SSE2") (const_int 0))
+ (const_string "V4SF")
+ (eq_attr "alternative" "0,1")
(if_then_else
(ne (symbol_ref "optimize_size")
(const_int 0))
(const_string "V2DF"))]
(const_string "V2DF")))])
-(define_insn "movv8hi_internal"
+(define_insn "*movv8hi_internal"
[(set (match_operand:V8HI 0 "nonimmediate_operand" "=x,x,m")
(match_operand:V8HI 1 "vector_move_operand" "C,xm,x"))]
- "TARGET_SSE2
+ "TARGET_SSE
&& (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
{
switch (which_alternative)
(const_string "TI"))]
(const_string "TI")))])
-(define_insn "movv16qi_internal"
+(define_insn "*movv16qi_internal"
[(set (match_operand:V16QI 0 "nonimmediate_operand" "=x,x,m")
(match_operand:V16QI 1 "vector_move_operand" "C,xm,x"))]
- "TARGET_SSE2
+ "TARGET_SSE
&& (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
{
switch (which_alternative)
(define_expand "movv2df"
[(set (match_operand:V2DF 0 "nonimmediate_operand" "")
(match_operand:V2DF 1 "nonimmediate_operand" ""))]
- "TARGET_SSE2"
+ "TARGET_SSE"
{
ix86_expand_vector_move (V2DFmode, operands);
DONE;
(define_expand "movv8hi"
[(set (match_operand:V8HI 0 "nonimmediate_operand" "")
(match_operand:V8HI 1 "nonimmediate_operand" ""))]
- "TARGET_SSE2"
+ "TARGET_SSE"
{
ix86_expand_vector_move (V8HImode, operands);
DONE;
(define_expand "movv16qi"
[(set (match_operand:V16QI 0 "nonimmediate_operand" "")
(match_operand:V16QI 1 "nonimmediate_operand" ""))]
- "TARGET_SSE2"
+ "TARGET_SSE"
{
ix86_expand_vector_move (V16QImode, operands);
DONE;
(define_expand "movv2sf"
[(set (match_operand:V2SF 0 "nonimmediate_operand" "")
(match_operand:V2SF 1 "nonimmediate_operand" ""))]
- "TARGET_3DNOW"
+ "TARGET_MMX"
{
ix86_expand_vector_move (V2SFmode, operands);
DONE;
(define_insn "*pushv2di"
[(set (match_operand:V2DI 0 "push_operand" "=<")
(match_operand:V2DI 1 "register_operand" "x"))]
- "TARGET_SSE2"
+ "TARGET_SSE"
"#")
(define_insn "*pushv8hi"
[(set (match_operand:V8HI 0 "push_operand" "=<")
(match_operand:V8HI 1 "register_operand" "x"))]
- "TARGET_SSE2"
+ "TARGET_SSE"
"#")
(define_insn "*pushv16qi"
[(set (match_operand:V16QI 0 "push_operand" "=<")
(match_operand:V16QI 1 "register_operand" "x"))]
- "TARGET_SSE2"
+ "TARGET_SSE"
"#")
(define_insn "*pushv4sf"
(define_insn "*pushv4si"
[(set (match_operand:V4SI 0 "push_operand" "=<")
(match_operand:V4SI 1 "register_operand" "x"))]
- "TARGET_SSE2"
+ "TARGET_SSE"
"#")
(define_insn "*pushv2si"
(define_insn "*pushv2sf"
[(set (match_operand:V2SF 0 "push_operand" "=<")
(match_operand:V2SF 1 "register_operand" "y"))]
- "TARGET_3DNOW"
+ "TARGET_MMX"
"#")
(define_split
operands[3] = GEN_INT (-GET_MODE_SIZE (GET_MODE (operands[0])));")
-(define_insn "movti_internal"
+(define_insn "*movti_internal"
[(set (match_operand:TI 0 "nonimmediate_operand" "=x,x,m")
(match_operand:TI 1 "vector_move_operand" "C,xm,x"))]
"TARGET_SSE && !TARGET_64BIT
[(set (match_operand:V2SI 0 "register_operand" "=y")
(gt:V2SI (match_operand:V2SF 1 "register_operand" "0")
(match_operand:V2SF 2 "nonimmediate_operand" "ym")))]
- "TARGET_3DNOW"
+ "TARGET_3DNOW"
"pfcmpgt\\t{%2, %0|%0, %2}"
[(set_attr "type" "mmxcmp")
(set_attr "mode" "V2SF")])