aboutsummaryrefslogtreecommitdiff
path: root/gcc/config
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config')
-rw-r--r--gcc/config/aarch64/aarch64-elf.h1
-rw-r--r--gcc/config/aarch64/aarch64-simd.md36
-rw-r--r--gcc/config/aarch64/aarch64.c24
-rw-r--r--gcc/config/aarch64/aarch64.md96
-rw-r--r--gcc/config/aarch64/t-aarch64-linux2
-rw-r--r--gcc/config/alpha/alpha.c3
-rw-r--r--gcc/config/arm/arm-protos.h2
-rw-r--r--gcc/config/arm/arm.c22
-rw-r--r--gcc/config/arm/arm.h11
-rw-r--r--gcc/config/arm/arm.md28
-rw-r--r--gcc/config/arm/arm.opt4
-rw-r--r--gcc/config/arm/iterators.md6
-rw-r--r--gcc/config/arm/neon.md164
-rw-r--r--gcc/config/avr/avr.c67
-rw-r--r--gcc/config/avr/avr.opt4
-rw-r--r--gcc/config/bfin/bfin.c6
-rw-r--r--gcc/config/c6x/c6x.c2
-rw-r--r--gcc/config/epiphany/epiphany.c2
-rw-r--r--gcc/config/frv/frv.c14
-rw-r--r--gcc/config/i386/constraints.md3
-rw-r--r--gcc/config/i386/cygwin.h6
-rw-r--r--gcc/config/i386/i386.md1055
-rw-r--r--gcc/config/i386/mmx.md333
-rw-r--r--gcc/config/i386/predicates.md3
-rw-r--r--gcc/config/ia64/ia64.c45
-rw-r--r--gcc/config/iq2000/iq2000.c15
-rw-r--r--gcc/config/mcore/mcore.c22
-rw-r--r--gcc/config/mep/mep.c26
-rw-r--r--gcc/config/microblaze/linux.h3
-rw-r--r--gcc/config/microblaze/microblaze-protos.h4
-rw-r--r--gcc/config/microblaze/microblaze.c596
-rw-r--r--gcc/config/microblaze/microblaze.h7
-rw-r--r--gcc/config/microblaze/microblaze.md19
-rw-r--r--gcc/config/microblaze/predicates.md57
-rw-r--r--gcc/config/mips/constraints.md114
-rw-r--r--gcc/config/mips/micromips.md125
-rw-r--r--gcc/config/mips/mips-cpus.def2
-rw-r--r--gcc/config/mips/mips-protos.h11
-rw-r--r--gcc/config/mips/mips-tables.opt174
-rw-r--r--gcc/config/mips/mips.c808
-rw-r--r--gcc/config/mips/mips.h51
-rw-r--r--gcc/config/mips/mips.md218
-rw-r--r--gcc/config/mips/mips.opt12
-rw-r--r--gcc/config/mips/predicates.md97
-rw-r--r--gcc/config/mips/sync.md50
-rw-r--r--gcc/config/mips/t-sde4
-rw-r--r--gcc/config/mmix/mmix.c2
-rw-r--r--gcc/config/mn10300/mn10300.c1
-rw-r--r--gcc/config/pa/pa.c73
-rw-r--r--gcc/config/rs6000/constraints.md17
-rw-r--r--gcc/config/rs6000/dfp.md315
-rw-r--r--gcc/config/rs6000/predicates.md27
-rw-r--r--gcc/config/rs6000/rs6000-cpus.def10
-rw-r--r--gcc/config/rs6000/rs6000-modes.def3
-rw-r--r--gcc/config/rs6000/rs6000.c473
-rw-r--r--gcc/config/rs6000/rs6000.h13
-rw-r--r--gcc/config/rs6000/rs6000.md863
-rw-r--r--gcc/config/rs6000/rs6000.opt4
-rw-r--r--gcc/config/rs6000/vector.md34
-rw-r--r--gcc/config/rs6000/vsx.md151
-rw-r--r--gcc/config/s390/s390.c44
-rw-r--r--gcc/config/sh/linux.h6
-rw-r--r--gcc/config/sh/netbsd-elf.h12
-rw-r--r--gcc/config/sh/sh.c3
-rw-r--r--gcc/config/sh/sh.h9
-rw-r--r--gcc/config/sh/sh.md14
-rw-r--r--gcc/config/sh/sh.opt6
-rw-r--r--gcc/config/sol2.c6
-rw-r--r--gcc/config/sparc/sparc.c12
-rw-r--r--gcc/config/sparc/sparc.md4
-rw-r--r--gcc/config/spu/spu.c6
-rw-r--r--gcc/config/stormy16/stormy16.c14
-rw-r--r--gcc/config/tilegx/sync.md46
-rw-r--r--gcc/config/v850/v850.c6
-rw-r--r--gcc/config/xtensa/xtensa.c2
75 files changed, 4276 insertions, 2254 deletions
diff --git a/gcc/config/aarch64/aarch64-elf.h b/gcc/config/aarch64/aarch64-elf.h
index db08031b178..3f3ae526a2a 100644
--- a/gcc/config/aarch64/aarch64-elf.h
+++ b/gcc/config/aarch64/aarch64-elf.h
@@ -106,7 +106,6 @@
#define ASM_COMMENT_START "//"
-#define REGISTER_PREFIX ""
#define LOCAL_LABEL_PREFIX "."
#define USER_LABEL_PREFIX ""
diff --git a/gcc/config/aarch64/aarch64-simd.md b/gcc/config/aarch64/aarch64-simd.md
index 0f0009505d8..92dcfc0c57b 100644
--- a/gcc/config/aarch64/aarch64-simd.md
+++ b/gcc/config/aarch64/aarch64-simd.md
@@ -44,6 +44,7 @@
; simd_dup duplicate element.
; simd_dupgp duplicate general purpose register.
; simd_ext bitwise extract from pair.
+; simd_fabd floating absolute difference and accumulate.
; simd_fadd floating point add/sub.
; simd_fcmp floating point compare.
; simd_fcvti floating point convert to integer.
@@ -147,6 +148,7 @@
simd_dup,\
simd_dupgp,\
simd_ext,\
+ simd_fabd,\
simd_fadd,\
simd_fcmp,\
simd_fcvti,\
@@ -520,6 +522,40 @@
(set_attr "simd_mode" "<MODE>")]
)
+(define_insn "abd<mode>_3"
+ [(set (match_operand:VDQ_BHSI 0 "register_operand" "=w")
+ (abs:VDQ_BHSI (minus:VDQ_BHSI
+ (match_operand:VDQ_BHSI 1 "register_operand" "w")
+ (match_operand:VDQ_BHSI 2 "register_operand" "w"))))]
+ "TARGET_SIMD"
+ "sabd\t%0.<Vtype>, %1.<Vtype>, %2.<Vtype>"
+ [(set_attr "simd_type" "simd_abd")
+ (set_attr "simd_mode" "<MODE>")]
+)
+
+(define_insn "aba<mode>_3"
+ [(set (match_operand:VDQ_BHSI 0 "register_operand" "=w")
+ (plus:VDQ_BHSI (abs:VDQ_BHSI (minus:VDQ_BHSI
+ (match_operand:VDQ_BHSI 1 "register_operand" "w")
+ (match_operand:VDQ_BHSI 2 "register_operand" "w")))
+ (match_operand:VDQ_BHSI 3 "register_operand" "0")))]
+ "TARGET_SIMD"
+ "saba\t%0.<Vtype>, %1.<Vtype>, %2.<Vtype>"
+ [(set_attr "simd_type" "simd_abd")
+ (set_attr "simd_mode" "<MODE>")]
+)
+
+(define_insn "fabd<mode>_3"
+ [(set (match_operand:VDQF 0 "register_operand" "=w")
+ (abs:VDQF (minus:VDQF
+ (match_operand:VDQF 1 "register_operand" "w")
+ (match_operand:VDQF 2 "register_operand" "w"))))]
+ "TARGET_SIMD"
+ "fabd\t%0.<Vtype>, %1.<Vtype>, %2.<Vtype>"
+ [(set_attr "simd_type" "simd_fabd")
+ (set_attr "simd_mode" "<MODE>")]
+)
+
(define_insn "and<mode>3"
[(set (match_operand:VDQ 0 "register_operand" "=w")
(and:VDQ (match_operand:VDQ 1 "register_operand" "w")
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 8c8532c97cc..343586e28c8 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -3086,7 +3086,7 @@ aarch64_select_cc_mode (RTX_CODE code, rtx x, rtx y)
if ((GET_MODE (x) == SImode || GET_MODE (x) == DImode)
&& y == const0_rtx
&& (code == EQ || code == NE || code == LT || code == GE)
- && (GET_CODE (x) == PLUS || GET_CODE (x) == MINUS))
+ && (GET_CODE (x) == PLUS || GET_CODE (x) == MINUS || GET_CODE (x) == AND))
return CC_NZmode;
/* A compare with a shifted operand. Because of canonicalization,
@@ -3348,7 +3348,7 @@ aarch64_print_operand (FILE *f, rtx x, char code)
output_operand_lossage ("incompatible floating point / vector register operand for '%%%c'", code);
return;
}
- asm_fprintf (f, "%s%c%d", REGISTER_PREFIX, code, REGNO (x) - V0_REGNUM);
+ asm_fprintf (f, "%c%d", code, REGNO (x) - V0_REGNUM);
break;
case 'S':
@@ -3361,8 +3361,17 @@ aarch64_print_operand (FILE *f, rtx x, char code)
output_operand_lossage ("incompatible floating point / vector register operand for '%%%c'", code);
return;
}
- asm_fprintf (f, "%sv%d", REGISTER_PREFIX,
- REGNO (x) - V0_REGNUM + (code - 'S'));
+ asm_fprintf (f, "v%d", REGNO (x) - V0_REGNUM + (code - 'S'));
+ break;
+
+ case 'X':
+ /* Print integer constant in hex. */
+ if (GET_CODE (x) != CONST_INT)
+ {
+ output_operand_lossage ("invalid operand for '%%%c'", code);
+ return;
+ }
+ asm_fprintf (f, "0x%x", UINTVAL (x));
break;
case 'w':
@@ -3372,20 +3381,19 @@ aarch64_print_operand (FILE *f, rtx x, char code)
if (x == const0_rtx
|| (CONST_DOUBLE_P (x) && aarch64_float_const_zero_rtx_p (x)))
{
- asm_fprintf (f, "%s%czr", REGISTER_PREFIX, code);
+ asm_fprintf (f, "%czr", code);
break;
}
if (REG_P (x) && GP_REGNUM_P (REGNO (x)))
{
- asm_fprintf (f, "%s%c%d", REGISTER_PREFIX, code,
- REGNO (x) - R0_REGNUM);
+ asm_fprintf (f, "%c%d", code, REGNO (x) - R0_REGNUM);
break;
}
if (REG_P (x) && REGNO (x) == SP_REGNUM)
{
- asm_fprintf (f, "%s%ssp", REGISTER_PREFIX, code == 'w' ? "w" : "");
+ asm_fprintf (f, "%ssp", code == 'w' ? "w" : "");
break;
}
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 73d86a7a184..c28f4a013dc 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -844,8 +844,8 @@
(match_operand:GPI 2 "const_int_operand" "n"))]
"INTVAL (operands[1]) < GET_MODE_BITSIZE (<MODE>mode)
&& INTVAL (operands[1]) % 16 == 0
- && INTVAL (operands[2]) <= 0xffff"
- "movk\\t%<w>0, %2, lsl %1"
+ && UINTVAL (operands[2]) <= 0xffff"
+ "movk\\t%<w>0, %X2, lsl %1"
[(set_attr "v8type" "movk")
(set_attr "mode" "<MODE>")]
)
@@ -1790,6 +1790,34 @@
(set_attr "mode" "SI")]
)
+(define_insn "*sub<mode>3_carryin"
+ [(set
+ (match_operand:GPI 0 "register_operand" "=r")
+ (minus:GPI (minus:GPI
+ (match_operand:GPI 1 "register_operand" "r")
+ (ltu:GPI (reg:CC CC_REGNUM) (const_int 0)))
+ (match_operand:GPI 2 "register_operand" "r")))]
+ ""
+ "sbc\\t%<w>0, %<w>1, %<w>2"
+ [(set_attr "v8type" "adc")
+ (set_attr "mode" "<MODE>")]
+)
+
+;; zero_extend version of the above
+(define_insn "*subsi3_carryin_uxtw"
+ [(set
+ (match_operand:DI 0 "register_operand" "=r")
+ (zero_extend:DI
+ (minus:SI (minus:SI
+ (match_operand:SI 1 "register_operand" "r")
+ (ltu:SI (reg:CC CC_REGNUM) (const_int 0)))
+ (match_operand:SI 2 "register_operand" "r"))))]
+ ""
+ "sbc\\t%w0, %w1, %w2"
+ [(set_attr "v8type" "adc")
+ (set_attr "mode" "SI")]
+)
+
(define_insn "*sub_uxt<mode>_multp2"
[(set (match_operand:GPI 0 "register_operand" "=rk")
(minus:GPI (match_operand:GPI 4 "register_operand" "r")
@@ -2547,8 +2575,8 @@
)
(define_insn "*and<mode>3nr_compare0"
- [(set (reg:CC CC_REGNUM)
- (compare:CC
+ [(set (reg:CC_NZ CC_REGNUM)
+ (compare:CC_NZ
(and:GPI (match_operand:GPI 0 "register_operand" "%r,r")
(match_operand:GPI 1 "aarch64_logical_operand" "r,<lconst>"))
(const_int 0)))]
@@ -2558,8 +2586,8 @@
(set_attr "mode" "<MODE>")])
(define_insn "*and_<SHIFT:optab><mode>3nr_compare0"
- [(set (reg:CC CC_REGNUM)
- (compare:CC
+ [(set (reg:CC_NZ CC_REGNUM)
+ (compare:CC_NZ
(and:GPI (SHIFT:GPI
(match_operand:GPI 0 "register_operand" "r")
(match_operand:QI 1 "aarch64_shift_imm_<mode>" "n"))
@@ -2703,6 +2731,62 @@
(set_attr "mode" "<MODE>")]
)
+(define_insn "*extr<mode>5_insn"
+ [(set (match_operand:GPI 0 "register_operand" "=r")
+ (ior:GPI (ashift:GPI (match_operand:GPI 1 "register_operand" "r")
+ (match_operand 3 "const_int_operand" "n"))
+ (lshiftrt:GPI (match_operand:GPI 2 "register_operand" "r")
+ (match_operand 4 "const_int_operand" "n"))))]
+ "UINTVAL (operands[3]) < GET_MODE_BITSIZE (<MODE>mode) &&
+ (UINTVAL (operands[3]) + UINTVAL (operands[4]) == GET_MODE_BITSIZE (<MODE>mode))"
+ "extr\\t%<w>0, %<w>1, %<w>2, %4"
+ [(set_attr "v8type" "shift")
+ (set_attr "mode" "<MODE>")]
+)
+
+;; zero_extend version of the above
+(define_insn "*extrsi5_insn_uxtw"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (zero_extend:DI
+ (ior:SI (ashift:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand 3 "const_int_operand" "n"))
+ (lshiftrt:SI (match_operand:SI 2 "register_operand" "r")
+ (match_operand 4 "const_int_operand" "n")))))]
+ "UINTVAL (operands[3]) < 32 &&
+ (UINTVAL (operands[3]) + UINTVAL (operands[4]) == 32)"
+ "extr\\t%w0, %w1, %w2, %4"
+ [(set_attr "v8type" "shift")
+ (set_attr "mode" "SI")]
+)
+
+(define_insn "*ror<mode>3_insn"
+ [(set (match_operand:GPI 0 "register_operand" "=r")
+ (rotate:GPI (match_operand:GPI 1 "register_operand" "r")
+ (match_operand 2 "const_int_operand" "n")))]
+ "UINTVAL (operands[2]) < GET_MODE_BITSIZE (<MODE>mode)"
+{
+ operands[3] = GEN_INT (<sizen> - UINTVAL (operands[2]));
+ return "ror\\t%<w>0, %<w>1, %3";
+}
+ [(set_attr "v8type" "shift")
+ (set_attr "mode" "<MODE>")]
+)
+
+;; zero_extend version of the above
+(define_insn "*rorsi3_insn_uxtw"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (zero_extend:DI
+ (rotate:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand 2 "const_int_operand" "n"))))]
+ "UINTVAL (operands[2]) < 32"
+{
+ operands[3] = GEN_INT (32 - UINTVAL (operands[2]));
+ return "ror\\t%w0, %w1, %3";
+}
+ [(set_attr "v8type" "shift")
+ (set_attr "mode" "SI")]
+)
+
(define_insn "*<ANY_EXTEND:optab><GPI:mode>_ashl<SHORT:mode>"
[(set (match_operand:GPI 0 "register_operand" "=r")
(ANY_EXTEND:GPI
diff --git a/gcc/config/aarch64/t-aarch64-linux b/gcc/config/aarch64/t-aarch64-linux
index 48b4c69f6b4..a7a0a883605 100644
--- a/gcc/config/aarch64/t-aarch64-linux
+++ b/gcc/config/aarch64/t-aarch64-linux
@@ -22,4 +22,4 @@ LIB1ASMSRC = aarch64/lib1funcs.asm
LIB1ASMFUNCS = _aarch64_sync_cache_range
AARCH_BE = $(if $(findstring TARGET_BIG_ENDIAN_DEFAULT=1, $(tm_defines)),_be)
-MULTIARCH_DIRNAME = $(call if_multiarch,aarch64$(AARCH_BE)-linux-gnu)
+MULTILIB_OSDIRNAMES = .=../lib64$(call if_multiarch,:aarch64$(AARCH_BE)-linux-gnu)
diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c
index 6926055f206..15cfd5ea866 100644
--- a/gcc/config/alpha/alpha.c
+++ b/gcc/config/alpha/alpha.c
@@ -9872,6 +9872,9 @@ alpha_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
#undef TARGET_LEGITIMATE_ADDRESS_P
#define TARGET_LEGITIMATE_ADDRESS_P alpha_legitimate_address_p
+#undef TARGET_LRA_P
+#define TARGET_LRA_P hook_bool_void_true
+
#undef TARGET_CONDITIONAL_REGISTER_USAGE
#define TARGET_CONDITIONAL_REGISTER_USAGE alpha_conditional_register_usage
diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index ffa00c0f7b7..694aa2802ae 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -269,6 +269,8 @@ struct tune_params
bool logical_op_non_short_circuit[2];
/* Vectorizer costs. */
const struct cpu_vec_costs* vec_costs;
+ /* Prefer Neon for 64-bit bitops. */
+ bool prefer_neon_for_64bits;
};
extern const struct tune_params *current_tune;
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 36b86dd760c..567b75ece9c 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -840,6 +840,10 @@ int arm_arch_thumb2;
int arm_arch_arm_hwdiv;
int arm_arch_thumb_hwdiv;
+/* Nonzero if we should use Neon to handle 64-bits operations rather
+ than core registers. */
+int prefer_neon_for_64bits = 0;
+
/* In case of a PRE_INC, POST_INC, PRE_DEC, POST_DEC memory reference,
we must report the mode of the memory reference from
TARGET_PRINT_OPERAND to TARGET_PRINT_OPERAND_ADDRESS. */
@@ -937,6 +941,7 @@ const struct tune_params arm_slowmul_tune =
false, /* Prefer LDRD/STRD. */
{true, true}, /* Prefer non short circuit. */
&arm_default_vec_cost, /* Vectorizer costs. */
+ false /* Prefer Neon for 64-bits bitops. */
};
const struct tune_params arm_fastmul_tune =
@@ -951,6 +956,7 @@ const struct tune_params arm_fastmul_tune =
false, /* Prefer LDRD/STRD. */
{true, true}, /* Prefer non short circuit. */
&arm_default_vec_cost, /* Vectorizer costs. */
+ false /* Prefer Neon for 64-bits bitops. */
};
/* StrongARM has early execution of branches, so a sequence that is worth
@@ -968,6 +974,7 @@ const struct tune_params arm_strongarm_tune =
false, /* Prefer LDRD/STRD. */
{true, true}, /* Prefer non short circuit. */
&arm_default_vec_cost, /* Vectorizer costs. */
+ false /* Prefer Neon for 64-bits bitops. */
};
const struct tune_params arm_xscale_tune =
@@ -982,6 +989,7 @@ const struct tune_params arm_xscale_tune =
false, /* Prefer LDRD/STRD. */
{true, true}, /* Prefer non short circuit. */
&arm_default_vec_cost, /* Vectorizer costs. */
+ false /* Prefer Neon for 64-bits bitops. */
};
const struct tune_params arm_9e_tune =
@@ -996,6 +1004,7 @@ const struct tune_params arm_9e_tune =
false, /* Prefer LDRD/STRD. */
{true, true}, /* Prefer non short circuit. */
&arm_default_vec_cost, /* Vectorizer costs. */
+ false /* Prefer Neon for 64-bits bitops. */
};
const struct tune_params arm_v6t2_tune =
@@ -1010,6 +1019,7 @@ const struct tune_params arm_v6t2_tune =
false, /* Prefer LDRD/STRD. */
{true, true}, /* Prefer non short circuit. */
&arm_default_vec_cost, /* Vectorizer costs. */
+ false /* Prefer Neon for 64-bits bitops. */
};
/* Generic Cortex tuning. Use more specific tunings if appropriate. */
@@ -1025,6 +1035,7 @@ const struct tune_params arm_cortex_tune =
false, /* Prefer LDRD/STRD. */
{true, true}, /* Prefer non short circuit. */
&arm_default_vec_cost, /* Vectorizer costs. */
+ false /* Prefer Neon for 64-bits bitops. */
};
const struct tune_params arm_cortex_a15_tune =
@@ -1039,6 +1050,7 @@ const struct tune_params arm_cortex_a15_tune =
true, /* Prefer LDRD/STRD. */
{true, true}, /* Prefer non short circuit. */
&arm_default_vec_cost, /* Vectorizer costs. */
+ false /* Prefer Neon for 64-bits bitops. */
};
/* Branches can be dual-issued on Cortex-A5, so conditional execution is
@@ -1056,6 +1068,7 @@ const struct tune_params arm_cortex_a5_tune =
false, /* Prefer LDRD/STRD. */
{false, false}, /* Prefer non short circuit. */
&arm_default_vec_cost, /* Vectorizer costs. */
+ false /* Prefer Neon for 64-bits bitops. */
};
const struct tune_params arm_cortex_a9_tune =
@@ -1070,6 +1083,7 @@ const struct tune_params arm_cortex_a9_tune =
false, /* Prefer LDRD/STRD. */
{true, true}, /* Prefer non short circuit. */
&arm_default_vec_cost, /* Vectorizer costs. */
+ false /* Prefer Neon for 64-bits bitops. */
};
/* The arm_v6m_tune is duplicated from arm_cortex_tune, rather than
@@ -1086,6 +1100,7 @@ const struct tune_params arm_v6m_tune =
false, /* Prefer LDRD/STRD. */
{false, false}, /* Prefer non short circuit. */
&arm_default_vec_cost, /* Vectorizer costs. */
+ false /* Prefer Neon for 64-bits bitops. */
};
const struct tune_params arm_fa726te_tune =
@@ -1100,6 +1115,7 @@ const struct tune_params arm_fa726te_tune =
false, /* Prefer LDRD/STRD. */
{true, true}, /* Prefer non short circuit. */
&arm_default_vec_cost, /* Vectorizer costs. */
+ false /* Prefer Neon for 64-bits bitops. */
};
@@ -2130,6 +2146,12 @@ arm_option_override (void)
global_options.x_param_values,
global_options_set.x_param_values);
+ /* Use Neon to perform 64-bits operations rather than core
+ registers. */
+ prefer_neon_for_64bits = current_tune->prefer_neon_for_64bits;
+ if (use_neon_for_64bits == 1)
+ prefer_neon_for_64bits = true;
+
/* Use the alternative scheduling-pressure algorithm by default. */
maybe_set_param_value (PARAM_SCHED_PRESSURE_ALGORITHM, 2,
global_options.x_param_values,
diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index 6d336e89ee9..04bff13368e 100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -354,6 +354,9 @@ extern void (*arm_lang_output_object_attributes_hook)(void);
#define TARGET_IDIV ((TARGET_ARM && arm_arch_arm_hwdiv) \
|| (TARGET_THUMB2 && arm_arch_thumb_hwdiv))
+/* Should NEON be used for 64-bits bitops. */
+#define TARGET_PREFER_NEON_64BITS (prefer_neon_for_64bits)
+
/* True iff the full BPABI is being used. If TARGET_BPABI is true,
then TARGET_AAPCS_BASED must be true -- but the converse does not
hold. TARGET_BPABI implies the use of the BPABI runtime library,
@@ -539,6 +542,10 @@ extern int arm_arch_arm_hwdiv;
/* Nonzero if chip supports integer division instruction in Thumb mode. */
extern int arm_arch_thumb_hwdiv;
+/* Nonzero if we should use Neon to handle 64-bits operations rather
+ than core registers. */
+extern int prefer_neon_for_64bits;
+
#ifndef TARGET_DEFAULT
#define TARGET_DEFAULT (MASK_APCS_FRAME)
#endif
@@ -1166,7 +1173,9 @@ enum reg_class
"IWMMXT_GR_REGS", \
"CC_REG", \
"VFPCC_REG", \
- "ALL_REGS", \
+ "SFP_REG", \
+ "AFP_REG", \
+ "ALL_REGS" \
}
/* Define which registers fit in which classes.
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index f3c59f37c85..d48bc8c0123 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -94,7 +94,7 @@
; for ARM or Thumb-2 with arm_arch6, and nov6 for ARM without
; arm_arch6. This attribute is used to compute attribute "enabled",
; use type "any" to enable an alternative in all cases.
-(define_attr "arch" "any,a,t,32,t1,t2,v6,nov6,onlya8,neon_onlya8,nota8,neon_nota8,iwmmxt,iwmmxt2"
+(define_attr "arch" "any,a,t,32,t1,t2,v6,nov6,neon_for_64bits,avoid_neon_for_64bits,iwmmxt,iwmmxt2"
(const_string "any"))
(define_attr "arch_enabled" "no,yes"
@@ -129,22 +129,14 @@
(match_test "TARGET_32BIT && !arm_arch6"))
(const_string "yes")
- (and (eq_attr "arch" "onlya8")
- (eq_attr "tune" "cortexa8"))
+ (and (eq_attr "arch" "avoid_neon_for_64bits")
+ (match_test "TARGET_NEON")
+ (not (match_test "TARGET_PREFER_NEON_64BITS")))
(const_string "yes")
- (and (eq_attr "arch" "neon_onlya8")
- (eq_attr "tune" "cortexa8")
- (match_test "TARGET_NEON"))
- (const_string "yes")
-
- (and (eq_attr "arch" "nota8")
- (not (eq_attr "tune" "cortexa8")))
- (const_string "yes")
-
- (and (eq_attr "arch" "neon_nota8")
- (not (eq_attr "tune" "cortexa8"))
- (match_test "TARGET_NEON"))
+ (and (eq_attr "arch" "neon_for_64bits")
+ (match_test "TARGET_NEON")
+ (match_test "TARGET_PREFER_NEON_64BITS"))
(const_string "yes")
(and (eq_attr "arch" "iwmmxt2")
@@ -4330,7 +4322,7 @@
[(set_attr "length" "*,8,8,*")
(set_attr "predicable" "no,yes,yes,no")
(set_attr "neon_type" "neon_int_1,*,*,neon_int_1")
- (set_attr "arch" "neon_nota8,*,*,neon_onlya8")]
+ (set_attr "arch" "neon_for_64bits,*,*,avoid_neon_for_64bits")]
)
(define_expand "one_cmplsi2"
@@ -4498,7 +4490,7 @@
"TARGET_32BIT <qhs_zextenddi_cond>"
"#"
[(set_attr "length" "8,4,8,8")
- (set_attr "arch" "neon_nota8,*,*,neon_onlya8")
+ (set_attr "arch" "neon_for_64bits,*,*,avoid_neon_for_64bits")
(set_attr "ce_count" "2")
(set_attr "predicable" "yes")]
)
@@ -4513,7 +4505,7 @@
(set_attr "ce_count" "2")
(set_attr "shift" "1")
(set_attr "predicable" "yes")
- (set_attr "arch" "neon_nota8,*,a,t,neon_onlya8")]
+ (set_attr "arch" "neon_for_64bits,*,a,t,avoid_neon_for_64bits")]
)
;; Splits for all extensions to DImode
diff --git a/gcc/config/arm/arm.opt b/gcc/config/arm/arm.opt
index e778407ab4c..afb42421c06 100644
--- a/gcc/config/arm/arm.opt
+++ b/gcc/config/arm/arm.opt
@@ -247,3 +247,7 @@ that may trigger Cortex-M3 errata.
munaligned-access
Target Report Var(unaligned_access) Init(2)
Enable unaligned word and halfword accesses to packed data.
+
+mneon-for-64bits
+Target Report RejectNegative Var(use_neon_for_64bits) Init(0)
+Use Neon to perform 64-bits operations rather than core registers.
diff --git a/gcc/config/arm/iterators.md b/gcc/config/arm/iterators.md
index 252f18b40a8..b3ad42b376f 100644
--- a/gcc/config/arm/iterators.md
+++ b/gcc/config/arm/iterators.md
@@ -314,6 +314,12 @@
(V2SF "V2SI") (V4SF "V4SI")
(DI "DI") (V2DI "V2DI")])
+(define_mode_attr v_cmp_result [(V8QI "v8qi") (V16QI "v16qi")
+ (V4HI "v4hi") (V8HI "v8hi")
+ (V2SI "v2si") (V4SI "v4si")
+ (DI "di") (V2DI "v2di")
+ (V2SF "v2si") (V4SF "v4si")])
+
;; Get element type from double-width mode, for operations where we
;; don't care about signedness.
(define_mode_attr V_if_elem [(V8QI "i8") (V16QI "i8")
diff --git a/gcc/config/arm/neon.md b/gcc/config/arm/neon.md
index 79b3f667c17..d7c2cb36949 100644
--- a/gcc/config/arm/neon.md
+++ b/gcc/config/arm/neon.md
@@ -487,7 +487,7 @@
[(set_attr "neon_type" "neon_int_1,*,*,neon_int_1,*,*,*")
(set_attr "conds" "*,clob,clob,*,clob,clob,clob")
(set_attr "length" "*,8,8,*,8,8,8")
- (set_attr "arch" "nota8,*,*,onlya8,*,*,*")]
+ (set_attr "arch" "neon_for_64bits,*,*,avoid_neon_for_64bits,*,*,*")]
)
(define_insn "*sub<mode>3_neon"
@@ -524,7 +524,7 @@
[(set_attr "neon_type" "neon_int_2,*,*,*,neon_int_2")
(set_attr "conds" "*,clob,clob,clob,*")
(set_attr "length" "*,8,8,8,*")
- (set_attr "arch" "nota8,*,*,*,onlya8")]
+ (set_attr "arch" "neon_for_64bits,*,*,*,avoid_neon_for_64bits")]
)
(define_insn "*mul<mode>3_neon"
@@ -699,7 +699,7 @@
}
[(set_attr "neon_type" "neon_int_1,neon_int_1,*,*,neon_int_1,neon_int_1")
(set_attr "length" "*,*,8,8,*,*")
- (set_attr "arch" "nota8,nota8,*,*,onlya8,onlya8")]
+ (set_attr "arch" "neon_for_64bits,neon_for_64bits,*,*,avoid_neon_for_64bits,avoid_neon_for_64bits")]
)
;; The concrete forms of the Neon immediate-logic instructions are vbic and
@@ -744,7 +744,7 @@
}
[(set_attr "neon_type" "neon_int_1,neon_int_1,*,*,neon_int_1,neon_int_1")
(set_attr "length" "*,*,8,8,*,*")
- (set_attr "arch" "nota8,nota8,*,*,onlya8,onlya8")]
+ (set_attr "arch" "neon_for_64bits,neon_for_64bits,*,*,avoid_neon_for_64bits,avoid_neon_for_64bits")]
)
(define_insn "orn<mode>3_neon"
@@ -840,7 +840,7 @@
veor\t%P0, %P1, %P2"
[(set_attr "neon_type" "neon_int_1,*,*,neon_int_1")
(set_attr "length" "*,8,8,*")
- (set_attr "arch" "nota8,*,*,onlya8")]
+ (set_attr "arch" "neon_for_64bits,*,*,avoid_neon_for_64bits")]
)
(define_insn "one_cmpl<mode>2"
@@ -1162,7 +1162,7 @@
}
DONE;
}"
- [(set_attr "arch" "nota8,nota8,*,*,onlya8,onlya8")
+ [(set_attr "arch" "neon_for_64bits,neon_for_64bits,*,*,avoid_neon_for_64bits,avoid_neon_for_64bits")
(set_attr "opt" "*,*,speed,speed,*,*")]
)
@@ -1263,7 +1263,7 @@
DONE;
}"
- [(set_attr "arch" "nota8,nota8,*,*,onlya8,onlya8")
+ [(set_attr "arch" "neon_for_64bits,neon_for_64bits,*,*,avoid_neon_for_64bits,avoid_neon_for_64bits")
(set_attr "opt" "*,*,speed,speed,*,*")]
)
@@ -1721,80 +1721,144 @@
(define_expand "vcond<mode><mode>"
[(set (match_operand:VDQW 0 "s_register_operand" "")
(if_then_else:VDQW
- (match_operator 3 "arm_comparison_operator"
+ (match_operator 3 "comparison_operator"
[(match_operand:VDQW 4 "s_register_operand" "")
(match_operand:VDQW 5 "nonmemory_operand" "")])
(match_operand:VDQW 1 "s_register_operand" "")
(match_operand:VDQW 2 "s_register_operand" "")))]
"TARGET_NEON && (!<Is_float_mode> || flag_unsafe_math_optimizations)"
{
- rtx mask;
- int inverse = 0, immediate_zero = 0;
- /* See the description of "magic" bits in the 'T' case of
- arm_print_operand. */
HOST_WIDE_INT magic_word = (<MODE>mode == V2SFmode || <MODE>mode == V4SFmode)
? 3 : 1;
rtx magic_rtx = GEN_INT (magic_word);
-
- mask = gen_reg_rtx (<V_cmp_result>mode);
-
- if (operands[5] == CONST0_RTX (<MODE>mode))
- immediate_zero = 1;
- else if (!REG_P (operands[5]))
- operands[5] = force_reg (<MODE>mode, operands[5]);
-
+ int inverse = 0;
+ int swap_bsl_operands = 0;
+ rtx mask = gen_reg_rtx (<V_cmp_result>mode);
+ rtx tmp = gen_reg_rtx (<V_cmp_result>mode);
+
+ rtx (*base_comparison) (rtx, rtx, rtx, rtx);
+ rtx (*complimentary_comparison) (rtx, rtx, rtx, rtx);
+
switch (GET_CODE (operands[3]))
{
case GE:
- emit_insn (gen_neon_vcge<mode> (mask, operands[4], operands[5],
- magic_rtx));
+ case LE:
+ case EQ:
+ if (!REG_P (operands[5])
+ && (operands[5] != CONST0_RTX (<MODE>mode)))
+ operands[5] = force_reg (<MODE>mode, operands[5]);
break;
-
+ default:
+ if (!REG_P (operands[5]))
+ operands[5] = force_reg (<MODE>mode, operands[5]);
+ }
+
+ switch (GET_CODE (operands[3]))
+ {
+ case LT:
+ case UNLT:
+ inverse = 1;
+ /* Fall through. */
+ case GE:
+ case UNGE:
+ case ORDERED:
+ case UNORDERED:
+ base_comparison = gen_neon_vcge<mode>;
+ complimentary_comparison = gen_neon_vcgt<mode>;
+ break;
+ case LE:
+ case UNLE:
+ inverse = 1;
+ /* Fall through. */
case GT:
- emit_insn (gen_neon_vcgt<mode> (mask, operands[4], operands[5],
- magic_rtx));
+ case UNGT:
+ base_comparison = gen_neon_vcgt<mode>;
+ complimentary_comparison = gen_neon_vcge<mode>;
break;
-
case EQ:
- emit_insn (gen_neon_vceq<mode> (mask, operands[4], operands[5],
- magic_rtx));
+ case NE:
+ case UNEQ:
+ base_comparison = gen_neon_vceq<mode>;
+ complimentary_comparison = gen_neon_vceq<mode>;
break;
-
+ default:
+ gcc_unreachable ();
+ }
+
+ switch (GET_CODE (operands[3]))
+ {
+ case LT:
case LE:
- if (immediate_zero)
- emit_insn (gen_neon_vcle<mode> (mask, operands[4], operands[5],
- magic_rtx));
+ case GT:
+ case GE:
+ case EQ:
+ /* The easy case. Here we emit one of vcge, vcgt or vceq.
+ As a LT b <=> b GE a && a LE b <=> b GT a. Our transformations are:
+ a GE b -> a GE b
+ a GT b -> a GT b
+ a LE b -> b GE a
+ a LT b -> b GT a
+ a EQ b -> a EQ b */
+
+ if (!inverse)
+ emit_insn (base_comparison (mask, operands[4], operands[5], magic_rtx));
else
- emit_insn (gen_neon_vcge<mode> (mask, operands[5], operands[4],
- magic_rtx));
+ emit_insn (complimentary_comparison (mask, operands[5], operands[4], magic_rtx));
break;
-
- case LT:
- if (immediate_zero)
- emit_insn (gen_neon_vclt<mode> (mask, operands[4], operands[5],
- magic_rtx));
+ case UNLT:
+ case UNLE:
+ case UNGT:
+ case UNGE:
+ case NE:
+ /* Vector compare returns false for lanes which are unordered, so if we use
+ the inverse of the comparison we actually want to emit, then
+ swap the operands to BSL, we will end up with the correct result.
+ Note that a NE NaN and NaN NE b are true for all a, b.
+
+ Our transformations are:
+ a GE b -> !(b GT a)
+ a GT b -> !(b GE a)
+ a LE b -> !(a GT b)
+ a LT b -> !(a GE b)
+ a NE b -> !(a EQ b) */
+
+ if (inverse)
+ emit_insn (base_comparison (mask, operands[4], operands[5], magic_rtx));
else
- emit_insn (gen_neon_vcgt<mode> (mask, operands[5], operands[4],
- magic_rtx));
+ emit_insn (complimentary_comparison (mask, operands[5], operands[4], magic_rtx));
+
+ swap_bsl_operands = 1;
break;
-
- case NE:
- emit_insn (gen_neon_vceq<mode> (mask, operands[4], operands[5],
- magic_rtx));
- inverse = 1;
+ case UNEQ:
+ /* We check (a > b || b > a). combining these comparisons give us
+ true iff !(a != b && a ORDERED b), swapping the operands to BSL
+ will then give us (a == b || a UNORDERED b) as intended. */
+
+ emit_insn (gen_neon_vcgt<mode> (mask, operands[4], operands[5], magic_rtx));
+ emit_insn (gen_neon_vcgt<mode> (tmp, operands[5], operands[4], magic_rtx));
+ emit_insn (gen_ior<v_cmp_result>3 (mask, mask, tmp));
+ swap_bsl_operands = 1;
+ break;
+ case UNORDERED:
+ /* Operands are ORDERED iff (a > b || b >= a).
+ Swapping the operands to BSL will give the UNORDERED case. */
+ swap_bsl_operands = 1;
+ /* Fall through. */
+ case ORDERED:
+ emit_insn (gen_neon_vcgt<mode> (tmp, operands[4], operands[5], magic_rtx));
+ emit_insn (gen_neon_vcge<mode> (mask, operands[5], operands[4], magic_rtx));
+ emit_insn (gen_ior<v_cmp_result>3 (mask, mask, tmp));
break;
-
default:
gcc_unreachable ();
}
-
- if (inverse)
+
+ if (swap_bsl_operands)
emit_insn (gen_neon_vbsl<mode> (operands[0], mask, operands[2],
operands[1]));
else
emit_insn (gen_neon_vbsl<mode> (operands[0], mask, operands[1],
operands[2]));
-
DONE;
})
diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c
index a35f47e83d6..3f2b54a169c 100644
--- a/gcc/config/avr/avr.c
+++ b/gcc/config/avr/avr.c
@@ -7629,9 +7629,9 @@ _reg_unused_after (rtx insn, rtx reg)
rtx this_insn = XVECEXP (PATTERN (insn), 0, i);
rtx set = single_set (this_insn);
- if (GET_CODE (this_insn) == CALL_INSN)
+ if (CALL_P (this_insn))
code = CALL_INSN;
- else if (GET_CODE (this_insn) == JUMP_INSN)
+ else if (JUMP_P (this_insn))
{
if (INSN_ANNULLED_BRANCH_P (this_insn))
return 0;
@@ -10765,6 +10765,66 @@ avr_addr_space_subset_p (addr_space_t subset ATTRIBUTE_UNUSED,
}
+/* Implement `TARGET_CONVERT_TO_TYPE'. */
+
+static tree
+avr_convert_to_type (tree type, tree expr)
+{
+ /* Print a diagnose for pointer conversion that changes the address
+ space of the pointer target to a non-enclosing address space,
+ provided -Waddr-space-convert is on.
+
+ FIXME: Filter out cases where the target object is known to
+ be located in the right memory, like in
+
+ (const __flash*) PSTR ("text")
+
+ Also try to distinguish between explicit casts requested by
+ the user and implicit casts like
+
+ void f (const __flash char*);
+
+ void g (const char *p)
+ {
+ f ((const __flash*) p);
+ }
+
+ under the assumption that an explicit casts means that the user
+ knows what he is doing, e.g. interface with PSTR or old style
+ code with progmem and pgm_read_xxx.
+ */
+
+ if (avr_warn_addr_space_convert
+ && expr != error_mark_node
+ && POINTER_TYPE_P (type)
+ && POINTER_TYPE_P (TREE_TYPE (expr)))
+ {
+ addr_space_t as_old = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (expr)));
+ addr_space_t as_new = TYPE_ADDR_SPACE (TREE_TYPE (type));
+
+ if (avr_log.progmem)
+ avr_edump ("%?: type = %t\nexpr = %t\n\n", type, expr);
+
+ if (as_new != ADDR_SPACE_MEMX
+ && as_new != as_old)
+ {
+ location_t loc = EXPR_LOCATION (expr);
+ const char *name_old = avr_addrspace[as_old].name;
+ const char *name_new = avr_addrspace[as_new].name;
+
+ warning (OPT_Waddr_space_convert,
+ "conversion from address space %qs to address space %qs",
+ ADDR_SPACE_GENERIC_P (as_old) ? "generic" : name_old,
+ ADDR_SPACE_GENERIC_P (as_new) ? "generic" : name_new);
+
+ return fold_build1_loc (loc, ADDR_SPACE_CONVERT_EXPR, type, expr);
+ }
+ }
+
+ return NULL_TREE;
+}
+
+
/* Worker function for movmemhi expander.
XOP[0] Destination as MEM:BLK
XOP[1] Source " "
@@ -12149,6 +12209,9 @@ avr_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED, tree *arg,
#undef TARGET_FIXED_POINT_SUPPORTED_P
#define TARGET_FIXED_POINT_SUPPORTED_P hook_bool_void_true
+#undef TARGET_CONVERT_TO_TYPE
+#define TARGET_CONVERT_TO_TYPE avr_convert_to_type
+
#undef TARGET_ADDR_SPACE_SUBSET_P
#define TARGET_ADDR_SPACE_SUBSET_P avr_addr_space_subset_p
diff --git a/gcc/config/avr/avr.opt b/gcc/config/avr/avr.opt
index 134a1d4d0d7..6b2e755eeb2 100644
--- a/gcc/config/avr/avr.opt
+++ b/gcc/config/avr/avr.opt
@@ -74,3 +74,7 @@ When accessing RAM, use X as imposed by the hardware, i.e. just use pre-decremen
msp8
Target Report RejectNegative Var(avr_sp8) Init(0)
The device has no SPH special function register. This option will be overridden by the compiler driver with the correct setting if presence/absence of SPH can be deduced from -mmcu=MCU.
+
+Waddr-space-convert
+Warning C Report Var(avr_warn_addr_space_convert) Init(0)
+Warn if the address space of an address is change.
diff --git a/gcc/config/bfin/bfin.c b/gcc/config/bfin/bfin.c
index 97c1d21682d..a2d22c1c26f 100644
--- a/gcc/config/bfin/bfin.c
+++ b/gcc/config/bfin/bfin.c
@@ -3887,8 +3887,7 @@ gen_one_bundle (rtx slot[3])
rtx t = NEXT_INSN (slot[0]);
while (t != slot[1])
{
- if (GET_CODE (t) != NOTE
- || NOTE_KIND (t) != NOTE_INSN_DELETED)
+ if (! NOTE_P (t) || NOTE_KIND (t) != NOTE_INSN_DELETED)
return false;
t = NEXT_INSN (t);
}
@@ -3898,8 +3897,7 @@ gen_one_bundle (rtx slot[3])
rtx t = NEXT_INSN (slot[1]);
while (t != slot[2])
{
- if (GET_CODE (t) != NOTE
- || NOTE_KIND (t) != NOTE_INSN_DELETED)
+ if (! NOTE_P (t) || NOTE_KIND (t) != NOTE_INSN_DELETED)
return false;
t = NEXT_INSN (t);
}
diff --git a/gcc/config/c6x/c6x.c b/gcc/config/c6x/c6x.c
index e0db8b12a27..f66ad55978e 100644
--- a/gcc/config/c6x/c6x.c
+++ b/gcc/config/c6x/c6x.c
@@ -4848,7 +4848,7 @@ reorg_split_calls (rtx *call_labels)
{
unsigned int reservation_mask = 0;
rtx insn = get_insns ();
- gcc_assert (GET_CODE (insn) == NOTE);
+ gcc_assert (NOTE_P (insn));
insn = next_real_insn (insn);
while (insn)
{
diff --git a/gcc/config/epiphany/epiphany.c b/gcc/config/epiphany/epiphany.c
index 782dc7b3e75..5520a633c1f 100644
--- a/gcc/config/epiphany/epiphany.c
+++ b/gcc/config/epiphany/epiphany.c
@@ -2386,7 +2386,7 @@ epiphany_mode_after (int entity, int last_mode, rtx insn)
calls. */
if (entity == EPIPHANY_MSW_ENTITY_AND || entity == EPIPHANY_MSW_ENTITY_OR)
{
- if (GET_CODE (insn) == CALL_INSN)
+ if (CALL_P (insn))
return 0;
return last_mode;
}
diff --git a/gcc/config/frv/frv.c b/gcc/config/frv/frv.c
index 8fe4655950c..fd5349f218e 100644
--- a/gcc/config/frv/frv.c
+++ b/gcc/config/frv/frv.c
@@ -1408,7 +1408,7 @@ frv_function_contains_far_jump (void)
{
rtx insn = get_insns ();
while (insn != NULL
- && !(GET_CODE (insn) == JUMP_INSN
+ && !(JUMP_P (insn)
/* Ignore tablejump patterns. */
&& GET_CODE (PATTERN (insn)) != ADDR_VEC
&& GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC
@@ -1446,7 +1446,7 @@ frv_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
simply emit a different assembly directive because bralr and jmpl
execute in different units. */
for (insn = get_insns(); insn != NULL; insn = NEXT_INSN (insn))
- if (GET_CODE (insn) == JUMP_INSN)
+ if (JUMP_P (insn))
{
rtx pattern = PATTERN (insn);
if (GET_CODE (pattern) == PARALLEL
@@ -2649,7 +2649,7 @@ frv_print_operand_jump_hint (rtx insn)
HOST_WIDE_INT prob = -1;
enum { UNKNOWN, BACKWARD, FORWARD } jump_type = UNKNOWN;
- gcc_assert (GET_CODE (insn) == JUMP_INSN);
+ gcc_assert (JUMP_P (insn));
/* Assume any non-conditional jump is likely. */
if (! any_condjump_p (insn))
@@ -7387,7 +7387,7 @@ frv_pack_insn_p (rtx insn)
- There's no point putting a call in its own packet unless
we have to. */
if (frv_packet.num_insns > 0
- && GET_CODE (insn) == INSN
+ && NONJUMP_INSN_P (insn)
&& GET_MODE (insn) == TImode
&& GET_CODE (PATTERN (insn)) != COND_EXEC)
return false;
@@ -7430,7 +7430,7 @@ frv_insert_nop_in_packet (rtx insn)
packet_group = &frv_packet.groups[frv_unit_groups[frv_insn_unit (insn)]];
last = frv_packet.insns[frv_packet.num_insns - 1];
- if (GET_CODE (last) != INSN)
+ if (! NONJUMP_INSN_P (last))
{
insn = emit_insn_before (PATTERN (insn), last);
frv_packet.insns[frv_packet.num_insns - 1] = insn;
@@ -7492,7 +7492,7 @@ frv_for_each_packet (void (*handle_packet) (void))
default:
/* Calls mustn't be packed on a TOMCAT. */
- if (GET_CODE (insn) == CALL_INSN && frv_cpu_type == FRV_CPU_TOMCAT)
+ if (CALL_P (insn) && frv_cpu_type == FRV_CPU_TOMCAT)
frv_finish_packet (handle_packet);
/* Since the last instruction in a packet determines the EH
@@ -7913,7 +7913,7 @@ frv_optimize_membar_local (basic_block bb, struct frv_io *next_io,
CLEAR_HARD_REG_SET (used_regs);
for (insn = BB_END (bb); insn != BB_HEAD (bb); insn = PREV_INSN (insn))
- if (GET_CODE (insn) == CALL_INSN)
+ if (CALL_P (insn))
{
/* We can't predict what a call will do to volatile memory. */
memset (next_io, 0, sizeof (struct frv_io));
diff --git a/gcc/config/i386/constraints.md b/gcc/config/i386/constraints.md
index d567fd78693..ec7c856c1ac 100644
--- a/gcc/config/i386/constraints.md
+++ b/gcc/config/i386/constraints.md
@@ -116,8 +116,7 @@
"@internal Any integer register when zero extensions with AND are disabled.")
(define_register_constraint "Yd"
- "(TARGET_64BIT
- || (TARGET_INTEGER_DFMODE_MOVES && optimize_function_for_speed_p (cfun)))
+ "TARGET_INTEGER_DFMODE_MOVES && optimize_function_for_speed_p (cfun)
? GENERAL_REGS : NO_REGS"
"@internal Any integer register when integer DFmode moves are enabled.")
diff --git a/gcc/config/i386/cygwin.h b/gcc/config/i386/cygwin.h
index de0a3fd3b3c..7f92ada9f7c 100644
--- a/gcc/config/i386/cygwin.h
+++ b/gcc/config/i386/cygwin.h
@@ -48,11 +48,7 @@ along with GCC; see the file COPYING3. If not see
%{static|static-libgcc:-lgcc -lgcc_eh} \
%{!static: \
%{!static-libgcc: \
- %{!shared: \
- %{!shared-libgcc:-lgcc -lgcc_eh} \
- %{shared-libgcc:-lgcc_s -lgcc} \
- } \
- %{shared:-lgcc_s -lgcc} \
+ -lgcc_s -lgcc \
} \
} "
#else
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index 24d1012d5ce..475da37cb9b 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -651,12 +651,14 @@
(define_attr "movu" "0,1" (const_string "0"))
;; Used to control the "enabled" attribute on a per-instruction basis.
-(define_attr "isa" "base,sse2,sse2_noavx,sse3,sse4,sse4_noavx,noavx,avx,
- avx2,noavx2,bmi2,fma4,fma"
+(define_attr "isa" "base,x64,nox64,sse2,sse2_noavx,sse3,sse4,sse4_noavx,
+ noavx,avx,avx2,noavx2,bmi2,fma4,fma"
(const_string "base"))
(define_attr "enabled" ""
- (cond [(eq_attr "isa" "sse2") (symbol_ref "TARGET_SSE2")
+ (cond [(eq_attr "isa" "x64") (symbol_ref "TARGET_64BIT")
+ (eq_attr "isa" "nox64") (symbol_ref "!TARGET_64BIT")
+ (eq_attr "isa" "sse2") (symbol_ref "TARGET_SSE2")
(eq_attr "isa" "sse2_noavx")
(symbol_ref "TARGET_SSE2 && !TARGET_AVX")
(eq_attr "isa" "sse3") (symbol_ref "TARGET_SSE3")
@@ -1654,6 +1656,40 @@
;; Move instructions.
+;; Reload patterns to support multi-word load/store
+;; with non-offsetable address.
+(define_expand "reload_noff_store"
+ [(parallel [(match_operand 0 "memory_operand" "=m")
+ (match_operand 1 "register_operand" "r")
+ (match_operand:DI 2 "register_operand" "=&r")])]
+ "TARGET_64BIT"
+{
+ rtx mem = operands[0];
+ rtx addr = XEXP (mem, 0);
+
+ emit_move_insn (operands[2], addr);
+ mem = replace_equiv_address_nv (mem, operands[2]);
+
+ emit_insn (gen_rtx_SET (VOIDmode, mem, operands[1]));
+ DONE;
+})
+
+(define_expand "reload_noff_load"
+ [(parallel [(match_operand 0 "register_operand" "=r")
+ (match_operand 1 "memory_operand" "m")
+ (match_operand:DI 2 "register_operand" "=r")])]
+ "TARGET_64BIT"
+{
+ rtx mem = operands[1];
+ rtx addr = XEXP (mem, 0);
+
+ emit_move_insn (operands[2], addr);
+ mem = replace_equiv_address_nv (mem, operands[2]);
+
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0], mem));
+ DONE;
+})
+
(define_expand "movoi"
[(set (match_operand:OI 0 "nonimmediate_operand")
(match_operand:OI 1 "general_operand"))]
@@ -1722,12 +1758,12 @@
(match_operand:OI 1 "vector_move_operand" "C ,xm,x"))]
"TARGET_AVX && !(MEM_P (operands[0]) && MEM_P (operands[1]))"
{
- switch (which_alternative)
+ switch (get_attr_type (insn))
{
- case 0:
+ case TYPE_SSELOG1:
return standard_sse_constant_opcode (insn, operands[1]);
- case 1:
- case 2:
+
+ case TYPE_SSEMOV:
if (misaligned_operand (operands[0], OImode)
|| misaligned_operand (operands[1], OImode))
{
@@ -1743,6 +1779,7 @@
else
return "vmovdqa\t{%1, %0|%0, %1}";
}
+
default:
gcc_unreachable ();
}
@@ -1758,20 +1795,21 @@
]
(const_string "OI")))])
-(define_insn "*movti_internal_rex64"
+(define_insn "*movti_internal"
[(set (match_operand:TI 0 "nonimmediate_operand" "=!r ,o ,x,x ,m")
(match_operand:TI 1 "general_operand" "riFo,re,C,xm,x"))]
- "TARGET_64BIT && !(MEM_P (operands[0]) && MEM_P (operands[1]))"
+ "(TARGET_64BIT || TARGET_SSE)
+ && !(MEM_P (operands[0]) && MEM_P (operands[1]))"
{
- switch (which_alternative)
+ switch (get_attr_type (insn))
{
- case 0:
- case 1:
+ case TYPE_MULTI:
return "#";
- case 2:
+
+ case TYPE_SSELOG1:
return standard_sse_constant_opcode (insn, operands[1]);
- case 3:
- case 4:
+
+ case TYPE_SSEMOV:
/* TDmode values are passed as TImode on the stack. Moving them
to stack may result in unaligned memory access. */
if (misaligned_operand (operands[0], TImode)
@@ -1789,16 +1827,22 @@
else
return "%vmovdqa\t{%1, %0|%0, %1}";
}
+
default:
gcc_unreachable ();
}
}
- [(set_attr "type" "*,*,sselog1,ssemov,ssemov")
- (set_attr "prefix" "*,*,maybe_vex,maybe_vex,maybe_vex")
+ [(set_attr "isa" "x64,x64,*,*,*")
+ (set_attr "type" "multi,multi,sselog1,ssemov,ssemov")
+ (set (attr "prefix")
+ (if_then_else (eq_attr "type" "sselog1,ssemov")
+ (const_string "maybe_vex")
+ (const_string "orig")))
(set (attr "mode")
(cond [(eq_attr "alternative" "0,1")
(const_string "DI")
- (match_test "TARGET_SSE_PACKED_SINGLE_INSN_OPTIMAL")
+ (ior (not (match_test "TARGET_SSE2"))
+ (match_test "TARGET_SSE_PACKED_SINGLE_INSN_OPTIMAL"))
(const_string "V4SF")
(and (eq_attr "alternative" "4")
(match_test "TARGET_SSE_TYPELESS_STORES"))
@@ -1818,120 +1862,98 @@
[(const_int 0)]
"ix86_split_long_move (operands); DONE;")
-(define_insn "*movti_internal_sse"
- [(set (match_operand:TI 0 "nonimmediate_operand" "=x,x ,m")
- (match_operand:TI 1 "vector_move_operand" "C ,xm,x"))]
- "TARGET_SSE && !TARGET_64BIT
- && !(MEM_P (operands[0]) && MEM_P (operands[1]))"
-{
- switch (which_alternative)
- {
- case 0:
- return standard_sse_constant_opcode (insn, operands[1]);
- case 1:
- case 2:
- /* TDmode values are passed as TImode on the stack. Moving them
- to stack may result in unaligned memory access. */
- if (misaligned_operand (operands[0], TImode)
- || misaligned_operand (operands[1], TImode))
- {
- if (get_attr_mode (insn) == MODE_V4SF)
- return "%vmovups\t{%1, %0|%0, %1}";
- else
- return "%vmovdqu\t{%1, %0|%0, %1}";
- }
- else
- {
- if (get_attr_mode (insn) == MODE_V4SF)
- return "%vmovaps\t{%1, %0|%0, %1}";
- else
- return "%vmovdqa\t{%1, %0|%0, %1}";
- }
- default:
- gcc_unreachable ();
- }
-}
- [(set_attr "type" "sselog1,ssemov,ssemov")
- (set_attr "prefix" "maybe_vex")
- (set (attr "mode")
- (cond [(match_test "TARGET_SSE_PACKED_SINGLE_INSN_OPTIMAL")
- (const_string "V4SF")
- (and (eq_attr "alternative" "2")
- (match_test "TARGET_SSE_TYPELESS_STORES"))
- (const_string "V4SF")
- (match_test "TARGET_AVX")
- (const_string "TI")
- (ior (not (match_test "TARGET_SSE2"))
- (match_test "optimize_function_for_size_p (cfun)"))
- (const_string "V4SF")
- ]
- (const_string "TI")))])
-
-(define_insn "*movdi_internal_rex64"
+(define_insn "*movdi_internal"
[(set (match_operand:DI 0 "nonimmediate_operand"
- "=r,r ,r,m ,*y,m*y,?*y,?r ,?*Ym,*x,m ,*x,*x,?r ,?*Yi,?*x,?*Ym")
+ "=r ,o ,r,r ,r,m ,*y,*y,?*y,?m,?r ,?*Ym,*x,*x,*x,m ,?r ,?*Yi,?*Ym,?*Yi")
(match_operand:DI 1 "general_operand"
- "Z ,rem,i,re,C ,*y ,m ,*Ym,r ,C ,*x,*x,m ,*Yi,r ,*Ym,*x"))]
- "TARGET_64BIT && !(MEM_P (operands[0]) && MEM_P (operands[1]))"
+ "riFo,riF,Z,rem,i,re,C ,*y,m ,*y,*Ym,r ,C ,*x,m ,*x,*Yi,r ,*Yi ,*Ym"))]
+ "!(MEM_P (operands[0]) && MEM_P (operands[1]))"
{
switch (get_attr_type (insn))
{
- case TYPE_SSECVT:
- if (SSE_REG_P (operands[0]))
- return "movq2dq\t{%1, %0|%0, %1}";
- else
- return "movdq2q\t{%1, %0|%0, %1}";
-
- case TYPE_SSEMOV:
- if (get_attr_mode (insn) == MODE_V4SF)
- return "%vmovaps\t{%1, %0|%0, %1}";
- else if (get_attr_mode (insn) == MODE_TI)
- return "%vmovdqa\t{%1, %0|%0, %1}";
+ case TYPE_MULTI:
+ return "#";
- /* Handle broken assemblers that require movd instead of movq. */
- if (GENERAL_REG_P (operands[0]) || GENERAL_REG_P (operands[1]))
- return "%vmovd\t{%1, %0|%0, %1}";
- else
- return "%vmovq\t{%1, %0|%0, %1}";
+ case TYPE_MMX:
+ return "pxor\t%0, %0";
case TYPE_MMXMOV:
+#ifndef HAVE_AS_IX86_INTERUNIT_MOVQ
/* Handle broken assemblers that require movd instead of movq. */
if (GENERAL_REG_P (operands[0]) || GENERAL_REG_P (operands[1]))
return "movd\t{%1, %0|%0, %1}";
- else
- return "movq\t{%1, %0|%0, %1}";
+#endif
+ return "movq\t{%1, %0|%0, %1}";
case TYPE_SSELOG1:
return standard_sse_constant_opcode (insn, operands[1]);
- case TYPE_MMX:
- return "pxor\t%0, %0";
+ case TYPE_SSEMOV:
+ switch (get_attr_mode (insn))
+ {
+ case MODE_DI:
+#ifndef HAVE_AS_IX86_INTERUNIT_MOVQ
+ /* Handle broken assemblers that require movd instead of movq. */
+ if (GENERAL_REG_P (operands[0]) || GENERAL_REG_P (operands[1]))
+ return "%vmovd\t{%1, %0|%0, %1}";
+#endif
+ return "%vmovq\t{%1, %0|%0, %1}";
+ case MODE_TI:
+ return "%vmovdqa\t{%1, %0|%0, %1}";
+
+ case MODE_V2SF:
+ gcc_assert (!TARGET_AVX);
+ return "movlps\t{%1, %0|%0, %1}";
+ case MODE_V4SF:
+ return "%vmovaps\t{%1, %0|%0, %1}";
+
+ default:
+ gcc_unreachable ();
+ }
+
+ case TYPE_SSECVT:
+ if (SSE_REG_P (operands[0]))
+ return "movq2dq\t{%1, %0|%0, %1}";
+ else
+ return "movdq2q\t{%1, %0|%0, %1}";
case TYPE_LEA:
return "lea{q}\t{%E1, %0|%0, %E1}";
- default:
+ case TYPE_IMOV:
gcc_assert (!flag_pic || LEGITIMATE_PIC_OPERAND_P (operands[1]));
if (get_attr_mode (insn) == MODE_SI)
return "mov{l}\t{%k1, %k0|%k0, %k1}";
- else if (which_alternative == 2)
+ else if (which_alternative == 4)
return "movabs{q}\t{%1, %0|%0, %1}";
else if (ix86_use_lea_for_mov (insn, operands))
return "lea{q}\t{%E1, %0|%0, %E1}";
else
return "mov{q}\t{%1, %0|%0, %1}";
+
+ default:
+ gcc_unreachable ();
}
}
- [(set (attr "type")
- (cond [(eq_attr "alternative" "4")
+ [(set (attr "isa")
+ (cond [(eq_attr "alternative" "0,1")
+ (const_string "nox64")
+ (eq_attr "alternative" "2,3,4,5,10,11,16,17")
+ (const_string "x64")
+ ]
+ (const_string "*")))
+ (set (attr "type")
+ (cond [(eq_attr "alternative" "0,1")
+ (const_string "multi")
+ (eq_attr "alternative" "6")
(const_string "mmx")
- (eq_attr "alternative" "5,6,7,8")
+ (eq_attr "alternative" "7,8,9,10,11")
(const_string "mmxmov")
- (eq_attr "alternative" "9")
+ (eq_attr "alternative" "12")
(const_string "sselog1")
- (eq_attr "alternative" "10,11,12,13,14")
+ (eq_attr "alternative" "13,14,15,16,17")
(const_string "ssemov")
- (eq_attr "alternative" "15,16")
+ (eq_attr "alternative" "18,19")
(const_string "ssecvt")
(match_operand 1 "pic_32bit_operand")
(const_string "lea")
@@ -1939,161 +1961,45 @@
(const_string "imov")))
(set (attr "modrm")
(if_then_else
- (and (eq_attr "alternative" "2") (eq_attr "type" "imov"))
+ (and (eq_attr "alternative" "4") (eq_attr "type" "imov"))
(const_string "0")
(const_string "*")))
(set (attr "length_immediate")
(if_then_else
- (and (eq_attr "alternative" "2") (eq_attr "type" "imov"))
+ (and (eq_attr "alternative" "4") (eq_attr "type" "imov"))
(const_string "8")
(const_string "*")))
(set (attr "prefix_rex")
- (if_then_else (eq_attr "alternative" "7,8")
- (const_string "1")
- (const_string "*")))
- (set (attr "prefix_data16")
- (if_then_else (eq_attr "alternative" "10")
+ (if_then_else (eq_attr "alternative" "10,11,16,17")
(const_string "1")
(const_string "*")))
(set (attr "prefix")
- (if_then_else (eq_attr "alternative" "9,10,11,12,13,14")
+ (if_then_else (eq_attr "type" "sselog1,ssemov")
(const_string "maybe_vex")
(const_string "orig")))
+ (set (attr "prefix_data16")
+ (if_then_else (and (eq_attr "type" "ssemov") (eq_attr "mode" "DI"))
+ (const_string "1")
+ (const_string "*")))
(set (attr "mode")
- (cond [(eq_attr "alternative" "0")
- (const_string "SI")
- (eq_attr "alternative" "9,11")
- (cond [(match_test "TARGET_SSE_PACKED_SINGLE_INSN_OPTIMAL")
- (const_string "V4SF")
- (match_test "TARGET_AVX")
- (const_string "TI")
- (match_test "optimize_function_for_size_p (cfun)")
- (const_string "V4SF")
- ]
- (const_string "TI"))
- ]
- (const_string "DI")))])
-
-;; Reload patterns to support multi-word load/store
-;; with non-offsetable address.
-(define_expand "reload_noff_store"
- [(parallel [(match_operand 0 "memory_operand" "=m")
- (match_operand 1 "register_operand" "r")
- (match_operand:DI 2 "register_operand" "=&r")])]
- "TARGET_64BIT"
-{
- rtx mem = operands[0];
- rtx addr = XEXP (mem, 0);
-
- emit_move_insn (operands[2], addr);
- mem = replace_equiv_address_nv (mem, operands[2]);
-
- emit_insn (gen_rtx_SET (VOIDmode, mem, operands[1]));
- DONE;
-})
-
-(define_expand "reload_noff_load"
- [(parallel [(match_operand 0 "register_operand" "=r")
- (match_operand 1 "memory_operand" "m")
- (match_operand:DI 2 "register_operand" "=r")])]
- "TARGET_64BIT"
-{
- rtx mem = operands[1];
- rtx addr = XEXP (mem, 0);
-
- emit_move_insn (operands[2], addr);
- mem = replace_equiv_address_nv (mem, operands[2]);
-
- emit_insn (gen_rtx_SET (VOIDmode, operands[0], mem));
- DONE;
-})
-
-(define_insn "*movdi_internal"
- [(set (match_operand:DI 0 "nonimmediate_operand"
- "=r ,o ,*y,m*y,*y,*x,m ,*x,*x,*x,m ,*x,*x,?*x,?*Ym")
- (match_operand:DI 1 "general_operand"
- "riFo,riF,C ,*y ,m ,C ,*x,*x,m ,C ,*x,*x,m ,*Ym,*x"))]
- "!TARGET_64BIT && !(MEM_P (operands[0]) && MEM_P (operands[1]))"
-{
- switch (get_attr_type (insn))
- {
- case TYPE_SSECVT:
- if (SSE_REG_P (operands[0]))
- return "movq2dq\t{%1, %0|%0, %1}";
- else
- return "movdq2q\t{%1, %0|%0, %1}";
-
- case TYPE_SSEMOV:
- switch (get_attr_mode (insn))
- {
- case MODE_TI:
- return "%vmovdqa\t{%1, %0|%0, %1}";
- case MODE_DI:
- return "%vmovq\t{%1, %0|%0, %1}";
- case MODE_V4SF:
- return "%vmovaps\t{%1, %0|%0, %1}";
- case MODE_V2SF:
- return "movlps\t{%1, %0|%0, %1}";
- default:
- gcc_unreachable ();
- }
-
- case TYPE_MMXMOV:
- return "movq\t{%1, %0|%0, %1}";
-
- case TYPE_SSELOG1:
- return standard_sse_constant_opcode (insn, operands[1]);
-
- case TYPE_MMX:
- return "pxor\t%0, %0";
-
- case TYPE_MULTI:
- return "#";
+ (cond [(eq_attr "alternative" "2")
+ (const_string "SI")
+ (eq_attr "alternative" "12,13")
+ (cond [(ior (not (match_test "TARGET_SSE2"))
+ (match_test "TARGET_SSE_PACKED_SINGLE_INSN_OPTIMAL"))
+ (const_string "V4SF")
+ (match_test "TARGET_AVX")
+ (const_string "TI")
+ (match_test "optimize_function_for_size_p (cfun)")
+ (const_string "V4SF")
+ ]
+ (const_string "TI"))
- default:
- gcc_unreachable ();
- }
-}
- [(set (attr "isa")
- (cond [(eq_attr "alternative" "5,6,7,8,13,14")
- (const_string "sse2")
- (eq_attr "alternative" "9,10,11,12")
- (const_string "noavx")
+ (and (eq_attr "alternative" "14,15")
+ (not (match_test "TARGET_SSE2")))
+ (const_string "V2SF")
]
- (const_string "*")))
- (set (attr "type")
- (cond [(eq_attr "alternative" "0,1")
- (const_string "multi")
- (eq_attr "alternative" "2")
- (const_string "mmx")
- (eq_attr "alternative" "3,4")
- (const_string "mmxmov")
- (eq_attr "alternative" "5,9")
- (const_string "sselog1")
- (eq_attr "alternative" "13,14")
- (const_string "ssecvt")
- ]
- (const_string "ssemov")))
- (set (attr "prefix")
- (if_then_else (eq_attr "alternative" "5,6,7,8")
- (const_string "maybe_vex")
- (const_string "orig")))
- (set (attr "mode")
- (cond [(eq_attr "alternative" "9,11")
- (const_string "V4SF")
- (eq_attr "alternative" "10,12")
- (const_string "V2SF")
- (eq_attr "alternative" "5,7")
- (cond [(match_test "TARGET_SSE_PACKED_SINGLE_INSN_OPTIMAL")
- (const_string "V4SF")
- (match_test "TARGET_AVX")
- (const_string "TI")
- (match_test "optimize_function_for_size_p (cfun)")
- (const_string "V4SF")
- ]
- (const_string "TI"))
- ]
- (const_string "DI")))])
+ (const_string "DI")))])
(define_split
[(set (match_operand:DI 0 "nonimmediate_operand")
@@ -2106,9 +2012,9 @@
(define_insn "*movsi_internal"
[(set (match_operand:SI 0 "nonimmediate_operand"
- "=r,m ,*y,*y,?rm,?*y,*x,*x,?r ,m ,?*Yi,*x")
+ "=r,m ,*y,*y,?rm,?*y,*x,*x,*x,m ,?r ,?*Yi")
(match_operand:SI 1 "general_operand"
- "g ,re,C ,*y,*y ,rm ,C ,*x,*Yi,*x,r ,m"))]
+ "g ,re,C ,*y,*y ,rm ,C ,*x,m ,*x,*Yi,r"))]
"!(MEM_P (operands[0]) && MEM_P (operands[1]))"
{
switch (get_attr_type (insn))
@@ -2119,14 +2025,18 @@
case TYPE_SSEMOV:
switch (get_attr_mode (insn))
{
+ case MODE_SI:
+ return "%vmovd\t{%1, %0|%0, %1}";
case MODE_TI:
return "%vmovdqa\t{%1, %0|%0, %1}";
+
case MODE_V4SF:
return "%vmovaps\t{%1, %0|%0, %1}";
- case MODE_SI:
- return "%vmovd\t{%1, %0|%0, %1}";
+
case MODE_SF:
- return "%vmovss\t{%1, %0|%0, %1}";
+ gcc_assert (!TARGET_AVX);
+ return "movss\t{%1, %0|%0, %1}";
+
default:
gcc_unreachable ();
}
@@ -2135,19 +2045,29 @@
return "pxor\t%0, %0";
case TYPE_MMXMOV:
- if (get_attr_mode (insn) == MODE_DI)
- return "movq\t{%1, %0|%0, %1}";
- return "movd\t{%1, %0|%0, %1}";
+ switch (get_attr_mode (insn))
+ {
+ case MODE_DI:
+ return "movq\t{%1, %0|%0, %1}";
+ case MODE_SI:
+ return "movd\t{%1, %0|%0, %1}";
+
+ default:
+ gcc_unreachable ();
+ }
case TYPE_LEA:
return "lea{l}\t{%E1, %0|%0, %E1}";
- default:
+ case TYPE_IMOV:
gcc_assert (!flag_pic || LEGITIMATE_PIC_OPERAND_P (operands[1]));
if (ix86_use_lea_for_mov (insn, operands))
return "lea{l}\t{%E1, %0|%0, %E1}";
else
return "mov{l}\t{%1, %0|%0, %1}";
+
+ default:
+ gcc_unreachable ();
}
}
[(set (attr "type")
@@ -2164,9 +2084,9 @@
]
(const_string "imov")))
(set (attr "prefix")
- (if_then_else (eq_attr "alternative" "0,1,2,3,4,5")
- (const_string "orig")
- (const_string "maybe_vex")))
+ (if_then_else (eq_attr "type" "sselog1,ssemov")
+ (const_string "maybe_vex")
+ (const_string "orig")))
(set (attr "prefix_data16")
(if_then_else (and (eq_attr "type" "ssemov") (eq_attr "mode" "SI"))
(const_string "1")
@@ -2175,16 +2095,17 @@
(cond [(eq_attr "alternative" "2,3")
(const_string "DI")
(eq_attr "alternative" "6,7")
- (cond [(match_test "TARGET_SSE_PACKED_SINGLE_INSN_OPTIMAL")
+ (cond [(ior (not (match_test "TARGET_SSE2"))
+ (match_test "TARGET_SSE_PACKED_SINGLE_INSN_OPTIMAL"))
(const_string "V4SF")
(match_test "TARGET_AVX")
(const_string "TI")
- (ior (not (match_test "TARGET_SSE2"))
- (match_test "optimize_function_for_size_p (cfun)"))
+ (match_test "optimize_function_for_size_p (cfun)")
(const_string "V4SF")
]
(const_string "TI"))
- (and (eq_attr "alternative" "8,9,10,11")
+
+ (and (eq_attr "alternative" "8,9")
(not (match_test "TARGET_SSE2")))
(const_string "SF")
]
@@ -2582,16 +2503,17 @@
;; Floating point push instructions.
(define_insn "*pushtf"
- [(set (match_operand:TF 0 "push_operand" "=<,<,<")
- (match_operand:TF 1 "general_no_elim_operand" "x,Fo,*r"))]
- "TARGET_SSE"
+ [(set (match_operand:TF 0 "push_operand" "=<,<")
+ (match_operand:TF 1 "general_no_elim_operand" "x,*roF"))]
+ "TARGET_64BIT || TARGET_SSE"
{
/* This insn should be already split before reg-stack. */
gcc_unreachable ();
}
- [(set_attr "type" "multi")
- (set_attr "unit" "sse,*,*")
- (set_attr "mode" "TF,SI,SI")])
+ [(set_attr "isa" "*,x64")
+ (set_attr "type" "multi")
+ (set_attr "unit" "sse,*")
+ (set_attr "mode" "TF,DI")])
;; %%% Kill this when call knows how to work this out.
(define_split
@@ -2603,33 +2525,21 @@
(define_insn "*pushxf"
[(set (match_operand:XF 0 "push_operand" "=<,<")
- (match_operand:XF 1 "general_no_elim_operand" "f,ro"))]
- "optimize_function_for_speed_p (cfun)"
-{
- /* This insn should be already split before reg-stack. */
- gcc_unreachable ();
-}
- [(set_attr "type" "multi")
- (set_attr "unit" "i387,*")
- (set_attr "mode" "XF,SI")])
-
-;; Size of pushxf is 3 (for sub) + 2 (for fstp) + memory operand size.
-;; Size of pushxf using integer instructions is 3+3*memory operand size
-;; Pushing using integer instructions is longer except for constants
-;; and direct memory references (assuming that any given constant is pushed
-;; only once, but this ought to be handled elsewhere).
-
-(define_insn "*pushxf_nointeger"
- [(set (match_operand:XF 0 "push_operand" "=<,<")
- (match_operand:XF 1 "general_no_elim_operand" "f,*rFo"))]
- "optimize_function_for_size_p (cfun)"
+ (match_operand:XF 1 "general_no_elim_operand" "f,Yx*roF"))]
+ ""
{
/* This insn should be already split before reg-stack. */
gcc_unreachable ();
}
[(set_attr "type" "multi")
(set_attr "unit" "i387,*")
- (set_attr "mode" "XF,SI")])
+ (set (attr "mode")
+ (cond [(eq_attr "alternative" "1")
+ (if_then_else (match_test "TARGET_64BIT")
+ (const_string "DI")
+ (const_string "SI"))
+ ]
+ (const_string "XF")))])
;; %%% Kill this when call knows how to work this out.
(define_split
@@ -2640,34 +2550,18 @@
(set (mem:XF (reg:P SP_REG)) (match_dup 1))]
"operands[2] = GEN_INT (-GET_MODE_SIZE (XFmode));")
-(define_insn "*pushdf_rex64"
- [(set (match_operand:DF 0 "push_operand" "=<,<,<")
- (match_operand:DF 1 "general_no_elim_operand" "f,Yd*rFm,x"))]
- "TARGET_64BIT"
-{
- /* This insn should be already split before reg-stack. */
- gcc_unreachable ();
-}
- [(set_attr "type" "multi")
- (set_attr "unit" "i387,*,*")
- (set_attr "mode" "DF,DI,DF")])
-
-;; Size of pushdf is 3 (for sub) + 2 (for fstp) + memory operand size.
-;; Size of pushdf using integer instructions is 2+2*memory operand size
-;; On the average, pushdf using integers can be still shorter.
-
(define_insn "*pushdf"
- [(set (match_operand:DF 0 "push_operand" "=<,<,<")
- (match_operand:DF 1 "general_no_elim_operand" "f,Yd*rFo,x"))]
- "!TARGET_64BIT"
+ [(set (match_operand:DF 0 "push_operand" "=<,<,<,<")
+ (match_operand:DF 1 "general_no_elim_operand" "f,Yd*roF,rmF,x"))]
+ ""
{
/* This insn should be already split before reg-stack. */
gcc_unreachable ();
}
- [(set_attr "isa" "*,*,sse2")
+ [(set_attr "isa" "*,nox64,x64,sse2")
(set_attr "type" "multi")
- (set_attr "unit" "i387,*,*")
- (set_attr "mode" "DF,DI,DF")])
+ (set_attr "unit" "i387,*,*,sse")
+ (set_attr "mode" "DF,SI,DI,DF")])
;; %%% Kill this when call knows how to work this out.
(define_split
@@ -2692,7 +2586,7 @@
(define_insn "*pushsf"
[(set (match_operand:SF 0 "push_operand" "=<,<,<")
- (match_operand:SF 1 "general_no_elim_operand" "f,rFm,x"))]
+ (match_operand:SF 1 "general_no_elim_operand" "f,rmF,x"))]
"!TARGET_64BIT"
{
/* Anything else should be already split before reg-stack. */
@@ -2736,10 +2630,7 @@
[(set (match_operand:TF 0 "nonimmediate_operand")
(match_operand:TF 1 "nonimmediate_operand"))]
"TARGET_64BIT || TARGET_SSE"
-{
- ix86_expand_move (TFmode, operands);
- DONE;
-})
+ "ix86_expand_move (TFmode, operands); DONE;")
(define_expand "mov<mode>"
[(set (match_operand:X87MODEF 0 "nonimmediate_operand")
@@ -2747,10 +2638,11 @@
""
"ix86_expand_move (<MODE>mode, operands); DONE;")
-(define_insn "*movtf_internal_rex64"
+(define_insn "*movtf_internal"
[(set (match_operand:TF 0 "nonimmediate_operand" "=x,x ,m,?*r ,!o")
(match_operand:TF 1 "general_operand" "C ,xm,x,*roF,*rC"))]
- "TARGET_64BIT && !(MEM_P (operands[0]) && MEM_P (operands[1]))
+ "(TARGET_64BIT || TARGET_SSE)
+ && !(MEM_P (operands[0]) && MEM_P (operands[1]))
&& (!can_create_pseudo_p ()
|| (ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_LARGE)
|| GET_CODE (operands[1]) != CONST_DOUBLE
@@ -2760,12 +2652,12 @@
|| (!TARGET_MEMORY_MISMATCH_STALL
&& memory_operand (operands[0], TFmode)))"
{
- switch (which_alternative)
+ switch (get_attr_type (insn))
{
- case 0:
+ case TYPE_SSELOG1:
return standard_sse_constant_opcode (insn, operands[1]);
- case 1:
- case 2:
+
+ case TYPE_SSEMOV:
/* Handle misaligned load/store since we
don't have movmisaligntf pattern. */
if (misaligned_operand (operands[0], TFmode)
@@ -2784,16 +2676,19 @@
return "%vmovdqa\t{%1, %0|%0, %1}";
}
- case 3:
- case 4:
+ case TYPE_MULTI:
return "#";
default:
gcc_unreachable ();
}
}
- [(set_attr "type" "sselog1,ssemov,ssemov,*,*")
- (set_attr "prefix" "maybe_vex,maybe_vex,maybe_vex,*,*")
+ [(set_attr "isa" "*,*,*,x64,x64")
+ (set_attr "type" "sselog1,ssemov,ssemov,multi,multi")
+ (set (attr "prefix")
+ (if_then_else (eq_attr "type" "sselog1,ssemov")
+ (const_string "maybe_vex")
+ (const_string "orig")))
(set (attr "mode")
(cond [(eq_attr "alternative" "3,4")
(const_string "DI")
@@ -2810,101 +2705,13 @@
]
(const_string "TI")))])
-(define_insn "*movtf_internal_sse"
- [(set (match_operand:TF 0 "nonimmediate_operand" "=x,x ,m")
- (match_operand:TF 1 "general_operand" "C ,xm,x"))]
- "TARGET_SSE && !TARGET_64BIT
- && !(MEM_P (operands[0]) && MEM_P (operands[1]))
- && (!can_create_pseudo_p ()
- || (ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_LARGE)
- || GET_CODE (operands[1]) != CONST_DOUBLE
- || (optimize_function_for_size_p (cfun)
- && standard_sse_constant_p (operands[1])
- && !memory_operand (operands[0], TFmode))
- || (!TARGET_MEMORY_MISMATCH_STALL
- && memory_operand (operands[0], TFmode)))"
-{
- switch (which_alternative)
- {
- case 0:
- return standard_sse_constant_opcode (insn, operands[1]);
- case 1:
- case 2:
- /* Handle misaligned load/store since we
- don't have movmisaligntf pattern. */
- if (misaligned_operand (operands[0], TFmode)
- || misaligned_operand (operands[1], TFmode))
- {
- if (get_attr_mode (insn) == MODE_V4SF)
- return "%vmovups\t{%1, %0|%0, %1}";
- else
- return "%vmovdqu\t{%1, %0|%0, %1}";
- }
- else
- {
- if (get_attr_mode (insn) == MODE_V4SF)
- return "%vmovaps\t{%1, %0|%0, %1}";
- else
- return "%vmovdqa\t{%1, %0|%0, %1}";
- }
- default:
- gcc_unreachable ();
- }
-}
- [(set_attr "type" "sselog1,ssemov,ssemov")
- (set_attr "prefix" "maybe_vex")
- (set (attr "mode")
- (cond [(match_test "TARGET_SSE_PACKED_SINGLE_INSN_OPTIMAL")
- (const_string "V4SF")
- (and (eq_attr "alternative" "2")
- (match_test "TARGET_SSE_TYPELESS_STORES"))
- (const_string "V4SF")
- (match_test "TARGET_AVX")
- (const_string "TI")
- (ior (not (match_test "TARGET_SSE2"))
- (match_test "optimize_function_for_size_p (cfun)"))
- (const_string "V4SF")
- ]
- (const_string "TI")))])
-
-(define_insn "*movxf_internal_rex64"
- [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m,f,?Yx*r ,!o")
- (match_operand:XF 1 "general_operand" "fm,f,G,Yx*roF,Yx*rC"))]
- "TARGET_64BIT && !(MEM_P (operands[0]) && MEM_P (operands[1]))
- && (!can_create_pseudo_p ()
- || (ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_LARGE)
- || GET_CODE (operands[1]) != CONST_DOUBLE
- || (optimize_function_for_size_p (cfun)
- && standard_80387_constant_p (operands[1]) > 0
- && !memory_operand (operands[0], XFmode))
- || (!TARGET_MEMORY_MISMATCH_STALL
- && memory_operand (operands[0], XFmode)))"
-{
- switch (which_alternative)
- {
- case 0:
- case 1:
- return output_387_reg_move (insn, operands);
-
- case 2:
- return standard_80387_constant_opcode (operands[1]);
-
- case 3:
- case 4:
- return "#";
-
- default:
- gcc_unreachable ();
- }
-}
- [(set_attr "type" "fmov,fmov,fmov,multi,multi")
- (set_attr "mode" "XF,XF,XF,SI,SI")])
-
-;; Possible store forwarding (partial memory) stall in alternative 4.
+;; Possible store forwarding (partial memory) stall in alternatives 4 and 5.
(define_insn "*movxf_internal"
- [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m,f,?Yx*r ,!o")
- (match_operand:XF 1 "general_operand" "fm,f,G,Yx*roF,Yx*rF"))]
- "!TARGET_64BIT && !(MEM_P (operands[0]) && MEM_P (operands[1]))
+ [(set (match_operand:XF 0 "nonimmediate_operand"
+ "=f,m,f,?Yx*r ,!o ,!o")
+ (match_operand:XF 1 "general_operand"
+ "fm,f,G,Yx*roF,Yx*rF,Yx*rC"))]
+ "!(MEM_P (operands[0]) && MEM_P (operands[1]))
&& (!can_create_pseudo_p ()
|| (ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_LARGE)
|| GET_CODE (operands[1]) != CONST_DOUBLE
@@ -2914,177 +2721,37 @@
|| (!TARGET_MEMORY_MISMATCH_STALL
&& memory_operand (operands[0], XFmode)))"
{
- switch (which_alternative)
+ switch (get_attr_type (insn))
{
- case 0:
- case 1:
+ case TYPE_FMOV:
+ if (which_alternative == 2)
+ return standard_80387_constant_opcode (operands[1]);
return output_387_reg_move (insn, operands);
- case 2:
- return standard_80387_constant_opcode (operands[1]);
-
- case 3:
- case 4:
+ case TYPE_MULTI:
return "#";
default:
gcc_unreachable ();
}
}
- [(set_attr "type" "fmov,fmov,fmov,multi,multi")
- (set_attr "mode" "XF,XF,XF,SI,SI")])
-
-(define_insn "*movdf_internal_rex64"
- [(set (match_operand:DF 0 "nonimmediate_operand"
- "=Yf*f,m ,Yf*f,?r,?m,?r,?r,x,x,x,m,Yi,r")
- (match_operand:DF 1 "general_operand"
- "Yf*fm,Yf*f,G ,rm,rC,C ,F ,C,x,m,x,r ,Yi"))]
- "TARGET_64BIT && !(MEM_P (operands[0]) && MEM_P (operands[1]))
- && (!can_create_pseudo_p ()
- || (ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_LARGE)
- || GET_CODE (operands[1]) != CONST_DOUBLE
- || (optimize_function_for_size_p (cfun)
- && ((!(TARGET_SSE2 && TARGET_SSE_MATH)
- && standard_80387_constant_p (operands[1]) > 0)
- || (TARGET_SSE2 && TARGET_SSE_MATH
- && standard_sse_constant_p (operands[1]))))
- || memory_operand (operands[0], DFmode))"
-{
- switch (which_alternative)
- {
- case 0:
- case 1:
- return output_387_reg_move (insn, operands);
-
- case 2:
- return standard_80387_constant_opcode (operands[1]);
-
- case 3:
- case 4:
- return "mov{q}\t{%1, %0|%0, %1}";
-
- case 5:
- return "mov{l}\t{%1, %k0|%k0, %1}";
-
- case 6:
- return "movabs{q}\t{%1, %0|%0, %1}";
-
- case 7:
- return standard_sse_constant_opcode (insn, operands[1]);
-
- case 8:
- case 9:
- case 10:
- switch (get_attr_mode (insn))
- {
- case MODE_V2DF:
- return "%vmovapd\t{%1, %0|%0, %1}";
- case MODE_V4SF:
- return "%vmovaps\t{%1, %0|%0, %1}";
-
- case MODE_DI:
- return "%vmovq\t{%1, %0|%0, %1}";
- case MODE_DF:
- if (TARGET_AVX && REG_P (operands[0]) && REG_P (operands[1]))
- return "vmovsd\t{%1, %0, %0|%0, %0, %1}";
- return "%vmovsd\t{%1, %0|%0, %1}";
- case MODE_V1DF:
- return "%vmovlpd\t{%1, %d0|%d0, %1}";
- case MODE_V2SF:
- return "%vmovlps\t{%1, %d0|%d0, %1}";
- default:
- gcc_unreachable ();
- }
-
- case 11:
- case 12:
- /* Handle broken assemblers that require movd instead of movq. */
- return "%vmovd\t{%1, %0|%0, %1}";
-
- default:
- gcc_unreachable();
- }
-}
- [(set (attr "type")
- (cond [(eq_attr "alternative" "0,1,2")
- (const_string "fmov")
- (eq_attr "alternative" "3,4,5,6")
- (const_string "imov")
- (eq_attr "alternative" "7")
- (const_string "sselog1")
- ]
- (const_string "ssemov")))
- (set (attr "modrm")
- (if_then_else
- (and (eq_attr "alternative" "6") (eq_attr "type" "imov"))
- (const_string "0")
- (const_string "*")))
- (set (attr "length_immediate")
- (if_then_else
- (and (eq_attr "alternative" "6") (eq_attr "type" "imov"))
- (const_string "8")
- (const_string "*")))
- (set (attr "prefix")
- (if_then_else (eq_attr "alternative" "0,1,2,3,4,5,6")
- (const_string "orig")
- (const_string "maybe_vex")))
- (set (attr "prefix_data16")
- (if_then_else (eq_attr "mode" "V1DF")
- (const_string "1")
- (const_string "*")))
+ [(set_attr "isa" "*,*,*,*,nox64,x64")
+ (set_attr "type" "fmov,fmov,fmov,multi,multi,multi")
(set (attr "mode")
- (cond [(eq_attr "alternative" "0,1,2")
- (const_string "DF")
- (eq_attr "alternative" "3,4,6,11,12")
- (const_string "DI")
- (eq_attr "alternative" "5")
- (const_string "SI")
-
- /* xorps is one byte shorter for !TARGET_AVX. */
- (eq_attr "alternative" "7")
- (cond [(match_test "TARGET_AVX")
- (const_string "V2DF")
- (match_test "optimize_function_for_size_p (cfun)")
- (const_string "V4SF")
- (match_test "TARGET_SSE_LOAD0_BY_PXOR")
- (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 for !TARGET_AVX. */
- (eq_attr "alternative" "8")
- (cond [(match_test "TARGET_SSE_PACKED_SINGLE_INSN_OPTIMAL")
- (const_string "V4SF")
- (match_test "TARGET_SSE_PARTIAL_REG_DEPENDENCY")
- (const_string "V2DF")
- (match_test "TARGET_AVX")
- (const_string "DF")
- (match_test "optimize_function_for_size_p (cfun)")
- (const_string "V4SF")
- ]
- (const_string "DF"))
- /* For architectures resolving dependencies on register
- parts we may avoid extra work to zero out upper part
- of register. */
- (eq_attr "alternative" "9")
- (if_then_else
- (match_test "TARGET_SSE_SPLIT_REGS")
- (const_string "V1DF")
- (const_string "DF"))
+ (cond [(eq_attr "alternative" "3,4,5")
+ (if_then_else (match_test "TARGET_64BIT")
+ (const_string "DI")
+ (const_string "SI"))
]
- (const_string "DF")))])
+ (const_string "XF")))])
;; Possible store forwarding (partial memory) stall in alternative 4.
(define_insn "*movdf_internal"
[(set (match_operand:DF 0 "nonimmediate_operand"
- "=Yf*f,m ,Yf*f,?Yd*r ,!o ,x,x,x,m,*x,*x,*x,m")
+ "=Yf*f,m ,Yf*f,?Yd*r ,!o ,?r,?m,?r,?r,x,x,x,m,*x,*x,*x,m ,r ,Yi")
(match_operand:DF 1 "general_operand"
- "Yf*fm,Yf*f,G ,Yd*roF,Yd*rF,C,x,m,x,C ,*x,m ,*x"))]
- "!TARGET_64BIT && !(MEM_P (operands[0]) && MEM_P (operands[1]))
+ "Yf*fm,Yf*f,G ,Yd*roF,Yd*rF,rm,rC,C ,F ,C,x,m,x,C ,*x,m ,*x,Yi,r"))]
+ "!(MEM_P (operands[0]) && MEM_P (operands[1]))
&& (!can_create_pseudo_p ()
|| (ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_LARGE)
|| GET_CODE (operands[1]) != CONST_DOUBLE
@@ -3094,49 +2761,58 @@
|| (TARGET_SSE2 && TARGET_SSE_MATH
&& standard_sse_constant_p (operands[1])))
&& !memory_operand (operands[0], DFmode))
- || (!TARGET_MEMORY_MISMATCH_STALL
+ || ((TARGET_64BIT || !TARGET_MEMORY_MISMATCH_STALL)
&& memory_operand (operands[0], DFmode)))"
{
- switch (which_alternative)
+ switch (get_attr_type (insn))
{
- case 0:
- case 1:
+ case TYPE_FMOV:
+ if (which_alternative == 2)
+ return standard_80387_constant_opcode (operands[1]);
return output_387_reg_move (insn, operands);
- case 2:
- return standard_80387_constant_opcode (operands[1]);
-
- case 3:
- case 4:
+ case TYPE_MULTI:
return "#";
- case 5:
- case 9:
+ case TYPE_IMOV:
+ if (get_attr_mode (insn) == MODE_SI)
+ return "mov{l}\t{%1, %k0|%k0, %1}";
+ else if (which_alternative == 8)
+ return "movabs{q}\t{%1, %0|%0, %1}";
+ else
+ return "mov{q}\t{%1, %0|%0, %1}";
+
+ case TYPE_SSELOG1:
return standard_sse_constant_opcode (insn, operands[1]);
- case 6:
- case 7:
- case 8:
- case 10:
- case 11:
- case 12:
+ case TYPE_SSEMOV:
switch (get_attr_mode (insn))
{
- case MODE_V2DF:
- return "%vmovapd\t{%1, %0|%0, %1}";
- case MODE_V4SF:
- return "%vmovaps\t{%1, %0|%0, %1}";
-
- case MODE_DI:
- return "%vmovq\t{%1, %0|%0, %1}";
case MODE_DF:
if (TARGET_AVX && REG_P (operands[0]) && REG_P (operands[1]))
return "vmovsd\t{%1, %0, %0|%0, %0, %1}";
return "%vmovsd\t{%1, %0|%0, %1}";
- case MODE_V1DF:
- return "%vmovlpd\t{%1, %d0|%d0, %1}";
+
+ case MODE_V4SF:
+ return "%vmovaps\t{%1, %0|%0, %1}";
+ case MODE_V2DF:
+ return "%vmovapd\t{%1, %0|%0, %1}";
+
case MODE_V2SF:
- return "%vmovlps\t{%1, %d0|%d0, %1}";
+ gcc_assert (!TARGET_AVX);
+ return "movlps\t{%1, %0|%0, %1}";
+ case MODE_V1DF:
+ gcc_assert (!TARGET_AVX);
+ return "movlpd\t{%1, %0|%0, %1}";
+
+ case MODE_DI:
+#ifndef HAVE_AS_IX86_INTERUNIT_MOVQ
+ /* Handle broken assemblers that require movd instead of movq. */
+ if (GENERAL_REG_P (operands[0]) || GENERAL_REG_P (operands[1]))
+ return "%vmovd\t{%1, %0|%0, %1}";
+#endif
+ return "%vmovq\t{%1, %0|%0, %1}";
+
default:
gcc_unreachable ();
}
@@ -3146,42 +2822,54 @@
}
}
[(set (attr "isa")
- (if_then_else (eq_attr "alternative" "5,6,7,8")
- (const_string "sse2")
- (const_string "*")))
+ (cond [(eq_attr "alternative" "3,4")
+ (const_string "nox64")
+ (eq_attr "alternative" "5,6,7,8,17,18")
+ (const_string "x64")
+ (eq_attr "alternative" "9,10,11,12")
+ (const_string "sse2")
+ ]
+ (const_string "*")))
(set (attr "type")
(cond [(eq_attr "alternative" "0,1,2")
(const_string "fmov")
(eq_attr "alternative" "3,4")
(const_string "multi")
- (eq_attr "alternative" "5,9")
+ (eq_attr "alternative" "5,6,7,8")
+ (const_string "imov")
+ (eq_attr "alternative" "9,13")
(const_string "sselog1")
]
(const_string "ssemov")))
+ (set (attr "modrm")
+ (if_then_else (eq_attr "alternative" "8")
+ (const_string "0")
+ (const_string "*")))
+ (set (attr "length_immediate")
+ (if_then_else (eq_attr "alternative" "8")
+ (const_string "8")
+ (const_string "*")))
(set (attr "prefix")
- (if_then_else (eq_attr "alternative" "0,1,2,3,4")
- (const_string "orig")
- (const_string "maybe_vex")))
+ (if_then_else (eq_attr "type" "sselog1,ssemov")
+ (const_string "maybe_vex")
+ (const_string "orig")))
(set (attr "prefix_data16")
- (if_then_else (eq_attr "mode" "V1DF")
+ (if_then_else
+ (ior (and (eq_attr "type" "ssemov") (eq_attr "mode" "DI"))
+ (eq_attr "mode" "V1DF"))
(const_string "1")
(const_string "*")))
(set (attr "mode")
- (cond [(eq_attr "alternative" "0,1,2")
- (const_string "DF")
- (eq_attr "alternative" "3,4")
+ (cond [(eq_attr "alternative" "3,4,7")
(const_string "SI")
+ (eq_attr "alternative" "5,6,8,17,18")
+ (const_string "DI")
- /* For SSE1, we have many fewer alternatives. */
- (not (match_test "TARGET_SSE2"))
- (if_then_else
- (eq_attr "alternative" "5,6,9,10")
- (const_string "V4SF")
- (const_string "V2SF"))
-
- /* xorps is one byte shorter for !TARGET_AVX. */
- (eq_attr "alternative" "5,9")
- (cond [(match_test "TARGET_AVX")
+ /* xorps is one byte shorter for non-AVX targets. */
+ (eq_attr "alternative" "9,13")
+ (cond [(not (match_test "TARGET_SSE2"))
+ (const_string "V4SF")
+ (match_test "TARGET_AVX")
(const_string "V2DF")
(match_test "optimize_function_for_size_p (cfun)")
(const_string "V4SF")
@@ -3191,12 +2879,13 @@
(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.
+ whole SSE registers use movapd to break dependency
+ chains, otherwise use short move to avoid extra work. */
- movaps encodes one byte shorter for !TARGET_AVX. */
- (eq_attr "alternative" "6,10")
- (cond [(match_test "TARGET_SSE_PACKED_SINGLE_INSN_OPTIMAL")
+ /* movaps is one byte shorter for non-AVX targets. */
+ (eq_attr "alternative" "10,14")
+ (cond [(ior (not (match_test "TARGET_SSE2"))
+ (match_test "TARGET_SSE_PACKED_SINGLE_INSN_OPTIMAL"))
(const_string "V4SF")
(match_test "TARGET_SSE_PARTIAL_REG_DEPENDENCY")
(const_string "V2DF")
@@ -3204,25 +2893,33 @@
(const_string "DF")
(match_test "optimize_function_for_size_p (cfun)")
(const_string "V4SF")
- ]
- (const_string "DF"))
+ ]
+ (const_string "DF"))
/* For architectures resolving dependencies on register
parts we may avoid extra work to zero out upper part
of register. */
- (eq_attr "alternative" "7,11")
- (if_then_else
- (match_test "TARGET_SSE_SPLIT_REGS")
- (const_string "V1DF")
- (const_string "DF"))
+ (eq_attr "alternative" "11,15")
+ (cond [(not (match_test "TARGET_SSE2"))
+ (const_string "V2SF")
+ (match_test "TARGET_AVX")
+ (const_string "DF")
+ (match_test "TARGET_SSE_SPLIT_REGS")
+ (const_string "V1DF")
+ ]
+ (const_string "DF"))
+
+ (and (eq_attr "alternative" "12,16")
+ (not (match_test "TARGET_SSE2")))
+ (const_string "V2SF")
]
(const_string "DF")))])
(define_insn "*movsf_internal"
[(set (match_operand:SF 0 "nonimmediate_operand"
- "=Yf*f,m ,Yf*f,?r ,?m,x,x,x,m,!*y,!m,!*y,?Yi,?r,!*Ym,!r")
+ "=Yf*f,m ,Yf*f,?r ,?m,x,x,x,m,?r,?Yi,!*y,!*y,!m,!r ,!*Ym")
(match_operand:SF 1 "general_operand"
- "Yf*fm,Yf*f,G ,rmF,rF,C,x,m,x,m ,*y,*y ,r ,Yi,r ,*Ym"))]
+ "Yf*fm,Yf*f,G ,rmF,rF,C,x,m,x,Yi,r ,*y ,m ,*y,*Ym,r"))]
"!(MEM_P (operands[0]) && MEM_P (operands[1]))
&& (!can_create_pseudo_p ()
|| (ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_LARGE)
@@ -3234,44 +2931,48 @@
&& standard_sse_constant_p (operands[1]))))
|| memory_operand (operands[0], SFmode))"
{
- switch (which_alternative)
+ switch (get_attr_type (insn))
{
- case 0:
- case 1:
+ case TYPE_FMOV:
+ if (which_alternative == 2)
+ return standard_80387_constant_opcode (operands[1]);
return output_387_reg_move (insn, operands);
- case 2:
- return standard_80387_constant_opcode (operands[1]);
-
- case 3:
- case 4:
+ case TYPE_IMOV:
return "mov{l}\t{%1, %0|%0, %1}";
- case 5:
+ case TYPE_SSELOG1:
return standard_sse_constant_opcode (insn, operands[1]);
- case 6:
- if (get_attr_mode (insn) == MODE_V4SF)
- return "%vmovaps\t{%1, %0|%0, %1}";
- if (TARGET_AVX)
- return "vmovss\t{%1, %0, %0|%0, %0, %1}";
+ case TYPE_SSEMOV:
+ switch (get_attr_mode (insn))
+ {
+ case MODE_SF:
+ if (TARGET_AVX && REG_P (operands[0]) && REG_P (operands[1]))
+ return "vmovss\t{%1, %0, %0|%0, %0, %1}";
+ return "%vmovss\t{%1, %0|%0, %1}";
- case 7:
- case 8:
- return "%vmovss\t{%1, %0|%0, %1}";
+ case MODE_V4SF:
+ return "%vmovaps\t{%1, %0|%0, %1}";
- case 9:
- case 10:
- case 14:
- case 15:
- return "movd\t{%1, %0|%0, %1}";
+ case MODE_SI:
+ return "%vmovd\t{%1, %0|%0, %1}";
- case 11:
- return "movq\t{%1, %0|%0, %1}";
+ default:
+ gcc_unreachable ();
+ }
- case 12:
- case 13:
- return "%vmovd\t{%1, %0|%0, %1}";
+ case TYPE_MMXMOV:
+ switch (get_attr_mode (insn))
+ {
+ case MODE_DI:
+ return "movq\t{%1, %0|%0, %1}";
+ case MODE_SI:
+ return "movd\t{%1, %0|%0, %1}";
+
+ default:
+ gcc_unreachable ();
+ }
default:
gcc_unreachable ();
@@ -3281,27 +2982,34 @@
(cond [(eq_attr "alternative" "0,1,2")
(const_string "fmov")
(eq_attr "alternative" "3,4")
- (const_string "multi")
+ (const_string "imov")
(eq_attr "alternative" "5")
(const_string "sselog1")
- (eq_attr "alternative" "9,10,11,14,15")
+ (eq_attr "alternative" "11,12,13,14,15")
(const_string "mmxmov")
]
(const_string "ssemov")))
(set (attr "prefix")
- (if_then_else (eq_attr "alternative" "5,6,7,8,12,13")
+ (if_then_else (eq_attr "type" "sselog1,ssemov")
(const_string "maybe_vex")
(const_string "orig")))
+ (set (attr "prefix_data16")
+ (if_then_else (and (eq_attr "type" "ssemov") (eq_attr "mode" "SI"))
+ (const_string "1")
+ (const_string "*")))
(set (attr "mode")
- (cond [(eq_attr "alternative" "3,4,9,10")
+ (cond [(eq_attr "alternative" "3,4,9,10,14,15")
(const_string "SI")
+ (eq_attr "alternative" "11")
+ (const_string "DI")
(eq_attr "alternative" "5")
- (cond [(match_test "TARGET_AVX")
- (const_string "V4SF")
- (ior (not (match_test "TARGET_SSE2"))
- (match_test "optimize_function_for_size_p (cfun)"))
+ (cond [(not (match_test "TARGET_SSE2"))
(const_string "V4SF")
- (match_test "TARGET_SSE_LOAD0_BY_PXOR")
+ (match_test "TARGET_AVX")
+ (const_string "V4SF")
+ (match_test "optimize_function_for_size_p (cfun)")
+ (const_string "V4SF")
+ (match_test "TARGET_SSE_LOAD0_BY_PXOR")
(const_string "TI")
]
(const_string "V4SF"))
@@ -3316,15 +3024,12 @@
of instructions to load just part of the register. It is
better to maintain the whole registers in single format
to avoid problems on using packed logical operations. */
- (eq_attr "alternative" "6")
- (if_then_else
- (ior (match_test "TARGET_SSE_PARTIAL_REG_DEPENDENCY")
- (match_test "TARGET_SSE_SPLIT_REGS"))
- (const_string "V4SF")
- (const_string "SF"))
- (eq_attr "alternative" "11")
- (const_string "DI")]
- (const_string "SF")))])
+ (and (eq_attr "alternative" "6")
+ (ior (match_test "TARGET_SSE_PARTIAL_REG_DEPENDENCY")
+ (match_test "TARGET_SSE_SPLIT_REGS")))
+ (const_string "V4SF")
+ ]
+ (const_string "SF")))])
(define_split
[(set (match_operand 0 "any_fp_register_operand")
diff --git a/gcc/config/i386/mmx.md b/gcc/config/i386/mmx.md
index 232ecfac73c..fb75d49570a 100644
--- a/gcc/config/i386/mmx.md
+++ b/gcc/config/i386/mmx.md
@@ -68,260 +68,145 @@
;; This is essential for maintaining stable calling conventions.
(define_expand "mov<mode>"
- [(set (match_operand:MMXMODEI8 0 "nonimmediate_operand")
- (match_operand:MMXMODEI8 1 "nonimmediate_operand"))]
+ [(set (match_operand:MMXMODE 0 "nonimmediate_operand")
+ (match_operand:MMXMODE 1 "nonimmediate_operand"))]
"TARGET_MMX"
{
ix86_expand_vector_move (<MODE>mode, operands);
DONE;
})
-;; movd instead of movq is required to handle broken assemblers.
-(define_insn "*mov<mode>_internal_rex64"
- [(set (match_operand:MMXMODEI8 0 "nonimmediate_operand"
- "=rm,r,!?y,!y,!?y,m ,!y ,*x,x,x ,m,r ,Yi")
- (match_operand:MMXMODEI8 1 "vector_move_operand"
- "Cr ,m,C ,!y,m ,!?y,*x,!y ,C,xm,x,Yi,r"))]
- "TARGET_64BIT && TARGET_MMX
- && !(MEM_P (operands[0]) && MEM_P (operands[1]))"
- "@
- mov{q}\t{%1, %0|%0, %1}
- mov{q}\t{%1, %0|%0, %1}
- pxor\t%0, %0
- movq\t{%1, %0|%0, %1}
- movq\t{%1, %0|%0, %1}
- movq\t{%1, %0|%0, %1}
- movdq2q\t{%1, %0|%0, %1}
- movq2dq\t{%1, %0|%0, %1}
- %vpxor\t%0, %d0
- %vmovq\t{%1, %0|%0, %1}
- %vmovq\t{%1, %0|%0, %1}
- %vmovd\t{%1, %0|%0, %1}
- %vmovd\t{%1, %0|%0, %1}"
- [(set (attr "type")
- (cond [(eq_attr "alternative" "0,1")
- (const_string "imov")
- (eq_attr "alternative" "2")
- (const_string "mmx")
- (eq_attr "alternative" "3,4,5")
- (const_string "mmxmov")
- (eq_attr "alternative" "6,7")
- (const_string "ssecvt")
- (eq_attr "alternative" "8")
- (const_string "sselog1")
- ]
- (const_string "ssemov")))
- (set (attr "unit")
- (if_then_else (eq_attr "alternative" "6,7")
- (const_string "mmx")
- (const_string "*")))
- (set (attr "prefix_rep")
- (if_then_else (eq_attr "alternative" "6,7,9")
- (const_string "1")
- (const_string "*")))
- (set (attr "prefix_data16")
- (if_then_else (eq_attr "alternative" "10,11,12")
- (const_string "1")
- (const_string "*")))
- (set (attr "prefix_rex")
- (if_then_else (eq_attr "alternative" "9,10")
- (symbol_ref "x86_extended_reg_mentioned_p (insn)")
- (const_string "*")))
- (set (attr "prefix")
- (if_then_else (eq_attr "alternative" "8,9,10,11,12")
- (const_string "maybe_vex")
- (const_string "orig")))
- (set_attr "mode" "DI")])
-
(define_insn "*mov<mode>_internal"
- [(set (match_operand:MMXMODEI8 0 "nonimmediate_operand"
- "=!?y,!y,!?y,m ,!y,*x,*x,*x ,m ,*x,*x,*x,m ,r ,m")
- (match_operand:MMXMODEI8 1 "vector_move_operand"
- "C ,!y,m ,!?y,*x,!y,C ,*xm,*x,C ,*x,m ,*x,irm,r"))]
- "!TARGET_64BIT && TARGET_MMX
+ [(set (match_operand:MMXMODE 0 "nonimmediate_operand"
+ "=r ,o ,r,r ,m ,?!y,!y,?!y,m ,r ,?!Ym,x,x,x,m,*x,*x,*x,m ,r ,Yi,!Ym,*Yi")
+ (match_operand:MMXMODE 1 "vector_move_operand"
+ "rCo,rC,C,rm,rC,C ,!y,m ,?!y,?!Ym,r ,C,x,m,x,C ,*x,m ,*x,Yi,r ,*Yi,!Ym"))]
+ "TARGET_MMX
&& !(MEM_P (operands[0]) && MEM_P (operands[1]))"
- "@
- pxor\t%0, %0
- movq\t{%1, %0|%0, %1}
- movq\t{%1, %0|%0, %1}
- movq\t{%1, %0|%0, %1}
- movdq2q\t{%1, %0|%0, %1}
- movq2dq\t{%1, %0|%0, %1}
- %vpxor\t%0, %d0
- %vmovq\t{%1, %0|%0, %1}
- %vmovq\t{%1, %0|%0, %1}
- xorps\t%0, %0
- movaps\t{%1, %0|%0, %1}
- movlps\t{%1, %0|%0, %1}
- movlps\t{%1, %0|%0, %1}
- #
- #"
+{
+ switch (get_attr_type (insn))
+ {
+ case TYPE_MULTI:
+ return "#";
+
+ case TYPE_IMOV:
+ if (get_attr_mode (insn) == MODE_SI)
+ return "mov{l}\t{%1, %k0|%k0, %1}";
+ else
+ return "mov{q}\t{%1, %0|%0, %1}";
+
+ case TYPE_MMX:
+ return "pxor\t%0, %0";
+
+ case TYPE_MMXMOV:
+#ifndef HAVE_AS_IX86_INTERUNIT_MOVQ
+ /* Handle broken assemblers that require movd instead of movq. */
+ if (GENERAL_REG_P (operands[0]) || GENERAL_REG_P (operands[1]))
+ return "movd\t{%1, %0|%0, %1}";
+#endif
+ return "movq\t{%1, %0|%0, %1}";
+
+ case TYPE_SSECVT:
+ if (SSE_REG_P (operands[0]))
+ return "movq2dq\t{%1, %0|%0, %1}";
+ else
+ return "movdq2q\t{%1, %0|%0, %1}";
+
+ case TYPE_SSELOG1:
+ return standard_sse_constant_opcode (insn, operands[1]);
+
+ case TYPE_SSEMOV:
+ switch (get_attr_mode (insn))
+ {
+ case MODE_DI:
+#ifndef HAVE_AS_IX86_INTERUNIT_MOVQ
+ /* Handle broken assemblers that require movd instead of movq. */
+ if (GENERAL_REG_P (operands[0]) || GENERAL_REG_P (operands[1]))
+ return "%vmovd\t{%1, %0|%0, %1}";
+#endif
+ return "%vmovq\t{%1, %0|%0, %1}";
+ case MODE_TI:
+ return "%vmovdqa\t{%1, %0|%0, %1}";
+
+ case MODE_V2SF:
+ if (TARGET_AVX && REG_P (operands[0]))
+ return "vmovlps\t{%1, %0, %0|%0, %0, %1}";
+ return "%vmovlps\t{%1, %0|%0, %1}";
+ case MODE_V4SF:
+ return "%vmovaps\t{%1, %0|%0, %1}";
+
+ default:
+ gcc_unreachable ();
+ }
+
+ default:
+ gcc_unreachable ();
+ }
+}
[(set (attr "isa")
- (cond [(eq_attr "alternative" "4,5,6,7,8")
- (const_string "sse2")
- (eq_attr "alternative" "9,10,11,12")
- (const_string "noavx")
+ (cond [(eq_attr "alternative" "0,1")
+ (const_string "nox64")
+ (eq_attr "alternative" "2,3,4,9,10,11,12,13,14,19,20")
+ (const_string "x64")
]
- (const_string "*")))
+ (const_string "*")))
(set (attr "type")
- (cond [(eq_attr "alternative" "0")
- (const_string "mmx")
- (eq_attr "alternative" "1,2,3")
- (const_string "mmxmov")
- (eq_attr "alternative" "4,5")
- (const_string "ssecvt")
- (eq_attr "alternative" "6,9")
- (const_string "sselog1")
- (eq_attr "alternative" "13,14")
- (const_string "multi")
- ]
- (const_string "ssemov")))
- (set (attr "unit")
- (if_then_else (eq_attr "alternative" "4,5")
- (const_string "mmx")
- (const_string "*")))
- (set (attr "prefix_rep")
- (if_then_else
- (ior (eq_attr "alternative" "4,5")
- (and (eq_attr "alternative" "7")
- (not (match_test "TARGET_AVX"))))
- (const_string "1")
- (const_string "*")))
- (set (attr "prefix_data16")
- (if_then_else
- (and (eq_attr "alternative" "8")
- (not (match_test "TARGET_AVX")))
- (const_string "1")
- (const_string "*")))
- (set (attr "prefix")
- (if_then_else (eq_attr "alternative" "6,7,8")
- (const_string "maybe_vex")
- (const_string "orig")))
- (set_attr "mode" "DI,DI,DI,DI,DI,DI,TI,DI,DI,V4SF,V4SF,V2SF,V2SF,DI,DI")])
-
-(define_expand "movv2sf"
- [(set (match_operand:V2SF 0 "nonimmediate_operand")
- (match_operand:V2SF 1 "nonimmediate_operand"))]
- "TARGET_MMX"
-{
- ix86_expand_vector_move (V2SFmode, operands);
- DONE;
-})
-
-;; movd instead of movq is required to handle broken assemblers.
-(define_insn "*movv2sf_internal_rex64"
- [(set (match_operand:V2SF 0 "nonimmediate_operand"
- "=rm,r,!?y,!y,!?y,m ,!y,*x,x,x,x,m,r ,Yi")
- (match_operand:V2SF 1 "vector_move_operand"
- "Cr ,m,C ,!y,m ,!?y,*x,!y,C,x,m,x,Yi,r"))]
- "TARGET_64BIT && TARGET_MMX
- && !(MEM_P (operands[0]) && MEM_P (operands[1]))"
- "@
- mov{q}\t{%1, %0|%0, %1}
- mov{q}\t{%1, %0|%0, %1}
- pxor\t%0, %0
- movq\t{%1, %0|%0, %1}
- movq\t{%1, %0|%0, %1}
- movq\t{%1, %0|%0, %1}
- movdq2q\t{%1, %0|%0, %1}
- movq2dq\t{%1, %0|%0, %1}
- %vxorps\t%0, %d0
- %vmovaps\t{%1, %0|%0, %1}
- %vmovlps\t{%1, %d0|%d0, %1}
- %vmovlps\t{%1, %0|%0, %1}
- %vmovd\t{%1, %0|%0, %1}
- %vmovd\t{%1, %0|%0, %1}"
- [(set (attr "type")
(cond [(eq_attr "alternative" "0,1")
+ (const_string "multi")
+ (eq_attr "alternative" "2,3,4")
(const_string "imov")
- (eq_attr "alternative" "2")
+ (eq_attr "alternative" "5")
(const_string "mmx")
- (eq_attr "alternative" "3,4,5")
+ (eq_attr "alternative" "6,7,8,9,10")
(const_string "mmxmov")
- (eq_attr "alternative" "6,7")
- (const_string "ssecvt")
- (eq_attr "alternative" "9")
+ (eq_attr "alternative" "11,15")
(const_string "sselog1")
+ (eq_attr "alternative" "21,22")
+ (const_string "ssecvt")
]
(const_string "ssemov")))
- (set (attr "unit")
- (if_then_else (eq_attr "alternative" "6,7")
- (const_string "mmx")
- (const_string "*")))
- (set (attr "prefix_rep")
- (if_then_else (eq_attr "alternative" "6,7")
+ (set (attr "prefix_rex")
+ (if_then_else (eq_attr "alternative" "9,10,19,20")
(const_string "1")
(const_string "*")))
- (set (attr "length_vex")
- (if_then_else
- (and (eq_attr "alternative" "12,13")
- (match_test "TARGET_AVX"))
- (const_string "4")
- (const_string "*")))
(set (attr "prefix")
- (if_then_else (eq_attr "alternative" "8,9,10,11,12,13")
+ (if_then_else (eq_attr "type" "sselog1,ssemov")
(const_string "maybe_vex")
(const_string "orig")))
- (set_attr "mode" "DI,DI,DI,DI,DI,DI,DI,DI,V4SF,V4SF,V2SF,V2SF,DI,DI")])
-
-(define_insn "*movv2sf_internal"
- [(set (match_operand:V2SF 0 "nonimmediate_operand"
- "=!?y,!y,!?y,m ,!y,*x,*x,*x,*x,m ,r ,m")
- (match_operand:V2SF 1 "vector_move_operand"
- "C ,!y,m ,!?y,*x,!y,C ,*x,m ,*x,irm,r"))]
- "!TARGET_64BIT && TARGET_MMX
- && !(MEM_P (operands[0]) && MEM_P (operands[1]))"
- "@
- pxor\t%0, %0
- movq\t{%1, %0|%0, %1}
- movq\t{%1, %0|%0, %1}
- movq\t{%1, %0|%0, %1}
- movdq2q\t{%1, %0|%0, %1}
- movq2dq\t{%1, %0|%0, %1}
- %vxorps\t%0, %d0
- %vmovaps\t{%1, %0|%0, %1}
- %vmovlps\t{%1, %d0|%d0, %1}
- %vmovlps\t{%1, %0|%0, %1}
- #
- #"
- [(set (attr "isa")
- (if_then_else (eq_attr "alternative" "4,5")
- (const_string "sse2")
- (const_string "*")))
- (set (attr "type")
- (cond [(eq_attr "alternative" "0")
- (const_string "mmx")
- (eq_attr "alternative" "1,2,3")
- (const_string "mmxmov")
- (eq_attr "alternative" "4,5")
- (const_string "ssecvt")
- (eq_attr "alternative" "6")
- (const_string "sselog1")
- (eq_attr "alternative" "10,11")
- (const_string "multi")
- ]
- (const_string "ssemov")))
- (set (attr "unit")
- (if_then_else (eq_attr "alternative" "4,5")
- (const_string "mmx")
- (const_string "*")))
- (set (attr "prefix_rep")
- (if_then_else (eq_attr "alternative" "4,5")
+ (set (attr "prefix_data16")
+ (if_then_else
+ (and (eq_attr "type" "ssemov") (eq_attr "mode" "DI"))
(const_string "1")
(const_string "*")))
- (set (attr "prefix")
- (if_then_else (eq_attr "alternative" "6,7,8,9")
- (const_string "maybe_vex")
- (const_string "orig")))
- (set_attr "mode" "DI,DI,DI,DI,DI,DI,V4SF,V4SF,V2SF,V2SF,DI,DI")])
+ (set (attr "mode")
+ (cond [(eq_attr "alternative" "2")
+ (const_string "SI")
+ (eq_attr "alternative" "11,12,15,16")
+ (cond [(match_test "<MODE>mode == V2SFmode")
+ (const_string "V4SF")
+ (ior (not (match_test "TARGET_SSE2"))
+ (match_test "TARGET_SSE_PACKED_SINGLE_INSN_OPTIMAL"))
+ (const_string "V4SF")
+ (match_test "TARGET_AVX")
+ (const_string "TI")
+ (match_test "optimize_function_for_size_p (cfun)")
+ (const_string "V4SF")
+ ]
+ (const_string "TI"))
+
+ (and (eq_attr "alternative" "13,14,17,18")
+ (ior (match_test "<MODE>mode == V2SFmode")
+ (not (match_test "TARGET_SSE2"))))
+ (const_string "V2SF")
+ ]
+ (const_string "DI")))])
-;; %%% This multiword shite has got to go.
(define_split
[(set (match_operand:MMXMODE 0 "nonimmediate_operand")
(match_operand:MMXMODE 1 "general_operand"))]
"!TARGET_64BIT && reload_completed
- && !(MMX_REG_P (operands[0]) || SSE_REG_P (operands[0])
- || MMX_REG_P (operands[1]) || SSE_REG_P (operands[1]))"
+ && !(MMX_REG_P (operands[0]) || SSE_REG_P (operands[0]))
+ && !(MMX_REG_P (operands[1]) || SSE_REG_P (operands[1]))"
[(const_int 0)]
"ix86_split_long_move (operands); DONE;")
diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md
index f5657b964a0..d098dc5423d 100644
--- a/gcc/config/i386/predicates.md
+++ b/gcc/config/i386/predicates.md
@@ -436,6 +436,9 @@
if (SYMBOL_REF_TLS_MODEL (op))
return false;
+ /* Dll-imported symbols are always external. */
+ if (TARGET_DLLIMPORT_DECL_ATTRIBUTES && SYMBOL_REF_DLLIMPORT_P (op))
+ return false;
if (SYMBOL_REF_LOCAL_P (op))
return true;
diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c
index 9ad5d1504a7..2f5220c91dc 100644
--- a/gcc/config/ia64/ia64.c
+++ b/gcc/config/ia64/ia64.c
@@ -5468,7 +5468,7 @@ ia64_print_operand (FILE * file, rtx x, int code)
else
which = ".sptk";
}
- else if (GET_CODE (current_output_insn) == CALL_INSN)
+ else if (CALL_P (current_output_insn))
which = ".sptk";
else
which = ".dptk";
@@ -6809,8 +6809,7 @@ group_barrier_needed (rtx insn)
memset (rws_insn, 0, sizeof (rws_insn));
/* Don't bundle a call following another call. */
- if ((pat = prev_active_insn (insn))
- && GET_CODE (pat) == CALL_INSN)
+ if ((pat = prev_active_insn (insn)) && CALL_P (pat))
{
need_barrier = 1;
break;
@@ -6824,8 +6823,7 @@ group_barrier_needed (rtx insn)
flags.is_branch = 1;
/* Don't bundle a jump following a call. */
- if ((pat = prev_active_insn (insn))
- && GET_CODE (pat) == CALL_INSN)
+ if ((pat = prev_active_insn (insn)) && CALL_P (pat))
{
need_barrier = 1;
break;
@@ -6927,20 +6925,20 @@ emit_insn_group_barriers (FILE *dump)
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
- if (GET_CODE (insn) == CODE_LABEL)
+ if (LABEL_P (insn))
{
if (insns_since_last_label)
last_label = insn;
insns_since_last_label = 0;
}
- else if (GET_CODE (insn) == NOTE
+ else if (NOTE_P (insn)
&& NOTE_KIND (insn) == NOTE_INSN_BASIC_BLOCK)
{
if (insns_since_last_label)
last_label = insn;
insns_since_last_label = 0;
}
- else if (GET_CODE (insn) == INSN
+ else if (NONJUMP_INSN_P (insn)
&& GET_CODE (PATTERN (insn)) == UNSPEC_VOLATILE
&& XINT (PATTERN (insn), 1) == UNSPECV_INSN_GROUP_BARRIER)
{
@@ -6981,13 +6979,13 @@ emit_all_insn_group_barriers (FILE *dump ATTRIBUTE_UNUSED)
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
- if (GET_CODE (insn) == BARRIER)
+ if (BARRIER_P (insn))
{
rtx last = prev_active_insn (insn);
if (! last)
continue;
- if (GET_CODE (last) == JUMP_INSN
+ if (JUMP_P (last)
&& GET_CODE (PATTERN (last)) == ADDR_DIFF_VEC)
last = prev_active_insn (last);
if (recog_memoized (last) != CODE_FOR_insn_group_barrier)
@@ -7485,7 +7483,7 @@ ia64_variable_issue (FILE *dump ATTRIBUTE_UNUSED,
int needed = group_barrier_needed (insn);
gcc_assert (!needed);
- if (GET_CODE (insn) == CALL_INSN)
+ if (CALL_P (insn))
init_insn_group_barriers ();
stops_p [INSN_UID (insn)] = stop_before_p;
stop_before_p = 0;
@@ -7574,7 +7572,7 @@ ia64_dfa_new_cycle (FILE *dump, int verbose, rtx insn, int last_clock,
&& last_scheduled_insn
&& scheduled_good_insn (last_scheduled_insn))))
|| (last_scheduled_insn
- && (GET_CODE (last_scheduled_insn) == CALL_INSN
+ && (CALL_P (last_scheduled_insn)
|| unknown_for_bundling_p (last_scheduled_insn))))
{
init_insn_group_barriers ();
@@ -7592,7 +7590,7 @@ ia64_dfa_new_cycle (FILE *dump, int verbose, rtx insn, int last_clock,
state_transition (curr_state, dfa_stop_insn);
if (TARGET_EARLY_STOP_BITS)
*sort_p = (last_scheduled_insn == NULL_RTX
- || GET_CODE (last_scheduled_insn) != CALL_INSN);
+ || ! CALL_P (last_scheduled_insn));
else
*sort_p = 0;
return 1;
@@ -8933,9 +8931,9 @@ ia64_add_bundle_selector_before (int template0, rtx insn)
{
do
insn = next_active_insn (insn);
- while (GET_CODE (insn) == INSN
+ while (NONJUMP_INSN_P (insn)
&& get_attr_empty (insn) == EMPTY_YES);
- if (GET_CODE (insn) == CALL_INSN)
+ if (CALL_P (insn))
note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
else if (note)
{
@@ -9369,13 +9367,13 @@ final_emit_insn_group_barriers (FILE *dump ATTRIBUTE_UNUSED)
insn != current_sched_info->next_tail;
insn = NEXT_INSN (insn))
{
- if (GET_CODE (insn) == BARRIER)
+ if (BARRIER_P (insn))
{
rtx last = prev_active_insn (insn);
if (! last)
continue;
- if (GET_CODE (last) == JUMP_INSN
+ if (JUMP_P (last)
&& GET_CODE (PATTERN (last)) == ADDR_DIFF_VEC)
last = prev_active_insn (last);
if (recog_memoized (last) != CODE_FOR_insn_group_barrier)
@@ -9442,8 +9440,7 @@ final_emit_insn_group_barriers (FILE *dump ATTRIBUTE_UNUSED)
else if (recog_memoized (insn) >= 0
&& important_for_bundling_p (insn))
seen_good_insn = 1;
- need_barrier_p = (GET_CODE (insn) == CALL_INSN
- || unknown_for_bundling_p (insn));
+ need_barrier_p = (CALL_P (insn) || unknown_for_bundling_p (insn));
}
}
}
@@ -9587,7 +9584,7 @@ emit_predicate_relation_info (void)
rtx head = BB_HEAD (bb);
/* We only need such notes at code labels. */
- if (GET_CODE (head) != CODE_LABEL)
+ if (! LABEL_P (head))
continue;
if (NOTE_INSN_BASIC_BLOCK_P (NEXT_INSN (head)))
head = NEXT_INSN (head);
@@ -9615,7 +9612,7 @@ emit_predicate_relation_info (void)
while (1)
{
- if (GET_CODE (insn) == CALL_INSN
+ if (CALL_P (insn)
&& GET_CODE (PATTERN (insn)) == COND_EXEC
&& find_reg_note (insn, REG_NORETURN, NULL_RTX))
{
@@ -9763,7 +9760,7 @@ ia64_reorg (void)
if (insn)
{
/* Skip over insns that expand to nothing. */
- while (GET_CODE (insn) == INSN
+ while (NONJUMP_INSN_P (insn)
&& get_attr_empty (insn) == EMPTY_YES)
{
if (GET_CODE (PATTERN (insn)) == UNSPEC_VOLATILE
@@ -9771,7 +9768,7 @@ ia64_reorg (void)
saw_stop = 1;
insn = prev_active_insn (insn);
}
- if (GET_CODE (insn) == CALL_INSN)
+ if (CALL_P (insn))
{
if (! saw_stop)
emit_insn (gen_insn_group_barrier (GEN_INT (3)));
@@ -10181,7 +10178,7 @@ ia64_asm_unwind_emit (FILE *asm_out_file, rtx insn)
}
}
- if (GET_CODE (insn) == NOTE || ! RTX_FRAME_RELATED_P (insn))
+ if (NOTE_P (insn) || ! RTX_FRAME_RELATED_P (insn))
return;
/* Look for the ALLOC insn. */
diff --git a/gcc/config/iq2000/iq2000.c b/gcc/config/iq2000/iq2000.c
index c2933986bda..7e19366ae93 100644
--- a/gcc/config/iq2000/iq2000.c
+++ b/gcc/config/iq2000/iq2000.c
@@ -381,8 +381,7 @@ iq2000_fill_delay_slot (const char *ret, enum delay_type type, rtx operands[],
/* Make sure that we don't put nop's after labels. */
next_insn = NEXT_INSN (cur_insn);
while (next_insn != 0
- && (GET_CODE (next_insn) == NOTE
- || GET_CODE (next_insn) == CODE_LABEL))
+ && (NOTE_P (next_insn) || LABEL_P (next_insn)))
next_insn = NEXT_INSN (next_insn);
dslots_load_total += num_nops;
@@ -391,7 +390,7 @@ iq2000_fill_delay_slot (const char *ret, enum delay_type type, rtx operands[],
|| operands == 0
|| cur_insn == 0
|| next_insn == 0
- || GET_CODE (next_insn) == CODE_LABEL
+ || LABEL_P (next_insn)
|| (set_reg = operands[0]) == 0)
{
dslots_number_nops = 0;
@@ -1533,8 +1532,8 @@ final_prescan_insn (rtx insn, rtx opvec[] ATTRIBUTE_UNUSED,
iq2000_load_reg4 = 0;
}
- if ( (GET_CODE (insn) == JUMP_INSN
- || GET_CODE (insn) == CALL_INSN
+ if ( (JUMP_P (insn)
+ || CALL_P (insn)
|| (GET_CODE (PATTERN (insn)) == RETURN))
&& NEXT_INSN (PREV_INSN (insn)) == insn)
{
@@ -1544,7 +1543,7 @@ final_prescan_insn (rtx insn, rtx opvec[] ATTRIBUTE_UNUSED,
}
if (TARGET_STATS
- && (GET_CODE (insn) == JUMP_INSN || GET_CODE (insn) == CALL_INSN))
+ && (JUMP_P (insn) || CALL_P (insn)))
dslots_jump_total ++;
}
@@ -2285,8 +2284,8 @@ iq2000_adjust_insn_length (rtx insn, int length)
/* A unconditional jump has an unfilled delay slot if it is not part
of a sequence. A conditional jump normally has a delay slot. */
if (simplejump_p (insn)
- || ( (GET_CODE (insn) == JUMP_INSN
- || GET_CODE (insn) == CALL_INSN)))
+ || ( (JUMP_P (insn)
+ || CALL_P (insn))))
length += 4;
return length;
diff --git a/gcc/config/mcore/mcore.c b/gcc/config/mcore/mcore.c
index e730362e0cc..6550b6905f0 100644
--- a/gcc/config/mcore/mcore.c
+++ b/gcc/config/mcore/mcore.c
@@ -914,10 +914,10 @@ mcore_is_dead (rtx first, rtx reg)
to assume that it is live. */
for (insn = NEXT_INSN (first); insn; insn = NEXT_INSN (insn))
{
- if (GET_CODE (insn) == JUMP_INSN)
+ if (JUMP_P (insn))
return 0; /* We lose track, assume it is alive. */
- else if (GET_CODE(insn) == CALL_INSN)
+ else if (CALL_P (insn))
{
/* Call's might use it for target or register parms. */
if (reg_referenced_p (reg, PATTERN (insn))
@@ -926,7 +926,7 @@ mcore_is_dead (rtx first, rtx reg)
else if (dead_or_set_p (insn, reg))
return 1;
}
- else if (GET_CODE (insn) == INSN)
+ else if (NONJUMP_INSN_P (insn))
{
if (reg_referenced_p (reg, PATTERN (insn)))
return 0;
@@ -2254,7 +2254,7 @@ is_cond_candidate (rtx insn)
changed into a conditional. Only bother with SImode items. If
we wanted to be a little more aggressive, we could also do other
modes such as DImode with reg-reg move or load 0. */
- if (GET_CODE (insn) == INSN)
+ if (NONJUMP_INSN_P (insn))
{
rtx pat = PATTERN (insn);
rtx src, dst;
@@ -2305,9 +2305,9 @@ is_cond_candidate (rtx insn)
*/
}
- else if (GET_CODE (insn) == JUMP_INSN &&
- GET_CODE (PATTERN (insn)) == SET &&
- GET_CODE (XEXP (PATTERN (insn), 1)) == LABEL_REF)
+ else if (JUMP_P (insn)
+ && GET_CODE (PATTERN (insn)) == SET
+ && GET_CODE (XEXP (PATTERN (insn), 1)) == LABEL_REF)
return COND_BRANCH_INSN;
return COND_NO;
@@ -2328,7 +2328,7 @@ emit_new_cond_insn (rtx insn, int cond)
pat = PATTERN (insn);
- if (GET_CODE (insn) == INSN)
+ if (NONJUMP_INSN_P (insn))
{
dst = SET_DEST (pat);
src = SET_SRC (pat);
@@ -2449,9 +2449,9 @@ conditionalize_block (rtx first)
/* Check that the first insn is a candidate conditional jump. This is
the one that we'll eliminate. If not, advance to the next insn to
try. */
- if (GET_CODE (first) != JUMP_INSN ||
- GET_CODE (PATTERN (first)) != SET ||
- GET_CODE (XEXP (PATTERN (first), 1)) != IF_THEN_ELSE)
+ if (! JUMP_P (first)
+ || GET_CODE (PATTERN (first)) != SET
+ || GET_CODE (XEXP (PATTERN (first), 1)) != IF_THEN_ELSE)
return NEXT_INSN (first);
/* Extract some information we need. */
diff --git a/gcc/config/mep/mep.c b/gcc/config/mep/mep.c
index c190d316045..60054f9ae57 100644
--- a/gcc/config/mep/mep.c
+++ b/gcc/config/mep/mep.c
@@ -4882,7 +4882,7 @@ mep_reorg_regmove (rtx insns)
if (dump_file)
for (insn = insns; insn; insn = NEXT_INSN (insn))
- if (GET_CODE (insn) == INSN)
+ if (NONJUMP_INSN_P (insn))
before++;
/* We're looking for (set r2 r1) moves where r1 dies, followed by a
@@ -4896,7 +4896,7 @@ mep_reorg_regmove (rtx insns)
for (insn = insns; insn; insn = next)
{
next = next_nonnote_nondebug_insn (insn);
- if (GET_CODE (insn) != INSN)
+ if (! NONJUMP_INSN_P (insn))
continue;
pat = PATTERN (insn);
@@ -4912,7 +4912,7 @@ mep_reorg_regmove (rtx insns)
if (dump_file)
fprintf (dump_file, "superfluous moves: considering %d\n", INSN_UID (insn));
- while (follow && GET_CODE (follow) == INSN
+ while (follow && NONJUMP_INSN_P (follow)
&& GET_CODE (PATTERN (follow)) == SET
&& !dead_or_set_p (follow, SET_SRC (pat))
&& !mep_mentioned_p (PATTERN (follow), SET_SRC (pat), 0)
@@ -4925,7 +4925,7 @@ mep_reorg_regmove (rtx insns)
if (dump_file)
fprintf (dump_file, "\tfollow is %d\n", INSN_UID (follow));
- if (follow && GET_CODE (follow) == INSN
+ if (follow && NONJUMP_INSN_P (follow)
&& GET_CODE (PATTERN (follow)) == SET
&& find_regno_note (follow, REG_DEAD, REGNO (SET_DEST (pat))))
{
@@ -5523,8 +5523,7 @@ mep_reorg_erepeat (rtx insns)
count = simplejump_p (insn) ? 0 : 1;
for (prev = PREV_INSN (insn); prev; prev = PREV_INSN (prev))
{
- if (GET_CODE (prev) == CALL_INSN
- || BARRIER_P (prev))
+ if (CALL_P (prev) || BARRIER_P (prev))
break;
if (prev == JUMP_LABEL (insn))
@@ -5543,10 +5542,10 @@ mep_reorg_erepeat (rtx insns)
*after* the label. */
rtx barrier;
for (barrier = PREV_INSN (prev);
- barrier && GET_CODE (barrier) == NOTE;
+ barrier && NOTE_P (barrier);
barrier = PREV_INSN (barrier))
;
- if (barrier && GET_CODE (barrier) != BARRIER)
+ if (barrier && ! BARRIER_P (barrier))
break;
}
else
@@ -5590,10 +5589,9 @@ mep_reorg_erepeat (rtx insns)
if (LABEL_NUSES (prev) == 1)
{
for (user = PREV_INSN (prev);
- user && (INSN_P (user) || GET_CODE (user) == NOTE);
+ user && (INSN_P (user) || NOTE_P (user));
user = PREV_INSN (user))
- if (GET_CODE (user) == JUMP_INSN
- && JUMP_LABEL (user) == prev)
+ if (JUMP_P (user) && JUMP_LABEL (user) == prev)
{
safe = INSN_UID (user);
break;
@@ -5631,8 +5629,8 @@ mep_jmp_return_reorg (rtx insns)
/* Find the fist real insn the jump jumps to. */
label = ret = JUMP_LABEL (insn);
while (ret
- && (GET_CODE (ret) == NOTE
- || GET_CODE (ret) == CODE_LABEL
+ && (NOTE_P (ret)
+ || LABEL_P (ret)
|| GET_CODE (PATTERN (ret)) == USE))
ret = NEXT_INSN (ret);
@@ -7018,7 +7016,7 @@ mep_bundle_insns (rtx insns)
if (recog_memoized (insn) >= 0
&& get_attr_slot (insn) == SLOT_COP)
{
- if (GET_CODE (insn) == JUMP_INSN
+ if (JUMP_P (insn)
|| ! last
|| recog_memoized (last) < 0
|| get_attr_slot (last) != SLOT_CORE
diff --git a/gcc/config/microblaze/linux.h b/gcc/config/microblaze/linux.h
index eca777640a7..a7b7a1adcfa 100644
--- a/gcc/config/microblaze/linux.h
+++ b/gcc/config/microblaze/linux.h
@@ -22,6 +22,9 @@
#undef TARGET_SUPPORTS_PIC
#define TARGET_SUPPORTS_PIC 1
+#undef TLS_NEEDS_GOT
+#define TLS_NEEDS_GOT 1
+
#define DYNAMIC_LINKER "/lib/ld.so.1"
#undef SUBTARGET_EXTRA_SPECS
#define SUBTARGET_EXTRA_SPECS \
diff --git a/gcc/config/microblaze/microblaze-protos.h b/gcc/config/microblaze/microblaze-protos.h
index e19939f0930..34be76ffa63 100644
--- a/gcc/config/microblaze/microblaze-protos.h
+++ b/gcc/config/microblaze/microblaze-protos.h
@@ -50,6 +50,10 @@ extern void microblaze_declare_object (FILE *, const char *, const char *,
const char *, int);
extern void microblaze_asm_output_ident (const char *);
extern int microblaze_legitimate_pic_operand (rtx);
+extern bool microblaze_tls_referenced_p (rtx);
+extern int symbol_mentioned_p (rtx);
+extern int label_mentioned_p (rtx);
+extern bool microblaze_cannot_force_const_mem (enum machine_mode, rtx);
#endif /* RTX_CODE */
/* Declare functions in microblaze-c.c. */
diff --git a/gcc/config/microblaze/microblaze.c b/gcc/config/microblaze/microblaze.c
index 3a5299410b9..c121c2baec3 100644
--- a/gcc/config/microblaze/microblaze.c
+++ b/gcc/config/microblaze/microblaze.c
@@ -84,7 +84,8 @@ enum microblaze_address_type
ADDRESS_CONST_INT,
ADDRESS_SYMBOLIC,
ADDRESS_GOTOFF,
- ADDRESS_PLT
+ ADDRESS_PLT,
+ ADDRESS_TLS
};
/* Classifies symbols
@@ -98,6 +99,15 @@ enum microblaze_symbol_type
SYMBOL_TYPE_GENERAL
};
+/* TLS Address Type. */
+enum tls_reloc {
+ TLS_GD,
+ TLS_LDM,
+ TLS_DTPREL,
+ TLS_IE,
+ TLS_LE
+};
+
/* Classification of a MicroBlaze address. */
struct microblaze_address_info
{
@@ -108,6 +118,7 @@ struct microblaze_address_info
rtx offset; /* Contains valid values on ADDRESS_CONST_INT and ADDRESS_REG. */
rtx symbol; /* Contains valid values on ADDRESS_SYMBOLIC. */
enum microblaze_symbol_type symbol_type;
+ enum tls_reloc tls_type;
};
/* Structure to be filled in by compute_frame_size with register
@@ -215,6 +226,11 @@ static int microblaze_interrupt_function_p (tree);
section *sdata2_section;
+#ifdef HAVE_AS_TLS
+#undef TARGET_HAVE_TLS
+#define TARGET_HAVE_TLS true
+#endif
+
/* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */
static bool
microblaze_const_double_ok (rtx op, enum machine_mode mode)
@@ -287,6 +303,9 @@ simple_memory_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
plus0 = XEXP (addr, 0);
plus1 = XEXP (addr, 1);
+ if (GET_CODE (plus0) != REG)
+ return 0;
+
if (GET_CODE (plus0) == REG && GET_CODE (plus1) == CONST_INT
&& SMALL_INT (plus1))
{
@@ -386,6 +405,225 @@ microblaze_valid_base_register_p (rtx x,
&& microblaze_regno_ok_for_base_p (REGNO (x), strict));
}
+/* Build the SYMBOL_REF for __tls_get_addr. */
+
+static GTY(()) rtx tls_get_addr_libfunc;
+
+static rtx
+get_tls_get_addr (void)
+{
+ if (!tls_get_addr_libfunc)
+ tls_get_addr_libfunc = init_one_libfunc ("__tls_get_addr");
+ return tls_get_addr_libfunc;
+}
+
+/* Return TRUE if X is a thread-local symbol. */
+bool
+microblaze_tls_symbol_p (rtx x)
+{
+ if (!TARGET_HAVE_TLS)
+ return false;
+
+ if (GET_CODE (x) != SYMBOL_REF)
+ return false;
+
+ return SYMBOL_REF_TLS_MODEL (x) != 0;
+}
+
+static int
+microblaze_tls_operand_p_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
+{
+ if (GET_CODE (*x) == SYMBOL_REF)
+ return SYMBOL_REF_TLS_MODEL (*x) != 0;
+
+ /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are
+ TLS offsets, not real symbol references. */
+ if (GET_CODE (*x) == UNSPEC && XINT (*x, 1) == UNSPEC_TLS)
+ return -1;
+
+ return 0;
+}
+
+/* Return TRUE if X contains any TLS symbol references. */
+
+bool
+microblaze_tls_referenced_p (rtx x)
+{
+ if (!TARGET_HAVE_TLS)
+ return false;
+
+ return for_each_rtx (&x, microblaze_tls_operand_p_1, NULL);
+}
+
+bool
+microblaze_cannot_force_const_mem (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x)
+{
+ return microblaze_tls_referenced_p(x);
+}
+
+/* Return TRUE if X references a SYMBOL_REF. */
+int
+symbol_mentioned_p (rtx x)
+{
+ const char * fmt;
+ int i;
+
+ if (GET_CODE (x) == SYMBOL_REF)
+ return 1;
+
+ /* UNSPEC entries for a symbol include the SYMBOL_REF, but they
+ are constant offsets, not symbols. */
+ if (GET_CODE (x) == UNSPEC)
+ return 0;
+
+ fmt = GET_RTX_FORMAT (GET_CODE (x));
+
+ for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'E')
+ {
+ int j;
+
+ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ if (symbol_mentioned_p (XVECEXP (x, i, j)))
+ return 1;
+ }
+ else if (fmt[i] == 'e' && symbol_mentioned_p (XEXP (x, i)))
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Return TRUE if X references a LABEL_REF. */
+int
+label_mentioned_p (rtx x)
+{
+ const char * fmt;
+ int i;
+
+ if (GET_CODE (x) == LABEL_REF)
+ return 1;
+
+ /* UNSPEC entries for a symbol include a LABEL_REF for the referencing
+ instruction, but they are constant offsets, not symbols. */
+ if (GET_CODE (x) == UNSPEC)
+ return 0;
+
+ fmt = GET_RTX_FORMAT (GET_CODE (x));
+ for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'E')
+ {
+ int j;
+
+ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ if (label_mentioned_p (XVECEXP (x, i, j)))
+ return 1;
+ }
+ else if (fmt[i] == 'e' && label_mentioned_p (XEXP (x, i)))
+ return 1;
+ }
+
+ return 0;
+}
+
+int
+tls_mentioned_p (rtx x)
+{
+ switch (GET_CODE (x))
+ {
+ case CONST:
+ return tls_mentioned_p (XEXP (x, 0));
+
+ case UNSPEC:
+ if (XINT (x, 1) == UNSPEC_TLS)
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+static rtx
+load_tls_operand (rtx x, rtx reg)
+{
+ rtx tmp;
+
+ if (reg == NULL_RTX)
+ reg = gen_reg_rtx (Pmode);
+
+ tmp = gen_rtx_CONST (Pmode, x);
+
+ emit_insn (gen_rtx_SET (VOIDmode, reg,
+ gen_rtx_PLUS (Pmode, pic_offset_table_rtx, tmp)));
+
+ return reg;
+}
+
+static rtx
+microblaze_call_tls_get_addr (rtx x, rtx reg, rtx *valuep, int reloc)
+{
+ rtx insns, tls_entry;
+
+ df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
+
+ start_sequence ();
+
+ tls_entry = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (reloc)),
+ UNSPEC_TLS);
+
+ reg = load_tls_operand (tls_entry, reg);
+
+ *valuep = emit_library_call_value (get_tls_get_addr (), NULL_RTX,
+ LCT_PURE, /* LCT_CONST? */
+ Pmode, 1, reg, Pmode);
+
+ insns = get_insns ();
+ end_sequence ();
+
+ return insns;
+}
+
+rtx
+microblaze_legitimize_tls_address(rtx x, rtx reg)
+{
+ rtx dest, insns, ret, eqv, addend;
+ enum tls_model model;
+ model = SYMBOL_REF_TLS_MODEL (x);
+
+ switch (model)
+ {
+ case TLS_MODEL_LOCAL_DYNAMIC:
+ case TLS_MODEL_GLOBAL_DYNAMIC:
+ case TLS_MODEL_INITIAL_EXEC:
+ insns = microblaze_call_tls_get_addr (x, reg, &ret, TLS_GD);
+ dest = gen_reg_rtx (Pmode);
+ emit_libcall_block (insns, dest, ret, x);
+ break;
+
+ case TLS_MODEL_LOCAL_EXEC:
+ insns = microblaze_call_tls_get_addr (x, reg, &ret, TLS_LDM);
+
+ /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
+ share the LDM result with other LD model accesses. */
+ eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const1_rtx), UNSPEC_TLS);
+ dest = gen_reg_rtx (Pmode);
+ emit_libcall_block (insns, dest, ret, eqv);
+
+ /* Load the addend. */
+ addend = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (TLS_DTPREL)),
+ UNSPEC_TLS);
+ addend = force_reg (SImode, gen_rtx_CONST (SImode, addend));
+ dest = gen_rtx_PLUS (Pmode, dest, addend);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ return dest;
+}
+
static bool
microblaze_classify_unspec (struct microblaze_address_info *info, rtx x)
{
@@ -401,6 +639,11 @@ microblaze_classify_unspec (struct microblaze_address_info *info, rtx x)
{
info->type = ADDRESS_PLT;
}
+ else if (XINT (x, 1) == UNSPEC_TLS)
+ {
+ info->type = ADDRESS_TLS;
+ info->tls_type = tls_reloc INTVAL(XVECEXP(x, 0, 1));
+ }
else
{
return false;
@@ -431,7 +674,12 @@ static int
get_base_reg (rtx x)
{
tree decl;
- int base_reg = (flag_pic ? MB_ABI_PIC_ADDR_REGNUM : MB_ABI_BASE_REGNUM);
+ int base_reg;
+
+ if (!flag_pic || microblaze_tls_symbol_p(x))
+ base_reg = MB_ABI_BASE_REGNUM;
+ else if (flag_pic)
+ base_reg = MB_ABI_PIC_ADDR_REGNUM;
if (TARGET_XLGPOPT
&& GET_CODE (x) == SYMBOL_REF
@@ -509,28 +757,61 @@ microblaze_classify_address (struct microblaze_address_info *info, rtx x,
}
else if (GET_CODE (xplus1) == UNSPEC)
{
+ /* Need offsettable address. */
+ if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
+ return false;
+
return microblaze_classify_unspec (info, xplus1);
}
else if ((GET_CODE (xplus1) == SYMBOL_REF ||
- GET_CODE (xplus1) == LABEL_REF) && flag_pic == 2)
- {
- return false;
- }
- else if (GET_CODE (xplus1) == SYMBOL_REF ||
- GET_CODE (xplus1) == LABEL_REF ||
- GET_CODE (xplus1) == CONST)
+ GET_CODE (xplus1) == LABEL_REF))
{
- if (GET_CODE (XEXP (xplus1, 0)) == UNSPEC)
- return microblaze_classify_unspec (info, XEXP (xplus1, 0));
- else if (flag_pic == 2)
- {
- return false;
- }
+ if (flag_pic == 2 || microblaze_tls_symbol_p(xplus1))
+ return false;
info->type = ADDRESS_SYMBOLIC;
info->symbol = xplus1;
info->symbol_type = SYMBOL_TYPE_GENERAL;
return true;
}
+ else if (GET_CODE (xplus1) == CONST)
+ {
+ rtx xconst0 = XEXP(xplus1, 0);
+
+ /* base + unspec. */
+ if (GET_CODE (xconst0) == UNSPEC)
+ {
+ /* Need offsettable address. */
+ if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
+ return false;
+ return microblaze_classify_unspec(info, xconst0);
+ }
+
+ /* for (plus x const_int) just look at x. */
+ if (GET_CODE (xconst0) == PLUS
+ && GET_CODE (XEXP (xconst0, 1)) == CONST_INT
+ && SMALL_INT (XEXP (xconst0, 1)))
+ {
+ /* This is ok as info->symbol is set to xplus1 the full
+ const-expression below. */
+ xconst0 = XEXP (xconst0, 0);
+ }
+
+ if (GET_CODE (xconst0) == SYMBOL_REF
+ || GET_CODE (xconst0) == LABEL_REF)
+ {
+ if (flag_pic == 2 || microblaze_tls_symbol_p(xconst0))
+ return false;
+
+ info->type = ADDRESS_SYMBOLIC;
+ info->symbol = xplus1;
+ info->symbol_type = SYMBOL_TYPE_GENERAL;
+ return true;
+ }
+
+ /* Not base + symbol || base + UNSPEC. */
+ return false;
+
+ }
else if (GET_CODE (xplus1) == REG
&& microblaze_valid_index_register_p (xplus1, mode,
strict)
@@ -562,13 +843,20 @@ microblaze_classify_address (struct microblaze_address_info *info, rtx x,
if (GET_CODE (x) == CONST)
{
- return !(flag_pic && pic_address_needs_scratch (x));
- }
- else if (flag_pic == 2)
- {
- return false;
+ if (GET_CODE (XEXP (x, 0)) == UNSPEC)
+ {
+ info->regA = gen_rtx_raw_REG (mode,
+ get_base_reg (XVECEXP (XEXP (x,0), 0, 0)));
+ return microblaze_classify_unspec (info, XEXP (x, 0));
+ }
+ return !(flag_pic && pic_address_needs_scratch (x));
}
+ if (flag_pic == 2)
+ return false;
+ else if (microblaze_tls_symbol_p(x))
+ return false;
+
return true;
}
@@ -616,11 +904,10 @@ microblaze_valid_pic_const (rtx x)
int
microblaze_legitimate_pic_operand (rtx x)
{
- struct microblaze_address_info addr;
-
- if (pic_address_needs_scratch (x))
+ if (flag_pic == 2 && (symbol_mentioned_p(x) || label_mentioned_p(x)))
return 0;
- if (!microblaze_valid_pic_const(x))
+
+ if (microblaze_tls_referenced_p(x))
return 0;
return 1;
@@ -706,7 +993,7 @@ microblaze_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
return result;
}
- if (code0 == REG && REG_OK_FOR_BASE_P (xplus0) && flag_pic == 2)
+ if (code0 == REG && REG_OK_FOR_BASE_P (xplus0))
{
if (reload_in_progress)
df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
@@ -717,26 +1004,58 @@ microblaze_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
}
if (code1 == SYMBOL_REF)
{
- result =
- gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xplus1), UNSPEC_GOTOFF);
- result = gen_rtx_CONST (Pmode, result);
- result = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result);
- result = gen_const_mem (Pmode, result);
- result = gen_rtx_PLUS (Pmode, xplus0, result);
- return result;
+ if (microblaze_tls_symbol_p(xplus1))
+ {
+ rtx tls_ref, reg;
+ reg = gen_reg_rtx (Pmode);
+
+ tls_ref = microblaze_legitimize_tls_address (xplus1,
+ NULL_RTX);
+ emit_move_insn (reg, tls_ref);
+
+ result = gen_rtx_PLUS (Pmode, xplus0, reg);
+
+ return result;
+ }
+ else if (flag_pic == 2)
+ {
+ rtx pic_ref, reg;
+ reg = gen_reg_rtx (Pmode);
+
+ pic_ref = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xplus1),
+ UNSPEC_GOTOFF);
+ pic_ref = gen_rtx_CONST (Pmode, pic_ref);
+ pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, pic_ref);
+ pic_ref = gen_const_mem (Pmode, pic_ref);
+ emit_move_insn (reg, pic_ref);
+ result = gen_rtx_PLUS (Pmode, xplus0, reg);
+ return result;
+ }
}
}
}
if (GET_CODE (xinsn) == SYMBOL_REF)
{
- if (reload_in_progress)
- df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
- result = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xinsn), UNSPEC_GOTOFF);
- result = gen_rtx_CONST (Pmode, result);
- result = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result);
- result = gen_const_mem (Pmode, result);
- return result;
+ rtx reg;
+ if (microblaze_tls_symbol_p(xinsn))
+ {
+ reg = microblaze_legitimize_tls_address (xinsn, NULL_RTX);
+ }
+ else
+ {
+ rtx pic_ref;
+
+ if (reload_in_progress)
+ df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
+
+ pic_ref = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xinsn), UNSPEC_GOTOFF);
+ pic_ref = gen_rtx_CONST (Pmode, pic_ref);
+ pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, pic_ref);
+ pic_ref = gen_const_mem (Pmode, pic_ref);
+ reg = pic_ref;
+ }
+ return reg;
}
return x;
@@ -1061,10 +1380,22 @@ microblaze_address_insns (rtx x, enum machine_mode mode)
else
return 2;
case ADDRESS_REG_INDEX:
- case ADDRESS_SYMBOLIC:
return 1;
+ case ADDRESS_SYMBOLIC:
case ADDRESS_GOTOFF:
return 2;
+ case ADDRESS_TLS:
+ switch (addr.tls_type)
+ {
+ case TLS_GD:
+ return 2;
+ case TLS_LDM:
+ return 2;
+ case TLS_DTPREL:
+ return 1;
+ default :
+ abort();
+ }
default:
break;
}
@@ -1088,13 +1419,18 @@ microblaze_address_cost (rtx addr, enum machine_mode mode ATTRIBUTE_UNUSED,
int
pic_address_needs_scratch (rtx x)
{
- /* An address which is a symbolic plus a non SMALL_INT needs a temp reg. */
- if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS
- && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
- && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
- && (flag_pic == 2 || !SMALL_INT (XEXP (XEXP (x, 0), 1))))
- return 1;
+ if (GET_CODE (x) == CONST && GET_CODE (XEXP (x,0)) == PLUS)
+ {
+ rtx p0, p1;
+ p0 = XEXP (XEXP (x, 0), 0);
+ p1 = XEXP (XEXP (x, 0), 1);
+
+ if ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
+ && (GET_CODE (p1) == CONST_INT)
+ && (flag_pic == 2 || microblaze_tls_symbol_p (p0) || !SMALL_INT (p1)))
+ return 1;
+ }
return 0;
}
@@ -1918,6 +2254,7 @@ print_operand (FILE * file, rtx op, int letter)
case ADDRESS_CONST_INT:
case ADDRESS_SYMBOLIC:
case ADDRESS_GOTOFF:
+ case ADDRESS_TLS:
fputs ("i", file);
break;
case ADDRESS_REG_INDEX:
@@ -2034,10 +2371,19 @@ print_operand (FILE * file, rtx op, int letter)
else if (letter == 't')
fputs (code == EQ ? "t" : "f", file);
- else if (code == CONST && GET_CODE (XEXP (op, 0)) == REG)
+ else if (code == CONST
+ && ((GET_CODE (XEXP (op, 0)) == REG)
+ || (GET_CODE (XEXP (op, 0)) == UNSPEC)))
{
print_operand (file, XEXP (op, 0), letter);
}
+ else if (code == CONST
+ && (GET_CODE (XEXP (op, 0)) == PLUS)
+ && (GET_CODE (XEXP (XEXP (op, 0), 0)) == REG)
+ && (GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST))
+ {
+ print_operand_address (file, XEXP (op, 0));
+ }
else if (letter == 'm')
fprintf (file, HOST_WIDE_INT_PRINT_DEC, (1L << INTVAL (op)));
else
@@ -2098,6 +2444,7 @@ print_operand_address (FILE * file, rtx addr)
case ADDRESS_SYMBOLIC:
case ADDRESS_GOTOFF:
case ADDRESS_PLT:
+ case ADDRESS_TLS:
if (info.regA)
fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
output_addr_const (file, info.symbol);
@@ -2109,6 +2456,24 @@ print_operand_address (FILE * file, rtx addr)
{
fputs ("@PLT", file);
}
+ else if (type == ADDRESS_TLS)
+ {
+ switch (info.tls_type)
+ {
+ case TLS_GD:
+ fputs ("@TLSGD", file);
+ break;
+ case TLS_LDM:
+ fputs ("@TLSLDM", file);
+ break;
+ case TLS_DTPREL:
+ fputs ("@TLSDTPREL", file);
+ break;
+ default :
+ abort();
+ break;
+ }
+ }
break;
case ADDRESS_INVALID:
fatal_insn ("invalid address", addr);
@@ -2471,7 +2836,8 @@ microblaze_expand_prologue (void)
}
}
- if (flag_pic == 2 && df_regs_ever_live_p (MB_ABI_PIC_ADDR_REGNUM))
+ if ((flag_pic == 2 || TLS_NEEDS_GOT )
+ && df_regs_ever_live_p (MB_ABI_PIC_ADDR_REGNUM))
{
SET_REGNO (pic_offset_table_rtx, MB_ABI_PIC_ADDR_REGNUM);
emit_insn (gen_set_got (pic_offset_table_rtx)); /* setting GOT. */
@@ -2701,83 +3067,62 @@ expand_pic_symbol_ref (enum machine_mode mode ATTRIBUTE_UNUSED, rtx op)
bool
microblaze_expand_move (enum machine_mode mode, rtx operands[])
{
+ rtx op0, op1;
+
+ op0 = operands[0];
+ op1 = operands[1];
+
+ if (!register_operand (op0, SImode)
+ && !register_operand (op1, SImode)
+ && (GET_CODE (op1) != CONST_INT || INTVAL (op1) != 0))
+ {
+ rtx temp = force_reg (SImode, op1);
+ emit_move_insn (op0, temp);
+ return true;
+ }
/* If operands[1] is a constant address invalid for pic, then we need to
handle it just like LEGITIMIZE_ADDRESS does. */
- if (flag_pic)
+ if (GET_CODE (op1) == SYMBOL_REF || GET_CODE (op1) == LABEL_REF)
{
- if (GET_CODE (operands[0]) == MEM)
+ rtx result;
+ if (microblaze_tls_symbol_p(op1))
{
- rtx addr = XEXP (operands[0], 0);
- if (GET_CODE (addr) == SYMBOL_REF)
- {
- rtx ptr_reg, result;
-
- if (reload_in_progress)
- df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
-
- addr = expand_pic_symbol_ref (mode, addr);
- ptr_reg = gen_reg_rtx (Pmode);
- emit_move_insn (ptr_reg, addr);
- result = gen_rtx_MEM (mode, ptr_reg);
- operands[0] = result;
- }
+ result = microblaze_legitimize_tls_address (op1, NULL_RTX);
+ emit_move_insn (op0, result);
+ return true;
}
- if (GET_CODE (operands[1]) == SYMBOL_REF
- || GET_CODE (operands[1]) == LABEL_REF)
+ else if (flag_pic)
{
- rtx result;
if (reload_in_progress)
df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
- result = expand_pic_symbol_ref (mode, operands[1]);
- if (GET_CODE (operands[0]) != REG)
- {
- rtx ptr_reg = gen_reg_rtx (Pmode);
- emit_move_insn (ptr_reg, result);
- emit_move_insn (operands[0], ptr_reg);
- }
- else
- {
- emit_move_insn (operands[0], result);
- }
+ result = expand_pic_symbol_ref (mode, op1);
+ emit_move_insn (op0, result);
return true;
}
- else if (GET_CODE (operands[1]) == MEM &&
- GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF)
- {
- rtx result;
- rtx ptr_reg;
- if (reload_in_progress)
- df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
- result = expand_pic_symbol_ref (mode, XEXP (operands[1], 0));
+ }
+ /* Handle Case of (const (plus symbol const_int)). */
+ if (GET_CODE (op1) == CONST && GET_CODE (XEXP (op1,0)) == PLUS)
+ {
+ rtx p0, p1;
- ptr_reg = gen_reg_rtx (Pmode);
+ p0 = XEXP (XEXP (op1, 0), 0);
+ p1 = XEXP (XEXP (op1, 0), 1);
- emit_move_insn (ptr_reg, result);
- result = gen_rtx_MEM (mode, ptr_reg);
- emit_move_insn (operands[0], result);
- return true;
- }
- else if (pic_address_needs_scratch (operands[1]))
+ if ((GET_CODE (p1) == CONST_INT)
+ && ((GET_CODE (p0) == UNSPEC)
+ || ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
+ && (flag_pic == 2 || microblaze_tls_symbol_p (p0)
+ || !SMALL_INT (p1)))))
{
- rtx temp = force_reg (SImode, XEXP (XEXP (operands[1], 0), 0));
- rtx temp2 = XEXP (XEXP (operands[1], 0), 1);
+ rtx temp = force_reg (SImode, p0);
+ rtx temp2 = p1;
- if (reload_in_progress)
+ if (flag_pic && reload_in_progress)
df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
- emit_move_insn (operands[0], gen_rtx_PLUS (SImode, temp, temp2));
+ emit_move_insn (op0, gen_rtx_PLUS (SImode, temp, temp2));
return true;
}
}
-
- if ((reload_in_progress | reload_completed) == 0
- && !register_operand (operands[0], SImode)
- && !register_operand (operands[1], SImode)
- && (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0))
- {
- rtx temp = force_reg (SImode, operands[1]);
- emit_move_insn (operands[0], temp);
- return true;
- }
return false;
}
@@ -3048,10 +3393,40 @@ microblaze_adjust_cost (rtx insn ATTRIBUTE_UNUSED, rtx link,
At present, GAS doesn't understand li.[sd], so don't allow it
to be generated at present. */
static bool
-microblaze_legitimate_constant_p (enum machine_mode mode, rtx x)
+microblaze_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x)
{
- return GET_CODE (x) != CONST_DOUBLE || microblaze_const_double_ok (x, mode);
+
+ if (microblaze_cannot_force_const_mem(mode, x))
+ return false;
+
+ if (GET_CODE (x) == CONST_DOUBLE)
+ {
+ return microblaze_const_double_ok (x, GET_MODE (x));
+ }
+
+ /* Handle Case of (const (plus unspec const_int)). */
+ if (GET_CODE (x) == CONST && GET_CODE (XEXP (x,0)) == PLUS)
+ {
+ rtx p0, p1;
+
+ p0 = XEXP (XEXP (x, 0), 0);
+ p1 = XEXP (XEXP (x, 0), 1);
+
+ if (GET_CODE(p1) == CONST_INT)
+ {
+ /* Const offset from UNSPEC is not supported. */
+ if ((GET_CODE (p0) == UNSPEC))
+ return false;
+
+ if ((GET_CODE (p0) == SYMBOL_REF || GET_CODE (p0) == LABEL_REF)
+ && (microblaze_tls_symbol_p (p0) || !SMALL_INT (p1)))
+ return false;
+ }
+ }
+
+ return true;
}
+
#undef TARGET_ENCODE_SECTION_INFO
#define TARGET_ENCODE_SECTION_INFO microblaze_encode_section_info
@@ -3068,6 +3443,9 @@ microblaze_legitimate_constant_p (enum machine_mode mode, rtx x)
#undef TARGET_RTX_COSTS
#define TARGET_RTX_COSTS microblaze_rtx_costs
+#undef TARGET_CANNOT_FORCE_CONST_MEM
+#define TARGET_CANNOT_FORCE_CONST_MEM microblaze_cannot_force_const_mem
+
#undef TARGET_ADDRESS_COST
#define TARGET_ADDRESS_COST microblaze_address_cost
diff --git a/gcc/config/microblaze/microblaze.h b/gcc/config/microblaze/microblaze.h
index 8fbe5bf8085..bc4d9a128d1 100644
--- a/gcc/config/microblaze/microblaze.h
+++ b/gcc/config/microblaze/microblaze.h
@@ -65,6 +65,9 @@ extern enum pipeline_type microblaze_pipe;
/* The default is to support PIC. */
#define TARGET_SUPPORTS_PIC 1
+/* The default is to not need GOT for TLS. */
+#define TLS_NEEDS_GOT 0
+
/* What is the default setting for -mcpu= . We set it to v4.00.a even though
we are actually ahead. This is safest version that has generate code
compatible for the original ISA */
@@ -326,9 +329,7 @@ extern char microblaze_hard_regno_mode_ok[][FIRST_PSEUDO_REGISTER];
#define NO_FUNCTION_CSE 1
-#define PIC_OFFSET_TABLE_REGNUM \
- (flag_pic ? (GP_REG_FIRST + MB_ABI_PIC_ADDR_REGNUM) : \
- INVALID_REGNUM)
+#define PIC_OFFSET_TABLE_REGNUM (GP_REG_FIRST + MB_ABI_PIC_ADDR_REGNUM)
enum reg_class
{
diff --git a/gcc/config/microblaze/microblaze.md b/gcc/config/microblaze/microblaze.md
index 02857875022..3618cad524b 100644
--- a/gcc/config/microblaze/microblaze.md
+++ b/gcc/config/microblaze/microblaze.md
@@ -40,6 +40,7 @@
(UNSPEC_PLT 103) ;; jump table
(UNSPEC_CMP 104) ;; signed compare
(UNSPEC_CMPU 105) ;; unsigned compare
+ (UNSPEC_TLS 106) ;; jump table
])
@@ -459,7 +460,7 @@
(define_insn "addsi3"
[(set (match_operand:SI 0 "register_operand" "=d,d,d")
(plus:SI (match_operand:SI 1 "reg_or_0_operand" "%dJ,dJ,dJ")
- (match_operand:SI 2 "arith_operand" "d,I,i")))]
+ (match_operand:SI 2 "arith_plus_operand" "d,I,i")))]
""
"@
addk\t%0,%z1,%2
@@ -892,8 +893,8 @@
(define_insn "*movdi_internal"
- [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,d,R,m")
- (match_operand:DI 1 "general_operand" " d,i,J,R,m,d,d"))]
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,d,R,o")
+ (match_operand:DI 1 "general_operand" " d,i,J,R,o,d,d"))]
""
{
switch (which_alternative)
@@ -999,13 +1000,9 @@
(set_attr "length" "4")])
(define_insn "*movsi_internal2"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d, d,d,R, T")
- (match_operand:SI 1 "move_operand" " d,I,Mnis,R,m,dJ,dJ"))]
- "(register_operand (operands[0], SImode)
- || register_operand (operands[1], SImode)
- || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))
- && (flag_pic != 2 || (GET_CODE (operands[1]) != SYMBOL_REF
- && GET_CODE (operands[1]) != LABEL_REF))"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d, d,d,R,m")
+ (match_operand:SI 1 "move_src_operand" " d,I,Mnis,R,m,dJ,dJ"))]
+ ""
"@
addk\t%0,%1,r0
addik\t%0,r0,%1\t# %X1
@@ -1196,7 +1193,7 @@
;; Applies to both TARGET_SOFT_FLOAT and TARGET_HARD_FLOAT
;;
(define_insn "*movdf_internal"
- [(set (match_operand:DF 0 "nonimmediate_operand" "=d,d,d,d,To")
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=d,d,d,d,o")
(match_operand:DF 1 "general_operand" "dG,o,F,T,d"))]
""
{
diff --git a/gcc/config/microblaze/predicates.md b/gcc/config/microblaze/predicates.md
index e6e99836024..5fd1bd40372 100644
--- a/gcc/config/microblaze/predicates.md
+++ b/gcc/config/microblaze/predicates.md
@@ -30,6 +30,52 @@
(and (match_code "const_int,const_double")
(match_test "LARGE_INT (op)"))))
+(define_predicate "arith_plus_operand"
+ (match_operand 0 "general_operand")
+{
+ switch (GET_CODE (op))
+ {
+ default:
+ return 0;
+ case CONST_INT:
+ case REG:
+ return 1;
+ case SYMBOL_REF:
+ case LABEL_REF:
+ if (flag_pic || microblaze_tls_referenced_p(op))
+ return 0;
+ return 1;
+ case CONST:
+ {
+ rtx const0;
+ const0 = XEXP (op, 0);
+
+ switch (GET_CODE(const0))
+ {
+ default:
+ return 0;
+ case UNSPEC :
+ return 1;
+
+ case PLUS :
+ {
+ rtx p0, p1;
+ p0 = XEXP (const0, 0);
+ p1 = XEXP (const0, 1);
+
+ if ((GET_CODE(p0) == SYMBOL_REF
+ || GET_CODE (p0) == LABEL_REF)
+ && GET_CODE(p1) == CONST_INT)
+ {
+ return arith_plus_operand (p0, GET_MODE(p0));
+ }
+ }
+ }
+ }
+ }
+ return 0;
+})
+
(define_predicate "const_0_operand"
(and (match_code "const_int,const_double")
(match_test "op == CONST0_RTX (GET_MODE (op))")))
@@ -54,14 +100,21 @@
(match_test "GET_CODE (op) == REG || GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST_INT")))
;; Return if OPERAND is valid as a source operand for a move instruction.
-(define_predicate "move_operand"
+(define_predicate "move_src_operand"
(and (
not (
and (match_code "plus")
(not (match_test "(GET_CODE (XEXP (op, 0)) == REG) ^ (GET_CODE (XEXP (op,1)) == REG)"))
)
)
- (match_operand 0 "general_operand")))
+ (match_operand 0 "general_operand"))
+{
+ if (microblaze_tls_referenced_p(op)
+ || (flag_pic && (symbol_mentioned_p(op) || label_mentioned_p(op))))
+ return false;
+
+ return true;
+})
;; Test for valid PIC call operand
(define_predicate "call_insn_plt_operand"
diff --git a/gcc/config/mips/constraints.md b/gcc/config/mips/constraints.md
index 71ec938d85b..e73c440e1f4 100644
--- a/gcc/config/mips/constraints.md
+++ b/gcc/config/mips/constraints.md
@@ -43,6 +43,9 @@
(define_register_constraint "b" "ALL_REGS"
"@internal")
+(define_register_constraint "u" "M16_REGS"
+ "@internal")
+
;; MIPS16 code always calls through a MIPS16 register; see mips_emit_call_insn
;; for details.
(define_register_constraint "c" "TARGET_MIPS16 ? M16_REGS
@@ -170,21 +173,40 @@
(and (match_operand 0 "call_insn_operand")
(match_test "CONSTANT_P (op)")))
-(define_constraint "T"
+(define_constraint "Udb7"
"@internal
- A constant @code{move_operand} that cannot be safely loaded into @code{$25}
- using @code{la}."
- (and (match_operand 0 "move_operand")
- (match_test "CONSTANT_P (op)")
- (match_test "mips_dangerous_for_la25_p (op)")))
+ A decremented unsigned constant of 7 bits."
+ (match_operand 0 "db7_operand"))
-(define_constraint "U"
+(define_constraint "Uead"
"@internal
- A constant @code{move_operand} that can be safely loaded into @code{$25}
- using @code{la}."
- (and (match_operand 0 "move_operand")
- (match_test "CONSTANT_P (op)")
- (not (match_test "mips_dangerous_for_la25_p (op)"))))
+ A microMIPS encoded ADDIUR2 immediate operand."
+ (match_operand 0 "addiur2_operand"))
+
+(define_constraint "Uean"
+ "@internal
+ A microMIPS encoded ANDI operand."
+ (match_operand 0 "andi16_operand"))
+
+(define_constraint "Uesp"
+ "@internal
+ A microMIPS encoded ADDIUSP operand."
+ (match_operand 0 "addiusp_operand"))
+
+(define_constraint "Uib3"
+ "@internal
+ An unsigned, incremented constant of 3 bits."
+ (match_operand 0 "ib3_operand"))
+
+(define_constraint "Uuw6"
+ "@internal
+ An unsigned constant of 6 bits, shifted left two places."
+ (match_operand 0 "uw6_operand"))
+
+(define_constraint "Usb4"
+ "@internal
+ A signed constant of 4 bits."
+ (match_operand 0 "sb4_operand"))
(define_memory_constraint "W"
"@internal
@@ -220,6 +242,22 @@
"@internal"
(match_operand 0 "qi_mask_operand"))
+(define_constraint "Yd"
+ "@internal
+ A constant @code{move_operand} that can be safely loaded into @code{$25}
+ using @code{la}."
+ (and (match_operand 0 "move_operand")
+ (match_test "CONSTANT_P (op)")
+ (not (match_test "mips_dangerous_for_la25_p (op)"))))
+
+(define_constraint "Yf"
+ "@internal
+ A constant @code{move_operand} that cannot be safely loaded into @code{$25}
+ using @code{la}."
+ (and (match_operand 0 "move_operand")
+ (match_test "CONSTANT_P (op)")
+ (match_test "mips_dangerous_for_la25_p (op)")))
+
(define_constraint "Yh"
"@internal"
(match_operand 0 "hi_mask_operand"))
@@ -232,7 +270,59 @@
"@internal"
(match_operand 0 "low_bitmask_operand"))
+(define_memory_constraint "ZC"
+ "When compiling microMIPS code, this constraint matches a memory operand
+ whose address is formed from a base register and a 12-bit offset. These
+ operands can be used for microMIPS instructions such as @code{ll} and
+ @code{sc}. When not compiling for microMIPS code, @code{ZC} is
+ equivalent to @code{R}."
+ (and (match_code "mem")
+ (if_then_else
+ (match_test "TARGET_MICROMIPS")
+ (match_test "umips_12bit_offset_address_p (XEXP (op, 0), mode)")
+ (match_test "mips_address_insns (XEXP (op, 0), mode, false)"))))
+
+(define_address_constraint "ZD"
+ "When compiling microMIPS code, this constraint matches an address operand
+ that is formed from a base register and a 12-bit offset. These operands
+ can be used for microMIPS instructions such as @code{prefetch}. When
+ not compiling for microMIPS code, @code{ZD} is equivalent to @code{p}."
+ (if_then_else (match_test "TARGET_MICROMIPS")
+ (match_test "umips_12bit_offset_address_p (op, mode)")
+ (match_test "mips_address_insns (op, mode, false)")))
+
(define_memory_constraint "ZR"
"@internal
An address valid for loading/storing register exclusive"
(match_operand 0 "mem_noofs_operand"))
+
+(define_memory_constraint "ZS"
+ "@internal
+ A microMIPS memory operand for use with the LWSP/SWSP insns."
+ (and (match_code "mem")
+ (match_operand 0 "lwsp_swsp_operand")))
+
+(define_memory_constraint "ZT"
+ "@internal
+ A microMIPS memory operand for use with the LW16/SW16 insns."
+ (and (match_code "mem")
+ (match_operand 0 "lw16_sw16_operand")))
+
+(define_memory_constraint "ZU"
+ "@internal
+ A microMIPS memory operand for use with the LHU16/SH16 insns."
+ (and (match_code "mem")
+ (match_operand 0 "lhu16_sh16_operand")))
+
+(define_memory_constraint "ZV"
+ "@internal
+ A microMIPS memory operand for use with the SB16 insn."
+ (and (match_code "mem")
+ (match_operand 0 "sb16_operand")))
+
+(define_memory_constraint "ZW"
+ "@internal
+ A microMIPS memory operand for use with the LBU16 insn."
+ (and (match_code "mem")
+ (match_operand 0 "lbu16_operand")))
+
diff --git a/gcc/config/mips/micromips.md b/gcc/config/mips/micromips.md
index e69de29bb2d..4b7a4a7013f 100644
--- a/gcc/config/mips/micromips.md
+++ b/gcc/config/mips/micromips.md
@@ -0,0 +1,125 @@
+;; Copyright (C) 2013 Free Software Foundation, Inc.
+;;
+;; micromips.md Machine Description for the microMIPS instruction set
+;; This file is part of GCC.
+
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published
+;; by the Free Software Foundation; either version 3, or (at your
+;; option) any later version.
+
+;; GCC is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3. If not see
+;; <http://www.gnu.org/licenses/>.
+
+(define_insn "*store_word_multiple"
+ [(match_parallel 0 ""
+ [(set (match_operand:SI 1 "memory_operand")
+ (match_operand:SI 2 "register_operand"))])]
+ "TARGET_MICROMIPS
+ && umips_save_restore_pattern_p (true, operands[0])"
+ { return umips_output_save_restore (true, operands[0]); }
+ [(set_attr "type" "multimem")
+ (set_attr "mode" "SI")
+ (set_attr "can_delay" "no")])
+
+(define_insn "*load_word_multiple"
+ [(match_parallel 0 ""
+ [(set (match_operand:SI 1 "register_operand")
+ (match_operand:SI 2 "memory_operand"))])]
+ "TARGET_MICROMIPS
+ && umips_save_restore_pattern_p (false, operands[0])"
+ { return umips_output_save_restore (false, operands[0]); }
+ [(set_attr "type" "multimem")
+ (set_attr "mode" "SI")
+ (set_attr "can_delay" "no")])
+
+;; For LWP.
+(define_peephole2
+ [(set (match_operand:SI 0 "d_operand" "")
+ (match_operand:SI 1 "non_volatile_mem_operand" ""))
+ (set (match_operand:SI 2 "d_operand" "")
+ (match_operand:SI 3 "non_volatile_mem_operand" ""))]
+ "TARGET_MICROMIPS
+ && umips_load_store_pair_p (true, operands)"
+ [(parallel [(set (match_dup 0) (match_dup 1))
+ (set (match_dup 2) (match_dup 3))])])
+
+;; The behavior of the LWP insn is undefined if placed in a delay slot.
+(define_insn "*lwp"
+ [(parallel [(set (match_operand:SI 0 "d_operand")
+ (match_operand:SI 1 "non_volatile_mem_operand"))
+ (set (match_operand:SI 2 "d_operand")
+ (match_operand:SI 3 "non_volatile_mem_operand"))])]
+
+ "TARGET_MICROMIPS
+ && umips_load_store_pair_p (true, operands)"
+{
+ umips_output_load_store_pair (true, operands);
+ return "";
+}
+ [(set_attr "type" "load")
+ (set_attr "mode" "SI")
+ (set_attr "can_delay" "no")])
+
+;; For SWP.
+(define_peephole2
+ [(set (match_operand:SI 0 "non_volatile_mem_operand" "")
+ (match_operand:SI 1 "d_operand" ""))
+ (set (match_operand:SI 2 "non_volatile_mem_operand" "")
+ (match_operand:SI 3 "d_operand" ""))]
+ "TARGET_MICROMIPS
+ && umips_load_store_pair_p (false, operands)"
+ [(parallel [(set (match_dup 0) (match_dup 1))
+ (set (match_dup 2) (match_dup 3))])])
+
+;; The behavior of the SWP insn is undefined if placed in a delay slot.
+(define_insn "*swp"
+ [(parallel [(set (match_operand:SI 0 "non_volatile_mem_operand")
+ (match_operand:SI 1 "d_operand"))
+ (set (match_operand:SI 2 "non_volatile_mem_operand")
+ (match_operand:SI 3 "d_operand"))])]
+
+ "TARGET_MICROMIPS
+ && umips_load_store_pair_p (false, operands)"
+{
+ umips_output_load_store_pair (false, operands);
+ return "";
+}
+ [(set_attr "type" "store")
+ (set_attr "mode" "SI")
+ (set_attr "can_delay" "no")])
+
+;; For MOVEP.
+(define_peephole2
+ [(set (match_operand:MOVEP1 0 "register_operand" "")
+ (match_operand:MOVEP1 1 "movep_src_operand" ""))
+ (set (match_operand:MOVEP2 2 "register_operand" "")
+ (match_operand:MOVEP2 3 "movep_src_operand" ""))]
+ "TARGET_MICROMIPS
+ && umips_movep_target_p (operands[0], operands[2])"
+ [(parallel [(set (match_dup 0) (match_dup 1))
+ (set (match_dup 2) (match_dup 3))])])
+
+;; The behavior of the MOVEP insn is undefined if placed in a delay slot.
+(define_insn "*movep<MOVEP1:mode><MOVEP2:mode>"
+ [(parallel [(set (match_operand:MOVEP1 0 "register_operand")
+ (match_operand:MOVEP1 1 "movep_src_operand"))
+ (set (match_operand:MOVEP2 2 "register_operand")
+ (match_operand:MOVEP2 3 "movep_src_operand"))])]
+ "TARGET_MICROMIPS
+ && umips_movep_target_p (operands[0], operands[2])"
+{
+ if (REGNO (operands[0]) < REGNO (operands[2]))
+ return "movep\t%0,%2,%z1,%z3";
+ else
+ return "movep\t%2,%0,%z3,%z1";
+}
+ [(set_attr "type" "move")
+ (set_attr "mode" "<MODE>")
+ (set_attr "can_delay" "no")])
diff --git a/gcc/config/mips/mips-cpus.def b/gcc/config/mips/mips-cpus.def
index 93c305a7c7f..1cc19999373 100644
--- a/gcc/config/mips/mips-cpus.def
+++ b/gcc/config/mips/mips-cpus.def
@@ -92,6 +92,8 @@ MIPS_CPU ("4ksc", PROCESSOR_4KC, 32, 0)
/* MIPS32 Release 2 processors. */
MIPS_CPU ("m4k", PROCESSOR_M4K, 33, 0)
+MIPS_CPU ("m14kc", PROCESSOR_M4K, 33, 0)
+MIPS_CPU ("m14k", PROCESSOR_M4K, 33, 0)
MIPS_CPU ("4kec", PROCESSOR_4KC, 33, 0)
MIPS_CPU ("4kem", PROCESSOR_4KC, 33, 0)
MIPS_CPU ("4kep", PROCESSOR_4KP, 33, 0)
diff --git a/gcc/config/mips/mips-protos.h b/gcc/config/mips/mips-protos.h
index 8560bb7e9dd..3aaf69a7804 100644
--- a/gcc/config/mips/mips-protos.h
+++ b/gcc/config/mips/mips-protos.h
@@ -350,6 +350,17 @@ extern void mips_expand_vec_reduc (rtx, rtx, rtx (*)(rtx, rtx, rtx));
extern void mips_expand_vec_minmax (rtx, rtx, rtx,
rtx (*) (rtx, rtx, rtx), bool);
+extern bool mips_signed_immediate_p (unsigned HOST_WIDE_INT, int, int);
+extern bool mips_unsigned_immediate_p (unsigned HOST_WIDE_INT, int, int);
+extern const char *umips_output_save_restore (bool, rtx);
+extern bool umips_save_restore_pattern_p (bool, rtx);
+extern bool umips_load_store_pair_p (bool, rtx *);
+extern void umips_output_load_store_pair (bool, rtx *);
+extern bool umips_movep_target_p (rtx, rtx);
+extern bool umips_12bit_offset_address_p (rtx, enum machine_mode);
+extern bool lwsp_swsp_address_p (rtx, enum machine_mode);
+extern bool m16_based_address_p (rtx, enum machine_mode,
+ int (*)(rtx_def*, machine_mode));
extern rtx mips_expand_thread_pointer (rtx);
extern bool mips_eh_uses (unsigned int);
diff --git a/gcc/config/mips/mips-tables.opt b/gcc/config/mips/mips-tables.opt
index de9a736452e..0d7fa26510d 100644
--- a/gcc/config/mips/mips-tables.opt
+++ b/gcc/config/mips/mips-tables.opt
@@ -373,254 +373,260 @@ EnumValue
Enum(mips_arch_opt_value) String(m4k) Value(39) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(4kec) Value(40) Canonical
+Enum(mips_arch_opt_value) String(m14kc) Value(40) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r4kec) Value(40)
+Enum(mips_arch_opt_value) String(m14k) Value(41) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(4kem) Value(41) Canonical
+Enum(mips_arch_opt_value) String(4kec) Value(42) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r4kem) Value(41)
+Enum(mips_arch_opt_value) String(r4kec) Value(42)
EnumValue
-Enum(mips_arch_opt_value) String(4kep) Value(42) Canonical
+Enum(mips_arch_opt_value) String(4kem) Value(43) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r4kep) Value(42)
+Enum(mips_arch_opt_value) String(r4kem) Value(43)
EnumValue
-Enum(mips_arch_opt_value) String(4ksd) Value(43) Canonical
+Enum(mips_arch_opt_value) String(4kep) Value(44) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r4ksd) Value(43)
+Enum(mips_arch_opt_value) String(r4kep) Value(44)
EnumValue
-Enum(mips_arch_opt_value) String(24kc) Value(44) Canonical
+Enum(mips_arch_opt_value) String(4ksd) Value(45) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r24kc) Value(44)
+Enum(mips_arch_opt_value) String(r4ksd) Value(45)
EnumValue
-Enum(mips_arch_opt_value) String(24kf2_1) Value(45) Canonical
+Enum(mips_arch_opt_value) String(24kc) Value(46) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r24kf2_1) Value(45)
+Enum(mips_arch_opt_value) String(r24kc) Value(46)
EnumValue
-Enum(mips_arch_opt_value) String(24kf) Value(46) Canonical
+Enum(mips_arch_opt_value) String(24kf2_1) Value(47) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r24kf) Value(46)
+Enum(mips_arch_opt_value) String(r24kf2_1) Value(47)
EnumValue
-Enum(mips_arch_opt_value) String(24kf1_1) Value(47) Canonical
+Enum(mips_arch_opt_value) String(24kf) Value(48) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r24kf1_1) Value(47)
+Enum(mips_arch_opt_value) String(r24kf) Value(48)
EnumValue
-Enum(mips_arch_opt_value) String(24kfx) Value(48) Canonical
+Enum(mips_arch_opt_value) String(24kf1_1) Value(49) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r24kfx) Value(48)
+Enum(mips_arch_opt_value) String(r24kf1_1) Value(49)
EnumValue
-Enum(mips_arch_opt_value) String(24kx) Value(49) Canonical
+Enum(mips_arch_opt_value) String(24kfx) Value(50) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r24kx) Value(49)
+Enum(mips_arch_opt_value) String(r24kfx) Value(50)
EnumValue
-Enum(mips_arch_opt_value) String(24kec) Value(50) Canonical
+Enum(mips_arch_opt_value) String(24kx) Value(51) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r24kec) Value(50)
+Enum(mips_arch_opt_value) String(r24kx) Value(51)
EnumValue
-Enum(mips_arch_opt_value) String(24kef2_1) Value(51) Canonical
+Enum(mips_arch_opt_value) String(24kec) Value(52) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r24kef2_1) Value(51)
+Enum(mips_arch_opt_value) String(r24kec) Value(52)
EnumValue
-Enum(mips_arch_opt_value) String(24kef) Value(52) Canonical
+Enum(mips_arch_opt_value) String(24kef2_1) Value(53) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r24kef) Value(52)
+Enum(mips_arch_opt_value) String(r24kef2_1) Value(53)
EnumValue
-Enum(mips_arch_opt_value) String(24kef1_1) Value(53) Canonical
+Enum(mips_arch_opt_value) String(24kef) Value(54) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r24kef1_1) Value(53)
+Enum(mips_arch_opt_value) String(r24kef) Value(54)
EnumValue
-Enum(mips_arch_opt_value) String(24kefx) Value(54) Canonical
+Enum(mips_arch_opt_value) String(24kef1_1) Value(55) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r24kefx) Value(54)
+Enum(mips_arch_opt_value) String(r24kef1_1) Value(55)
EnumValue
-Enum(mips_arch_opt_value) String(24kex) Value(55) Canonical
+Enum(mips_arch_opt_value) String(24kefx) Value(56) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r24kex) Value(55)
+Enum(mips_arch_opt_value) String(r24kefx) Value(56)
EnumValue
-Enum(mips_arch_opt_value) String(34kc) Value(56) Canonical
+Enum(mips_arch_opt_value) String(24kex) Value(57) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r34kc) Value(56)
+Enum(mips_arch_opt_value) String(r24kex) Value(57)
EnumValue
-Enum(mips_arch_opt_value) String(34kf2_1) Value(57) Canonical
+Enum(mips_arch_opt_value) String(34kc) Value(58) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r34kf2_1) Value(57)
+Enum(mips_arch_opt_value) String(r34kc) Value(58)
EnumValue
-Enum(mips_arch_opt_value) String(34kf) Value(58) Canonical
+Enum(mips_arch_opt_value) String(34kf2_1) Value(59) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r34kf) Value(58)
+Enum(mips_arch_opt_value) String(r34kf2_1) Value(59)
EnumValue
-Enum(mips_arch_opt_value) String(34kf1_1) Value(59) Canonical
+Enum(mips_arch_opt_value) String(34kf) Value(60) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r34kf1_1) Value(59)
+Enum(mips_arch_opt_value) String(r34kf) Value(60)
EnumValue
-Enum(mips_arch_opt_value) String(34kfx) Value(60) Canonical
+Enum(mips_arch_opt_value) String(34kf1_1) Value(61) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r34kfx) Value(60)
+Enum(mips_arch_opt_value) String(r34kf1_1) Value(61)
EnumValue
-Enum(mips_arch_opt_value) String(34kx) Value(61) Canonical
+Enum(mips_arch_opt_value) String(34kfx) Value(62) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r34kx) Value(61)
+Enum(mips_arch_opt_value) String(r34kfx) Value(62)
EnumValue
-Enum(mips_arch_opt_value) String(34kn) Value(62) Canonical
+Enum(mips_arch_opt_value) String(34kx) Value(63) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r34kn) Value(62)
+Enum(mips_arch_opt_value) String(r34kx) Value(63)
EnumValue
-Enum(mips_arch_opt_value) String(74kc) Value(63) Canonical
+Enum(mips_arch_opt_value) String(34kn) Value(64) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r74kc) Value(63)
+Enum(mips_arch_opt_value) String(r34kn) Value(64)
EnumValue
-Enum(mips_arch_opt_value) String(74kf2_1) Value(64) Canonical
+Enum(mips_arch_opt_value) String(74kc) Value(65) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r74kf2_1) Value(64)
+Enum(mips_arch_opt_value) String(r74kc) Value(65)
EnumValue
-Enum(mips_arch_opt_value) String(74kf) Value(65) Canonical
+Enum(mips_arch_opt_value) String(74kf2_1) Value(66) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r74kf) Value(65)
+Enum(mips_arch_opt_value) String(r74kf2_1) Value(66)
EnumValue
-Enum(mips_arch_opt_value) String(74kf1_1) Value(66) Canonical
+Enum(mips_arch_opt_value) String(74kf) Value(67) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r74kf1_1) Value(66)
+Enum(mips_arch_opt_value) String(r74kf) Value(67)
EnumValue
-Enum(mips_arch_opt_value) String(74kfx) Value(67) Canonical
+Enum(mips_arch_opt_value) String(74kf1_1) Value(68) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r74kfx) Value(67)
+Enum(mips_arch_opt_value) String(r74kf1_1) Value(68)
EnumValue
-Enum(mips_arch_opt_value) String(74kx) Value(68) Canonical
+Enum(mips_arch_opt_value) String(74kfx) Value(69) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r74kx) Value(68)
+Enum(mips_arch_opt_value) String(r74kfx) Value(69)
EnumValue
-Enum(mips_arch_opt_value) String(74kf3_2) Value(69) Canonical
+Enum(mips_arch_opt_value) String(74kx) Value(70) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r74kf3_2) Value(69)
+Enum(mips_arch_opt_value) String(r74kx) Value(70)
EnumValue
-Enum(mips_arch_opt_value) String(1004kc) Value(70) Canonical
+Enum(mips_arch_opt_value) String(74kf3_2) Value(71) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r1004kc) Value(70)
+Enum(mips_arch_opt_value) String(r74kf3_2) Value(71)
EnumValue
-Enum(mips_arch_opt_value) String(1004kf2_1) Value(71) Canonical
+Enum(mips_arch_opt_value) String(1004kc) Value(72) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r1004kf2_1) Value(71)
+Enum(mips_arch_opt_value) String(r1004kc) Value(72)
EnumValue
-Enum(mips_arch_opt_value) String(1004kf) Value(72) Canonical
+Enum(mips_arch_opt_value) String(1004kf2_1) Value(73) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r1004kf) Value(72)
+Enum(mips_arch_opt_value) String(r1004kf2_1) Value(73)
EnumValue
-Enum(mips_arch_opt_value) String(1004kf1_1) Value(73) Canonical
+Enum(mips_arch_opt_value) String(1004kf) Value(74) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r1004kf1_1) Value(73)
+Enum(mips_arch_opt_value) String(r1004kf) Value(74)
EnumValue
-Enum(mips_arch_opt_value) String(5kc) Value(74) Canonical
+Enum(mips_arch_opt_value) String(1004kf1_1) Value(75) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r5kc) Value(74)
+Enum(mips_arch_opt_value) String(r1004kf1_1) Value(75)
EnumValue
-Enum(mips_arch_opt_value) String(5kf) Value(75) Canonical
+Enum(mips_arch_opt_value) String(5kc) Value(76) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r5kf) Value(75)
+Enum(mips_arch_opt_value) String(r5kc) Value(76)
EnumValue
-Enum(mips_arch_opt_value) String(20kc) Value(76) Canonical
+Enum(mips_arch_opt_value) String(5kf) Value(77) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(r20kc) Value(76)
+Enum(mips_arch_opt_value) String(r5kf) Value(77)
EnumValue
-Enum(mips_arch_opt_value) String(sb1) Value(77) Canonical
+Enum(mips_arch_opt_value) String(20kc) Value(78) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(sb1a) Value(78) Canonical
+Enum(mips_arch_opt_value) String(r20kc) Value(78)
EnumValue
-Enum(mips_arch_opt_value) String(sr71000) Value(79) Canonical
+Enum(mips_arch_opt_value) String(sb1) Value(79) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(sr71k) Value(79)
+Enum(mips_arch_opt_value) String(sb1a) Value(80) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(xlr) Value(80) Canonical
+Enum(mips_arch_opt_value) String(sr71000) Value(81) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(loongson3a) Value(81) Canonical
+Enum(mips_arch_opt_value) String(sr71k) Value(81)
EnumValue
-Enum(mips_arch_opt_value) String(octeon) Value(82) Canonical
+Enum(mips_arch_opt_value) String(xlr) Value(82) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(octeon+) Value(83) Canonical
+Enum(mips_arch_opt_value) String(loongson3a) Value(83) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(octeon2) Value(84) Canonical
+Enum(mips_arch_opt_value) String(octeon) Value(84) Canonical
EnumValue
-Enum(mips_arch_opt_value) String(xlp) Value(85) Canonical
+Enum(mips_arch_opt_value) String(octeon+) Value(85) Canonical
+
+EnumValue
+Enum(mips_arch_opt_value) String(octeon2) Value(86) Canonical
+
+EnumValue
+Enum(mips_arch_opt_value) String(xlp) Value(87) Canonical
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index 53804298f2a..3d356b456ab 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -77,6 +77,9 @@ along with GCC; see the file COPYING3. If not see
preserve the maximum stack alignment. We therefore use a value
of 0x7ff0 in this case.
+ microMIPS LWM and SWM support 12-bit offsets (from -0x800 to 0x7ff),
+ so we use a maximum of 0x7f0 for TARGET_MICROMIPS.
+
MIPS16e SAVE and RESTORE instructions can adjust the stack pointer by
up to 0x7f8 bytes and can usually save or restore all the registers
that we need to save or restore. (Note that we can only use these
@@ -87,8 +90,8 @@ along with GCC; see the file COPYING3. If not see
to save and restore registers, and to allocate and deallocate the top
part of the frame. */
#define MIPS_MAX_FIRST_STACK_STEP \
- (!TARGET_MIPS16 ? 0x7ff0 \
- : GENERATE_MIPS16E_SAVE_RESTORE ? 0x7f8 \
+ (!TARGET_COMPRESSION ? 0x7ff0 \
+ : TARGET_MICROMIPS || GENERATE_MIPS16E_SAVE_RESTORE ? 0x7f8 \
: TARGET_64BIT ? 0x100 : 0x400)
/* True if INSN is a mips.md pattern or asm statement. */
@@ -560,8 +563,8 @@ static const struct mips_rtx_cost_data *mips_cost;
/* The ambient target flags, excluding MASK_MIPS16. */
static int mips_base_target_flags;
-/* True if MIPS16 is the default mode. */
-bool mips_base_mips16;
+/* The default compression mode. */
+unsigned int mips_base_compression_flags;
/* The ambient values of other global variables. */
static int mips_base_schedule_insns; /* flag_schedule_insns */
@@ -674,6 +677,9 @@ static const struct attribute_spec mips_attribute_table[] = {
code generation but don't carry other semantics. */
{ "mips16", 0, 0, true, false, false, NULL, false },
{ "nomips16", 0, 0, true, false, false, NULL, false },
+ { "micromips", 0, 0, true, false, false, NULL, false },
+ { "nomicromips", 0, 0, true, false, false, NULL, false },
+ { "nocompression", 0, 0, true, false, false, NULL, false },
/* Allow functions to be specified as interrupt handlers */
{ "interrupt", 0, 0, false, true, true, NULL, false },
{ "use_shadow_register_set", 0, 0, false, true, true, NULL, false },
@@ -1167,10 +1173,11 @@ mflip_mips16_use_mips16_p (tree decl)
const char *name;
hashval_t hash;
void **slot;
+ bool base_is_mips16 = (mips_base_compression_flags & MASK_MIPS16) != 0;
/* Use the opposite of the command-line setting for anonymous decls. */
if (!DECL_NAME (decl))
- return !mips_base_mips16;
+ return !base_is_mips16;
if (!mflip_mips16_htab)
mflip_mips16_htab = htab_create_ggc (37, mflip_mips16_htab_hash,
@@ -1185,7 +1192,7 @@ mflip_mips16_use_mips16_p (tree decl)
mips16_flipper = !mips16_flipper;
entry = ggc_alloc_mflip_mips16_entry ();
entry->name = name;
- entry->mips16_p = mips16_flipper ? !mips_base_mips16 : mips_base_mips16;
+ entry->mips16_p = mips16_flipper ? !base_is_mips16 : base_is_mips16;
*slot = entry;
}
return entry->mips16_p;
@@ -1207,19 +1214,6 @@ mips_far_type_p (const_tree type)
|| lookup_attribute ("far", TYPE_ATTRIBUTES (type)) != NULL);
}
-/* Similar predicates for "mips16"/"nomips16" function attributes. */
-
-static bool
-mips_mips16_decl_p (const_tree decl)
-{
- return lookup_attribute ("mips16", DECL_ATTRIBUTES (decl)) != NULL;
-}
-
-static bool
-mips_nomips16_decl_p (const_tree decl)
-{
- return lookup_attribute ("nomips16", DECL_ATTRIBUTES (decl)) != NULL;
-}
/* Check if the interrupt attribute is set for a function. */
@@ -1257,12 +1251,52 @@ mips_use_debug_exception_return_p (tree type)
TYPE_ATTRIBUTES (type)) != NULL;
}
-/* Return true if function DECL is a MIPS16 function. Return the ambient
- setting if DECL is null. */
+/* Return the set of compression modes that are explicitly required
+ by the attributes in ATTRIBUTES. */
-static bool
-mips_use_mips16_mode_p (tree decl)
+static unsigned int
+mips_get_compress_on_flags (tree attributes)
+{
+ unsigned int flags = 0;
+
+ if (lookup_attribute ("mips16", attributes) != NULL)
+ flags |= MASK_MIPS16;
+
+ if (lookup_attribute ("micromips", attributes) != NULL)
+ flags |= MASK_MICROMIPS;
+
+ return flags;
+}
+
+/* Return the set of compression modes that are explicitly forbidden
+ by the attributes in ATTRIBUTES. */
+
+static unsigned int
+mips_get_compress_off_flags (tree attributes)
+{
+ unsigned int flags = 0;
+
+ if (lookup_attribute ("nocompression", attributes) != NULL)
+ flags |= MASK_MIPS16 | MASK_MICROMIPS;
+
+ if (lookup_attribute ("nomips16", attributes) != NULL)
+ flags |= MASK_MIPS16;
+
+ if (lookup_attribute ("nomicromips", attributes) != NULL)
+ flags |= MASK_MICROMIPS;
+
+ return flags;
+}
+
+/* Return the compression mode that should be used for function DECL.
+ Return the ambient setting if DECL is null. */
+
+static unsigned int
+mips_get_compress_mode (tree decl)
{
+ unsigned int flags, force_on;
+
+ flags = mips_base_compression_flags;
if (decl)
{
/* Nested functions must use the same frame pointer as their
@@ -1270,12 +1304,36 @@ mips_use_mips16_mode_p (tree decl)
tree parent = decl_function_context (decl);
if (parent)
decl = parent;
- if (mips_mips16_decl_p (decl))
- return true;
- if (mips_nomips16_decl_p (decl))
- return false;
+ force_on = mips_get_compress_on_flags (DECL_ATTRIBUTES (decl));
+ if (force_on)
+ return force_on;
+ flags &= ~mips_get_compress_off_flags (DECL_ATTRIBUTES (decl));
}
- return mips_base_mips16;
+ return flags;
+}
+
+/* Return the attribute name associated with MASK_MIPS16 and MASK_MICROMIPS
+ flags FLAGS. */
+
+static const char *
+mips_get_compress_on_name (unsigned int flags)
+{
+ if (flags == MASK_MIPS16)
+ return "mips16";
+ return "micromips";
+}
+
+/* Return the attribute name that forbids MASK_MIPS16 and MASK_MICROMIPS
+ flags FLAGS. */
+
+static const char *
+mips_get_compress_off_name (unsigned int flags)
+{
+ if (flags == MASK_MIPS16)
+ return "nomips16";
+ if (flags == MASK_MICROMIPS)
+ return "nomicromips";
+ return "nocompression";
}
/* Implement TARGET_COMP_TYPE_ATTRIBUTES. */
@@ -1297,37 +1355,50 @@ static void
mips_insert_attributes (tree decl, tree *attributes)
{
const char *name;
- bool mips16_p, nomips16_p;
+ unsigned int compression_flags, nocompression_flags;
/* Check for "mips16" and "nomips16" attributes. */
- mips16_p = lookup_attribute ("mips16", *attributes) != NULL;
- nomips16_p = lookup_attribute ("nomips16", *attributes) != NULL;
+ compression_flags = mips_get_compress_on_flags (*attributes);
+ nocompression_flags = mips_get_compress_off_flags (*attributes);
+
if (TREE_CODE (decl) != FUNCTION_DECL)
{
- if (mips16_p)
- error ("%qs attribute only applies to functions", "mips16");
- if (nomips16_p)
- error ("%qs attribute only applies to functions", "nomips16");
+ if (nocompression_flags)
+ error ("%qs attribute only applies to functions",
+ mips_get_compress_off_name (nocompression_flags));
+
+ if (compression_flags)
+ error ("%qs attribute only applies to functions",
+ mips_get_compress_on_name (nocompression_flags));
}
else
{
- mips16_p |= mips_mips16_decl_p (decl);
- nomips16_p |= mips_nomips16_decl_p (decl);
- if (mips16_p || nomips16_p)
- {
- /* DECL cannot be simultaneously "mips16" and "nomips16". */
- if (mips16_p && nomips16_p)
- error ("%qE cannot have both %<mips16%> and "
- "%<nomips16%> attributes",
- DECL_NAME (decl));
- }
- else if (TARGET_FLIP_MIPS16 && !DECL_ARTIFICIAL (decl))
+ compression_flags |= mips_get_compress_on_flags (DECL_ATTRIBUTES (decl));
+ nocompression_flags |=
+ mips_get_compress_off_flags (DECL_ATTRIBUTES (decl));
+
+ if (compression_flags && nocompression_flags)
+ error ("%qE cannot have both %qs and %qs attributes",
+ DECL_NAME (decl), mips_get_compress_on_name (compression_flags),
+ mips_get_compress_off_name (nocompression_flags));
+
+ if (compression_flags & MASK_MIPS16
+ && compression_flags & MASK_MICROMIPS)
+ error ("%qE cannot have both %qs and %qs attributes",
+ DECL_NAME (decl), "mips16", "micromips");
+
+ if (TARGET_FLIP_MIPS16
+ && !DECL_ARTIFICIAL (decl)
+ && compression_flags == 0
+ && nocompression_flags == 0)
{
/* Implement -mflip-mips16. If DECL has neither a "nomips16" nor a
"mips16" attribute, arbitrarily pick one. We must pick the same
setting for duplicate declarations of a function. */
name = mflip_mips16_use_mips16_p (decl) ? "mips16" : "nomips16";
*attributes = tree_cons (get_identifier (name), NULL, *attributes);
+ name = "nomicromips";
+ *attributes = tree_cons (get_identifier (name), NULL, *attributes);
}
}
}
@@ -1337,13 +1408,19 @@ mips_insert_attributes (tree decl, tree *attributes)
static tree
mips_merge_decl_attributes (tree olddecl, tree newdecl)
{
- /* The decls' "mips16" and "nomips16" attributes must match exactly. */
- if (mips_mips16_decl_p (olddecl) != mips_mips16_decl_p (newdecl))
+ unsigned int diff;
+
+ diff = (mips_get_compress_on_flags (DECL_ATTRIBUTES (olddecl))
+ ^ mips_get_compress_on_flags (DECL_ATTRIBUTES (newdecl)));
+ if (diff)
error ("%qE redeclared with conflicting %qs attributes",
- DECL_NAME (newdecl), "mips16");
- if (mips_nomips16_decl_p (olddecl) != mips_nomips16_decl_p (newdecl))
+ DECL_NAME (newdecl), mips_get_compress_on_name (diff));
+
+ diff = (mips_get_compress_off_flags (DECL_ATTRIBUTES (olddecl))
+ ^ mips_get_compress_off_flags (DECL_ATTRIBUTES (newdecl)));
+ if (diff)
error ("%qE redeclared with conflicting %qs attributes",
- DECL_NAME (newdecl), "nomips16");
+ DECL_NAME (newdecl), mips_get_compress_off_name (diff));
return merge_attributes (DECL_ATTRIBUTES (olddecl),
DECL_ATTRIBUTES (newdecl));
@@ -1550,7 +1627,7 @@ mips16_local_function_p (const_rtx x)
return (GET_CODE (x) == SYMBOL_REF
&& SYMBOL_REF_LOCAL_P (x)
&& !SYMBOL_REF_EXTERNAL_P (x)
- && mips_use_mips16_mode_p (SYMBOL_REF_DECL (x)));
+ && (mips_get_compress_mode (SYMBOL_REF_DECL (x)) & MASK_MIPS16));
}
/* Return true if SYMBOL_REF X binds locally. */
@@ -2300,6 +2377,69 @@ mips_address_insns (rtx x, enum machine_mode mode, bool might_split_p)
return 0;
}
+/* Return true if X fits within an unsigned field of BITS bits that is
+ shifted left SHIFT bits before being used. */
+
+bool
+mips_unsigned_immediate_p (unsigned HOST_WIDE_INT x, int bits, int shift = 0)
+{
+ return (x & ((1 << shift) - 1)) == 0 && x < ((unsigned) 1 << (shift + bits));
+}
+
+/* Return true if X fits within a signed field of BITS bits that is
+ shifted left SHIFT bits before being used. */
+
+bool
+mips_signed_immediate_p (unsigned HOST_WIDE_INT x, int bits, int shift = 0)
+{
+ x += 1 << (bits + shift - 1);
+ return mips_unsigned_immediate_p (x, bits, shift);
+}
+
+/* Return true if X is legitimate for accessing values of mode MODE,
+ if it is based on a MIPS16 register, and if the offset satisfies
+ OFFSET_PREDICATE. */
+
+bool
+m16_based_address_p (rtx x, enum machine_mode mode,
+ insn_operand_predicate_fn offset_predicate)
+{
+ struct mips_address_info addr;
+
+ return (mips_classify_address (&addr, x, mode, false)
+ && addr.type == ADDRESS_REG
+ && M16_REG_P (REGNO (addr.reg))
+ && offset_predicate (addr.offset, mode));
+}
+
+/* Return true if X is a legitimate address that conforms to the requirements
+ for a microMIPS LWSP or SWSP insn. */
+
+bool
+lwsp_swsp_address_p (rtx x, enum machine_mode mode)
+{
+ struct mips_address_info addr;
+
+ return (mips_classify_address (&addr, x, mode, false)
+ && addr.type == ADDRESS_REG
+ && REGNO (addr.reg) == STACK_POINTER_REGNUM
+ && uw5_operand (addr.offset, mode));
+}
+
+/* Return true if X is a legitimate address with a 12-bit offset.
+ MODE is the mode of the value being accessed. */
+
+bool
+umips_12bit_offset_address_p (rtx x, enum machine_mode mode)
+{
+ struct mips_address_info addr;
+
+ return (mips_classify_address (&addr, x, mode, false)
+ && addr.type == ADDRESS_REG
+ && CONST_INT_P (addr.offset)
+ && UMIPS_12BIT_OFFSET_P (INTVAL (addr.offset)));
+}
+
/* Return the number of instructions needed to load constant X.
Return 0 if X isn't a valid constant. */
@@ -6097,6 +6237,13 @@ mips_start_function_definition (const char *name, bool mips16_p)
else
fprintf (asm_out_file, "\t.set\tnomips16\n");
+ if (TARGET_MICROMIPS)
+ fprintf (asm_out_file, "\t.set\tmicromips\n");
+#ifdef HAVE_GAS_MICROMIPS
+ else
+ fprintf (asm_out_file, "\t.set\tnomicromips\n");
+#endif
+
if (!flag_inhibit_size_directive)
{
fputs ("\t.ent\t", asm_out_file);
@@ -6903,6 +7050,37 @@ mips_split_call (rtx insn, rtx call_pattern)
mips_restore_gp_from_cprestore_slot (gen_rtx_REG (Pmode, GP_ARG_FIRST + 2));
}
+/* Return true if a call to DECL may need to use JALX. */
+
+static bool
+mips_call_may_need_jalx_p (tree decl)
+{
+ /* If the current translation unit would use a different mode for DECL,
+ assume that the call needs JALX. */
+ if (mips_get_compress_mode (decl) != TARGET_COMPRESSION)
+ return true;
+
+ /* mips_get_compress_mode is always accurate for locally-binding
+ functions in the current translation unit. */
+ if (!DECL_EXTERNAL (decl) && targetm.binds_local_p (decl))
+ return false;
+
+ /* When -minterlink-compressed is in effect, assume that functions
+ could use a different encoding mode unless an attribute explicitly
+ tells us otherwise. */
+ if (TARGET_INTERLINK_COMPRESSED)
+ {
+ if (!TARGET_COMPRESSION
+ && mips_get_compress_off_flags (DECL_ATTRIBUTES (decl)) ==0)
+ return true;
+ if (TARGET_COMPRESSION
+ && mips_get_compress_on_flags (DECL_ATTRIBUTES (decl)) == 0)
+ return true;
+ }
+
+ return false;
+}
+
/* Implement TARGET_FUNCTION_OK_FOR_SIBCALL. */
static bool
@@ -6916,23 +7094,11 @@ mips_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
if (mips_interrupt_type_p (TREE_TYPE (current_function_decl)))
return false;
- /* We can't do a sibcall if the called function is a MIPS16 function
- because there is no direct "jx" instruction equivalent to "jalx" to
- switch the ISA mode. We only care about cases where the sibling
- and normal calls would both be direct. */
+ /* Direct Js are only possible to functions that use the same ISA encoding.
+ There is no JX counterpoart of JALX. */
if (decl
- && mips_use_mips16_mode_p (decl)
- && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
- return false;
-
- /* When -minterlink-mips16 is in effect, assume that non-locally-binding
- functions could be MIPS16 ones unless an attribute explicitly tells
- us otherwise. */
- if (TARGET_INTERLINK_MIPS16
- && decl
- && (DECL_EXTERNAL (decl) || !targetm.binds_local_p (decl))
- && !mips_nomips16_decl_p (decl)
- && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
+ && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode)
+ && mips_call_may_need_jalx_p (decl))
return false;
/* Otherwise OK. */
@@ -7798,6 +7964,9 @@ mips_pop_asm_switch (struct mips_asm_switch *asm_switch)
'^' Print the name of the pic call-through register (t9 or $25).
'+' Print the name of the gp register (usually gp or $28).
'$' Print the name of the stack pointer register (sp or $29).
+ ':' Print "c" to use the compact version if the delay slot is a nop.
+ '!' Print "s" to use the short version if the delay slot contains a
+ 16-bit instruction.
See also mips_init_print_operand_pucnt. */
@@ -7881,6 +8050,21 @@ mips_print_operand_punctuation (FILE *file, int ch)
fputs (reg_names[STACK_POINTER_REGNUM], file);
break;
+ case ':':
+ /* When final_sequence is 0, the delay slot will be a nop. We can
+ use the compact version for microMIPS. */
+ if (final_sequence == 0)
+ putc ('c', file);
+ break;
+
+ case '!':
+ /* If the delay slot instruction is short, then use the
+ compact version. */
+ if (final_sequence == 0
+ || get_attr_length (XVECEXP (final_sequence, 0, 1)) == 2)
+ putc ('s', file);
+ break;
+
default:
gcc_unreachable ();
break;
@@ -7894,7 +8078,7 @@ mips_init_print_operand_punct (void)
{
const char *p;
- for (p = "()[]<>*#/?~.@^+$"; *p; p++)
+ for (p = "()[]<>*#/?~.@^+$:!"; *p; p++)
mips_print_operand_punct[(unsigned char) *p] = true;
}
@@ -10236,6 +10420,126 @@ mips_for_each_saved_acc (HOST_WIDE_INT sp_offset, mips_save_restore_fn fn)
}
}
+/* Save register REG to MEM. Make the instruction frame-related. */
+
+static void
+mips_save_reg (rtx reg, rtx mem)
+{
+ if (GET_MODE (reg) == DFmode && !TARGET_FLOAT64)
+ {
+ rtx x1, x2;
+
+ mips_emit_move_or_split (mem, reg, SPLIT_IF_NECESSARY);
+
+ x1 = mips_frame_set (mips_subword (mem, false),
+ mips_subword (reg, false));
+ x2 = mips_frame_set (mips_subword (mem, true),
+ mips_subword (reg, true));
+ mips_set_frame_expr (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, x1, x2)));
+ }
+ else
+ mips_emit_save_slot_move (mem, reg, MIPS_PROLOGUE_TEMP (GET_MODE (reg)));
+}
+
+/* Capture the register combinations that are allowed in a SWM or LWM
+ instruction. The entries are ordered by number of registers set in
+ the mask. We also ignore the single register encodings because a
+ normal SW/LW is preferred. */
+
+static const unsigned int umips_swm_mask[17] = {
+ 0xc0ff0000, 0x80ff0000, 0x40ff0000, 0x807f0000,
+ 0x00ff0000, 0x803f0000, 0x007f0000, 0x801f0000,
+ 0x003f0000, 0x800f0000, 0x001f0000, 0x80070000,
+ 0x000f0000, 0x80030000, 0x00070000, 0x80010000,
+ 0x00030000
+};
+
+static const unsigned int umips_swm_encoding[17] = {
+ 25, 24, 9, 23, 8, 22, 7, 21, 6, 20, 5, 19, 4, 18, 3, 17, 2
+};
+
+/* Try to use a microMIPS LWM or SWM instruction to save or restore
+ as many GPRs in *MASK as possible. *OFFSET is the offset from the
+ stack pointer of the topmost save slot.
+
+ Remove from *MASK all registers that were handled using LWM and SWM.
+ Update *OFFSET so that it points to the first unused save slot. */
+
+static bool
+umips_build_save_restore (mips_save_restore_fn fn,
+ unsigned *mask, HOST_WIDE_INT *offset)
+{
+ int nregs;
+ unsigned int i, j;
+ rtx pattern, set, reg, mem;
+ HOST_WIDE_INT this_offset;
+ rtx this_base;
+
+ /* Try matching $16 to $31 (s0 to ra). */
+ for (i = 0; i < ARRAY_SIZE (umips_swm_mask); i++)
+ if ((*mask & 0xffff0000) == umips_swm_mask[i])
+ break;
+
+ if (i == ARRAY_SIZE (umips_swm_mask))
+ return false;
+
+ /* Get the offset of the lowest save slot. */
+ nregs = (umips_swm_encoding[i] & 0xf) + (umips_swm_encoding[i] >> 4);
+ this_offset = *offset - UNITS_PER_WORD * (nregs - 1);
+
+ /* LWM/SWM can only support offsets from -2048 to 2047. */
+ if (!UMIPS_12BIT_OFFSET_P (this_offset))
+ return false;
+
+ /* Create the final PARALLEL. */
+ pattern = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nregs));
+ this_base = stack_pointer_rtx;
+
+ /* For registers $16-$23 and $30. */
+ for (j = 0; j < (umips_swm_encoding[i] & 0xf); j++)
+ {
+ HOST_WIDE_INT offset = this_offset + j * UNITS_PER_WORD;
+ mem = gen_frame_mem (SImode, plus_constant (Pmode, this_base, offset));
+ unsigned int regno = (j != 8) ? 16 + j : 30;
+ *mask &= ~(1 << regno);
+ reg = gen_rtx_REG (SImode, regno);
+ if (fn == mips_save_reg)
+ set = mips_frame_set (mem, reg);
+ else
+ {
+ set = gen_rtx_SET (VOIDmode, reg, mem);
+ mips_add_cfa_restore (reg);
+ }
+ XVECEXP (pattern, 0, j) = set;
+ }
+
+ /* For register $31. */
+ if (umips_swm_encoding[i] >> 4)
+ {
+ HOST_WIDE_INT offset = this_offset + j * UNITS_PER_WORD;
+ *mask &= ~(1 << 31);
+ mem = gen_frame_mem (SImode, plus_constant (Pmode, this_base, offset));
+ reg = gen_rtx_REG (SImode, 31);
+ if (fn == mips_save_reg)
+ set = mips_frame_set (mem, reg);
+ else
+ {
+ set = gen_rtx_SET (VOIDmode, reg, mem);
+ mips_add_cfa_restore (reg);
+ }
+ XVECEXP (pattern, 0, j) = set;
+ }
+
+ pattern = emit_insn (pattern);
+ if (fn == mips_save_reg)
+ RTX_FRAME_RELATED_P (pattern) = 1;
+
+ /* Adjust the last offset. */
+ *offset -= UNITS_PER_WORD * nregs;
+
+ return true;
+}
+
/* Call FN for each register that is saved by the current function.
SP_OFFSET is the offset of the current stack pointer from the start
of the frame. */
@@ -10245,16 +10549,23 @@ mips_for_each_saved_gpr_and_fpr (HOST_WIDE_INT sp_offset,
mips_save_restore_fn fn)
{
enum machine_mode fpr_mode;
- HOST_WIDE_INT offset;
int regno;
+ const struct mips_frame_info *frame = &cfun->machine->frame;
+ HOST_WIDE_INT offset;
+ unsigned int mask;
/* Save registers starting from high to low. The debuggers prefer at least
the return register be stored at func+4, and also it allows us not to
need a nop in the epilogue if at least one register is reloaded in
addition to return address. */
- offset = cfun->machine->frame.gp_sp_offset - sp_offset;
+ offset = frame->gp_sp_offset - sp_offset;
+ mask = frame->mask;
+
+ if (TARGET_MICROMIPS)
+ umips_build_save_restore (fn, &mask, &offset);
+
for (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--)
- if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
+ if (BITSET_P (mask, regno - GP_REG_FIRST))
{
/* Record the ra offset for use by mips_function_profiler. */
if (regno == RETURN_ADDR_REGNUM)
@@ -10501,26 +10812,6 @@ mips_frame_barrier (void)
emit_clobber (gen_frame_mem (BLKmode, stack_pointer_rtx));
}
-/* Save register REG to MEM. Make the instruction frame-related. */
-
-static void
-mips_save_reg (rtx reg, rtx mem)
-{
- if (GET_MODE (reg) == DFmode && !TARGET_FLOAT64)
- {
- rtx x1, x2;
-
- mips_emit_move_or_split (mem, reg, SPLIT_IF_NECESSARY);
-
- x1 = mips_frame_set (mips_subword (mem, false),
- mips_subword (reg, false));
- x2 = mips_frame_set (mips_subword (mem, true),
- mips_subword (reg, true));
- mips_set_frame_expr (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, x1, x2)));
- }
- else
- mips_emit_save_slot_move (mem, reg, MIPS_PROLOGUE_TEMP (GET_MODE (reg)));
-}
/* The __gnu_local_gp symbol. */
@@ -11239,7 +11530,7 @@ mips_expand_epilogue (bool sibcall_p)
mips_emit_move (gen_rtx_REG (word_mode, K0_REG_NUM), mem);
offset -= UNITS_PER_WORD;
- /* If we don't use shoadow register set, we need to update SP. */
+ /* If we don't use shadow register set, we need to update SP. */
if (!cfun->machine->use_shadow_register_set_p)
mips_deallocate_stack (stack_pointer_rtx, GEN_INT (step2), 0);
else
@@ -11254,6 +11545,7 @@ mips_expand_epilogue (bool sibcall_p)
/* Deallocate the final bit of the frame. */
mips_deallocate_stack (stack_pointer_rtx, GEN_INT (step2), 0);
}
+
gcc_assert (!mips_epilogue.cfa_restores);
/* Add in the __builtin_eh_return stack adjustment. We need to
@@ -16224,17 +16516,19 @@ mips_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
reload_completed = 0;
}
-/* The last argument passed to mips_set_mips16_mode, or negative if the
- function hasn't been called yet. */
-static int was_mips16_p = -1;
-/* Set up the target-dependent global state so that it matches the
- current function's ISA mode. */
+/* The last argument passed to mips_set_compression_mode,
+ or negative if the function hasn't been called yet. */
+static unsigned int old_compression_mode = -1;
+
+/* Set up the target-dependent global state for ISA mode COMPRESSION_MODE,
+ which is either MASK_MIPS16 or MASK_MICROMIPS. */
static void
-mips_set_mips16_mode (int mips16_p)
+mips_set_compression_mode (unsigned int compression_mode)
{
- if (mips16_p == was_mips16_p)
+
+ if (compression_mode == old_compression_mode)
return;
/* Restore base settings of various flags. */
@@ -16245,8 +16539,10 @@ mips_set_mips16_mode (int mips16_p)
align_loops = mips_base_align_loops;
align_jumps = mips_base_align_jumps;
align_functions = mips_base_align_functions;
+ target_flags &= ~(MASK_MIPS16 | MASK_MICROMIPS);
+ target_flags |= compression_mode;
- if (mips16_p)
+ if (compression_mode & MASK_MIPS16)
{
/* Switch to MIPS16 mode. */
target_flags |= MASK_MIPS16;
@@ -16300,8 +16596,11 @@ mips_set_mips16_mode (int mips16_p)
}
else
{
- /* Switch to normal (non-MIPS16) mode. */
- target_flags &= ~MASK_MIPS16;
+ /* Switch to microMIPS or the standard encoding. */
+
+ if (TARGET_MICROMIPS)
+ /* Avoid branch likely. */
+ target_flags &= ~MASK_BRANCHLIKELY;
/* Provide default values for align_* for 64-bit targets. */
if (TARGET_64BIT)
@@ -16323,7 +16622,7 @@ mips_set_mips16_mode (int mips16_p)
/* (Re)initialize MIPS target internals for new ISA. */
mips_init_relocs ();
- if (mips16_p)
+ if (compression_mode & MASK_MIPS16)
{
if (!mips16_globals)
mips16_globals = save_target_globals_default_opts ();
@@ -16333,16 +16632,17 @@ mips_set_mips16_mode (int mips16_p)
else
restore_target_globals (&default_target_globals);
- was_mips16_p = mips16_p;
+ old_compression_mode = compression_mode;
}
/* Implement TARGET_SET_CURRENT_FUNCTION. Decide whether the current
- function should use the MIPS16 ISA and switch modes accordingly. */
+ function should use the MIPS16 or microMIPS ISA and switch modes
+ accordingly. */
static void
mips_set_current_function (tree fndecl)
{
- mips_set_mips16_mode (mips_use_mips16_mode_p (fndecl));
+ mips_set_compression_mode (mips_get_compress_mode (fndecl));
}
/* Allocate a chunk of memory for per-function machine-dependent data. */
@@ -16450,14 +16750,19 @@ mips_option_override (void)
if (global_options_set.x_mips_isa_option)
mips_isa_option_info = &mips_cpu_info_table[mips_isa_option];
- /* Process flags as though we were generating non-MIPS16 code. */
- mips_base_mips16 = TARGET_MIPS16;
- target_flags &= ~MASK_MIPS16;
-
#ifdef SUBTARGET_OVERRIDE_OPTIONS
SUBTARGET_OVERRIDE_OPTIONS;
#endif
+ /* MIPS16 and microMIPS cannot coexist. */
+ if (TARGET_MICROMIPS && TARGET_MIPS16)
+ error ("unsupported combination: %s", "-mips16 -mmicromips");
+
+ /* Save the base compression state and process flags as though we
+ were generating uncompressed code. */
+ mips_base_compression_flags = TARGET_COMPRESSION;
+ target_flags &= ~TARGET_COMPRESSION;
+
/* -mno-float overrides -mhard-float and -msoft-float. */
if (TARGET_NO_FLOAT)
{
@@ -16466,7 +16771,7 @@ mips_option_override (void)
}
if (TARGET_FLIP_MIPS16)
- TARGET_INTERLINK_MIPS16 = 1;
+ TARGET_INTERLINK_COMPRESSED = 1;
/* Set the small data limit. */
mips_small_data_threshold = (global_options_set.x_g_switch_value
@@ -16839,9 +17144,9 @@ mips_option_override (void)
/* Now select the ISA mode.
- Do all CPP-sensitive stuff in non-MIPS16 mode; we'll switch to
- MIPS16 mode afterwards if need be. */
- mips_set_mips16_mode (false);
+ Do all CPP-sensitive stuff in uncompressed mode; we'll switch modes
+ later if required. */
+ mips_set_compression_mode (0);
}
/* Swap the register information for registers I and I + 1, which
@@ -17101,6 +17406,277 @@ mips_mulsidi3_gen_fn (enum rtx_code ext_code)
return signed_p ? gen_mulsidi3_32bit : gen_umulsidi3_32bit;
}
}
+
+/* Return true if PATTERN matches the kind of instruction generated by
+ umips_build_save_restore. SAVE_P is true for store. */
+
+bool
+umips_save_restore_pattern_p (bool save_p, rtx pattern)
+{
+ int n;
+ unsigned int i;
+ HOST_WIDE_INT first_offset = 0;
+ rtx first_base = 0;
+ unsigned int regmask = 0;
+
+ for (n = 0; n < XVECLEN (pattern, 0); n++)
+ {
+ rtx set, reg, mem, this_base;
+ HOST_WIDE_INT this_offset;
+
+ /* Check that we have a SET. */
+ set = XVECEXP (pattern, 0, n);
+ if (GET_CODE (set) != SET)
+ return false;
+
+ /* Check that the SET is a load (if restoring) or a store
+ (if saving). */
+ mem = save_p ? SET_DEST (set) : SET_SRC (set);
+ if (!MEM_P (mem) || MEM_VOLATILE_P (mem))
+ return false;
+
+ /* Check that the address is the sum of base and a possibly-zero
+ constant offset. Determine if the offset is in range. */
+ mips_split_plus (XEXP (mem, 0), &this_base, &this_offset);
+ if (!REG_P (this_base))
+ return false;
+
+ if (n == 0)
+ {
+ if (!UMIPS_12BIT_OFFSET_P (this_offset))
+ return false;
+ first_base = this_base;
+ first_offset = this_offset;
+ }
+ else
+ {
+ /* Check that the save slots are consecutive. */
+ if (REGNO (this_base) != REGNO (first_base)
+ || this_offset != first_offset + UNITS_PER_WORD * n)
+ return false;
+ }
+
+ /* Check that SET's other operand is a register. */
+ reg = save_p ? SET_SRC (set) : SET_DEST (set);
+ if (!REG_P (reg))
+ return false;
+
+ regmask |= 1 << REGNO (reg);
+ }
+
+ for (i = 0; i < ARRAY_SIZE (umips_swm_mask); i++)
+ if (regmask == umips_swm_mask[i])
+ return true;
+
+ return false;
+}
+
+/* Return the assembly instruction for microMIPS LWM or SWM.
+ SAVE_P and PATTERN are as for umips_save_restore_pattern_p. */
+
+const char *
+umips_output_save_restore (bool save_p, rtx pattern)
+{
+ static char buffer[300];
+ char *s;
+ int n;
+ HOST_WIDE_INT offset;
+ rtx base, mem, set, last_set, last_reg;
+
+ /* Parse the pattern. */
+ gcc_assert (umips_save_restore_pattern_p (save_p, pattern));
+
+ s = strcpy (buffer, save_p ? "swm\t" : "lwm\t");
+ s += strlen (s);
+ n = XVECLEN (pattern, 0);
+
+ set = XVECEXP (pattern, 0, 0);
+ mem = save_p ? SET_DEST (set) : SET_SRC (set);
+ mips_split_plus (XEXP (mem, 0), &base, &offset);
+
+ last_set = XVECEXP (pattern, 0, n - 1);
+ last_reg = save_p ? SET_SRC (last_set) : SET_DEST (last_set);
+
+ if (REGNO (last_reg) == 31)
+ n--;
+
+ gcc_assert (n <= 9);
+ if (n == 0)
+ ;
+ else if (n == 1)
+ s += sprintf (s, "%s,", reg_names[16]);
+ else if (n < 9)
+ s += sprintf (s, "%s-%s,", reg_names[16], reg_names[15 + n]);
+ else if (n == 9)
+ s += sprintf (s, "%s-%s,%s,", reg_names[16], reg_names[23],
+ reg_names[30]);
+
+ if (REGNO (last_reg) == 31)
+ s += sprintf (s, "%s,", reg_names[31]);
+
+ s += sprintf (s, "%d(%s)", (int)offset, reg_names[REGNO (base)]);
+ return buffer;
+}
+
+/* Return true if MEM1 and MEM2 use the same base register, and the
+ offset of MEM2 equals the offset of MEM1 plus 4. FIRST_REG is the
+ register into (from) which the contents of MEM1 will be loaded
+ (stored), depending on the value of LOAD_P.
+ SWAP_P is true when the 1st and 2nd instructions are swapped. */
+
+static bool
+umips_load_store_pair_p_1 (bool load_p, bool swap_p,
+ rtx first_reg, rtx mem1, rtx mem2)
+{
+ rtx base1, base2;
+ HOST_WIDE_INT offset1, offset2;
+
+ if (!MEM_P (mem1) || !MEM_P (mem2))
+ return false;
+
+ mips_split_plus (XEXP (mem1, 0), &base1, &offset1);
+ mips_split_plus (XEXP (mem2, 0), &base2, &offset2);
+
+ if (!REG_P (base1) || !rtx_equal_p (base1, base2))
+ return false;
+
+ /* Avoid invalid load pair instructions. */
+ if (load_p && REGNO (first_reg) == REGNO (base1))
+ return false;
+
+ /* We must avoid this case for anti-dependence.
+ Ex: lw $3, 4($3)
+ lw $2, 0($3)
+ first_reg is $2, but the base is $3. */
+ if (load_p
+ && swap_p
+ && REGNO (first_reg) + 1 == REGNO (base1))
+ return false;
+
+ if (offset2 != offset1 + 4)
+ return false;
+
+ if (!UMIPS_12BIT_OFFSET_P (offset1))
+ return false;
+
+ return true;
+}
+
+/* OPERANDS describes the operands to a pair of SETs, in the order
+ dest1, src1, dest2, src2. Return true if the operands can be used
+ in an LWP or SWP instruction; LOAD_P says which. */
+
+bool
+umips_load_store_pair_p (bool load_p, rtx *operands)
+{
+ rtx reg1, reg2, mem1, mem2;
+
+ if (load_p)
+ {
+ reg1 = operands[0];
+ reg2 = operands[2];
+ mem1 = operands[1];
+ mem2 = operands[3];
+ }
+ else
+ {
+ reg1 = operands[1];
+ reg2 = operands[3];
+ mem1 = operands[0];
+ mem2 = operands[2];
+ }
+
+ if (REGNO (reg2) == REGNO (reg1) + 1)
+ return umips_load_store_pair_p_1 (load_p, false, reg1, mem1, mem2);
+
+ if (REGNO (reg1) == REGNO (reg2) + 1)
+ return umips_load_store_pair_p_1 (load_p, true, reg2, mem2, mem1);
+
+ return false;
+}
+
+/* Return the assembly instruction for a microMIPS LWP or SWP in which
+ the first register is REG and the first memory slot is MEM.
+ LOAD_P is true for LWP. */
+
+static void
+umips_output_load_store_pair_1 (bool load_p, rtx reg, rtx mem)
+{
+ rtx ops[] = {reg, mem};
+
+ if (load_p)
+ output_asm_insn ("lwp\t%0,%1", ops);
+ else
+ output_asm_insn ("swp\t%0,%1", ops);
+}
+
+/* Output the assembly instruction for a microMIPS LWP or SWP instruction.
+ LOAD_P and OPERANDS are as for umips_load_store_pair_p. */
+
+void
+umips_output_load_store_pair (bool load_p, rtx *operands)
+{
+ rtx reg1, reg2, mem1, mem2;
+ if (load_p)
+ {
+ reg1 = operands[0];
+ reg2 = operands[2];
+ mem1 = operands[1];
+ mem2 = operands[3];
+ }
+ else
+ {
+ reg1 = operands[1];
+ reg2 = operands[3];
+ mem1 = operands[0];
+ mem2 = operands[2];
+ }
+
+ if (REGNO (reg2) == REGNO (reg1) + 1)
+ {
+ umips_output_load_store_pair_1 (load_p, reg1, mem1);
+ return;
+ }
+
+ gcc_assert (REGNO (reg1) == REGNO (reg2) + 1);
+ umips_output_load_store_pair_1 (load_p, reg2, mem2);
+}
+
+/* Return true if REG1 and REG2 match the criteria for a movep insn. */
+
+bool
+umips_movep_target_p (rtx reg1, rtx reg2)
+{
+ int regno1, regno2, pair;
+ unsigned int i;
+ static const int match[8] = {
+ 0x00000060, /* 5, 6 */
+ 0x000000a0, /* 5, 7 */
+ 0x000000c0, /* 6, 7 */
+ 0x00200010, /* 4, 21 */
+ 0x00400010, /* 4, 22 */
+ 0x00000030, /* 4, 5 */
+ 0x00000050, /* 4, 6 */
+ 0x00000090 /* 4, 7 */
+ };
+
+ if (!REG_P (reg1) || !REG_P (reg2))
+ return false;
+
+ regno1 = REGNO (reg1);
+ regno2 = REGNO (reg2);
+
+ if (!GP_REG_P (regno1) || !GP_REG_P (regno2))
+ return false;
+
+ pair = (1 << regno1) | (1 << regno2);
+
+ for (i = 0; i < ARRAY_SIZE (match); i++)
+ if (pair == match[i])
+ return true;
+
+ return false;
+}
/* Return the size in bytes of the trampoline code, padded to
TRAMPOLINE_ALIGNMENT bits. The static chain pointer and target
@@ -17355,7 +17931,7 @@ mips_prepare_pch_save (void)
It therefore seems best to switch back to non-MIPS16 mode at
save time, and to ensure that mips16_globals remains null after
a PCH load. */
- mips_set_mips16_mode (false);
+ mips_set_compression_mode (0);
mips16_globals = 0;
}
diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h
index 0acce14bd8c..0db36988dcc 100644
--- a/gcc/config/mips/mips.h
+++ b/gcc/config/mips/mips.h
@@ -174,6 +174,9 @@ struct mips_cpu_info {
#define ISA_HAS_DSP_MULT ISA_HAS_DSPR2
#endif
+/* The ISA compression flags that are currently in effect. */
+#define TARGET_COMPRESSION (target_flags & (MASK_MIPS16 | MASK_MICROMIPS))
+
/* Generate mips16 code */
#define TARGET_MIPS16 ((target_flags & MASK_MIPS16) != 0)
/* Generate mips16e code. Default 16bit ASE for mips32* and mips64* */
@@ -374,7 +377,7 @@ struct mips_cpu_info {
else \
builtin_define ("__mips_fpr=32"); \
\
- if (mips_base_mips16) \
+ if (mips_base_compression_flags & MASK_MIPS16) \
builtin_define ("__mips16"); \
\
if (TARGET_MIPS3D) \
@@ -383,6 +386,9 @@ struct mips_cpu_info {
if (TARGET_SMARTMIPS) \
builtin_define ("__mips_smartmips"); \
\
+ if (mips_base_compression_flags & MASK_MICROMIPS) \
+ builtin_define ("__mips_micromips"); \
+ \
if (TARGET_MCU) \
builtin_define ("__mips_mcu"); \
\
@@ -702,7 +708,7 @@ struct mips_cpu_info {
|march=r10000|march=r12000|march=r14000|march=r16000:-mips4} \
%{march=mips32|march=4kc|march=4km|march=4kp|march=4ksc:-mips32} \
%{march=mips32r2|march=m4k|march=4ke*|march=4ksd|march=24k* \
- |march=34k*|march=74k*|march=1004k*: -mips32r2} \
+ |march=34k*|march=74k*|march=m14k*|march=1004k*: -mips32r2} \
%{march=mips64|march=5k*|march=20k*|march=sb1*|march=sr71000 \
|march=xlr|march=loongson3a: -mips64} \
%{march=mips64r2|march=octeon|march=xlp: -mips64r2} \
@@ -716,7 +722,7 @@ struct mips_cpu_info {
"%{mhard-float|msoft-float|mno-float|march=mips*:; \
march=vr41*|march=m4k|march=4k*|march=24kc|march=24kec \
|march=34kc|march=34kn|march=74kc|march=1004kc|march=5kc \
- |march=octeon|march=xlr: -msoft-float; \
+ |march=m14k*|march=octeon|march=xlr: -msoft-float; \
march=*: -mhard-float}"
/* A spec condition that matches 32-bit options. It only works if
@@ -989,7 +995,8 @@ struct mips_cpu_info {
|| ISA_MIPS64R2))
/* ISA has lwxs instruction (load w/scaled index address. */
-#define ISA_HAS_LWXS (TARGET_SMARTMIPS && !TARGET_MIPS16)
+#define ISA_HAS_LWXS ((TARGET_SMARTMIPS || TARGET_MICROMIPS) \
+ && !TARGET_MIPS16)
/* ISA has lbx, lbux, lhx, lhx, lhux, lwx, lwux, or ldx instruction. */
#define ISA_HAS_LBX (TARGET_OCTEON2)
@@ -1012,7 +1019,8 @@ struct mips_cpu_info {
and "addiu $4,$4,1". */
#define ISA_HAS_LOAD_DELAY (ISA_MIPS1 \
&& !TARGET_MIPS3900 \
- && !TARGET_MIPS16)
+ && !TARGET_MIPS16 \
+ && !TARGET_MICROMIPS)
/* Likewise mtc1 and mfc1. */
#define ISA_HAS_XFER_DELAY (mips_isa <= 3 \
@@ -1123,6 +1131,7 @@ struct mips_cpu_info {
%{G*} %(endian_spec) %{mips1} %{mips2} %{mips3} %{mips4} \
%{mips32*} %{mips64*} \
%{mips16} %{mno-mips16:-no-mips16} \
+%{mmicromips} %{mno-micromips} \
%{mips3d} %{mno-mips3d:-no-mips3d} \
%{mdmx} %{mno-mdmx:-no-mdmx} \
%{mdsp} %{mno-dsp} \
@@ -1672,6 +1681,8 @@ struct mips_cpu_info {
((unsigned int) ((int) (REGNO) - GP_REG_FIRST) < GP_REG_NUM)
#define M16_REG_P(REGNO) \
(((REGNO) >= 2 && (REGNO) <= 7) || (REGNO) == 16 || (REGNO) == 17)
+#define M16STORE_REG_P(REGNO) \
+ (((REGNO) >= 2 && (REGNO) <= 7) || (REGNO) == 0 || (REGNO) == 17)
#define FP_REG_P(REGNO) \
((unsigned int) ((int) (REGNO) - FP_REG_FIRST) < FP_REG_NUM)
#define MD_REG_P(REGNO) \
@@ -2034,6 +2045,7 @@ enum reg_class
#define SMALL_INT(X) SMALL_OPERAND (INTVAL (X))
#define SMALL_INT_UNSIGNED(X) SMALL_OPERAND_UNSIGNED (INTVAL (X))
#define LUI_INT(X) LUI_OPERAND (INTVAL (X))
+#define UMIPS_12BIT_OFFSET_P(OFFSET) (IN_RANGE (OFFSET, -2048, 2047))
/* The HI and LO registers can only be reloaded via the general
registers. Condition code registers can only be loaded to the
@@ -2452,17 +2464,32 @@ typedef struct mips_args {
all calls should use assembly macros. Otherwise, all indirect
calls should use "jr" or "jalr"; we will arrange to restore $gp
afterwards if necessary. Finally, we can only generate direct
- calls for -mabicalls by temporarily switching to non-PIC mode. */
+ calls for -mabicalls by temporarily switching to non-PIC mode.
+
+ For microMIPS jal(r), we try to generate jal(r)s when a 16-bit
+ instruction is in the delay slot of jal(r). */
#define MIPS_CALL(INSN, OPERANDS, TARGET_OPNO, SIZE_OPNO) \
(TARGET_USE_GOT && !TARGET_EXPLICIT_RELOCS \
? "%*" INSN "\t%" #TARGET_OPNO "%/" \
- : (REG_P (OPERANDS[TARGET_OPNO]) \
- && mips_get_pic_call_symbol (OPERANDS, SIZE_OPNO)) \
- ? ("%*.reloc\t1f,R_MIPS_JALR,%" #SIZE_OPNO "\n" \
- "1:\t" INSN "r\t%" #TARGET_OPNO "%/") \
: REG_P (OPERANDS[TARGET_OPNO]) \
- ? "%*" INSN "r\t%" #TARGET_OPNO "%/" \
+ ? (mips_get_pic_call_symbol (OPERANDS, SIZE_OPNO) \
+ ? ("%*.reloc\t1f,R_MIPS_JALR,%" #SIZE_OPNO "\n" \
+ "1:\t" INSN "r\t%" #TARGET_OPNO "%/") \
+ : TARGET_MICROMIPS && !TARGET_INTERLINK_COMPRESSED \
+ ? "%*" INSN "r%!\t%" #TARGET_OPNO "%/" \
+ : "%*" INSN "r\t%" #TARGET_OPNO "%/") \
: MIPS_ABSOLUTE_JUMP ("%*" INSN "\t%" #TARGET_OPNO "%/"))
+
+/* Similar to MIPS_CALL, but this is for MICROMIPS "j" to generate
+ "jrc" when nop is in the delay slot of "jr". */
+
+#define MICROMIPS_J(INSN, OPERANDS, OPNO) \
+ (TARGET_USE_GOT && !TARGET_EXPLICIT_RELOCS \
+ ? "%*j\t%" #OPNO "%/" \
+ : REG_P (OPERANDS[OPNO]) \
+ ? "%*jr%:\t%" #OPNO \
+ : MIPS_ABSOLUTE_JUMP ("%*" INSN "\t%" #OPNO "%/"))
+
/* Control the assembler format that we output. */
@@ -2877,7 +2904,7 @@ extern enum processor mips_tune; /* which cpu to schedule for */
extern int mips_isa; /* architectural level */
extern const struct mips_cpu_info *mips_arch_info;
extern const struct mips_cpu_info *mips_tune_info;
-extern bool mips_base_mips16;
+extern unsigned int mips_base_compression_flags;
extern GTY(()) struct target_globals *mips16_globals;
#endif
diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md
index 7aa461dbd69..2f629107a57 100644
--- a/gcc/config/mips/mips.md
+++ b/gcc/config/mips/mips.md
@@ -342,13 +342,14 @@
;; syncloop memory atomic operation implemented as a sync loop
;; nop no operation
;; ghost an instruction that produces no real code
+;; multimem microMIPS multiword load and store
(define_attr "type"
"unknown,branch,jump,call,load,fpload,fpidxload,store,fpstore,fpidxstore,
prefetch,prefetchx,condmove,mtc,mfc,mthi,mtlo,mfhi,mflo,const,arith,logical,
shift,slt,signext,clz,pop,trap,imul,imul3,imul3nc,imadd,idiv,idiv3,move,
fmove,fadd,fmul,fmadd,fdiv,frdiv,frdiv1,frdiv2,fabs,fneg,fcmp,fcvt,fsqrt,
frsqrt,frsqrt1,frsqrt2,dspmac,dspmacsat,accext,accmod,dspalu,dspalusat,
- multi,atomic,syncloop,nop,ghost"
+ multi,atomic,syncloop,nop,ghost,multimem"
(cond [(eq_attr "jal" "!unset") (const_string "call")
(eq_attr "got" "load") (const_string "load")
@@ -411,11 +412,32 @@
(const_string "yes")
(const_string "no")))
+(define_attr "compression" "none,all,micromips"
+ (const_string "none"))
+
+(define_attr "enabled" "no,yes"
+ (if_then_else (ior (eq_attr "compression" "all,none")
+ (and (eq_attr "compression" "micromips")
+ (match_test "TARGET_MICROMIPS")))
+ (const_string "yes")
+ (const_string "no")))
+
;; Length of instruction in bytes.
(define_attr "length" ""
- (cond [;; Direct branch instructions have a range of [-0x20000,0x1fffc],
- ;; relative to the address of the delay slot. If a branch is
- ;; outside this range, we have a choice of two sequences.
+ (cond [(and (eq_attr "extended_mips16" "yes")
+ (match_test "TARGET_MIPS16"))
+ (const_int 8)
+
+ (and (eq_attr "compression" "micromips,all")
+ (eq_attr "dword_mode" "no")
+ (match_test "TARGET_MICROMIPS"))
+ (const_int 2)
+
+ ;; Direct microMIPS branch instructions have a range of
+ ;; [-0x10000,0xfffe], otherwise the range is [-0x20000,0x1fffc].
+ ;; If a branch is outside this range, we have a choice of two
+ ;; sequences.
+ ;;
;; For PIC, an out-of-range branch like:
;;
;; bne r1,r2,target
@@ -451,8 +473,15 @@
;; from the shorten_branches reference address.
(and (eq_attr "type" "branch")
(not (match_test "TARGET_MIPS16")))
- (cond [(and (le (minus (match_dup 0) (pc)) (const_int 131064))
- (le (minus (pc) (match_dup 0)) (const_int 131068)))
+ (cond [;; Any variant can handle the 17-bit range.
+ (and (le (minus (match_dup 0) (pc)) (const_int 65532))
+ (le (minus (pc) (match_dup 0)) (const_int 65534)))
+ (const_int 4)
+
+ ;; The 18-bit range is OK other than for microMIPS.
+ (and (not (match_test "TARGET_MICROMIPS"))
+ (and (le (minus (match_dup 0) (pc)) (const_int 131064))
+ (le (minus (pc) (match_dup 0)) (const_int 131068))))
(const_int 4)
;; The non-PIC case: branch, first delay slot, and J.
@@ -712,6 +741,9 @@
;; modes.
(define_mode_iterator GPR2 [SI (DI "TARGET_64BIT")])
+(define_mode_iterator MOVEP1 [SI SF])
+(define_mode_iterator MOVEP2 [SI SF])
+
;; This mode iterator allows :HILO to be used as the mode of the
;; concatenated HI and LO registers.
(define_mode_iterator HILO [(DI "!TARGET_64BIT") (TI "TARGET_64BIT")])
@@ -947,6 +979,10 @@
(xor "xori")
(and "andi")])
+(define_code_attr shift_compression [(ashift "micromips")
+ (lshiftrt "micromips")
+ (ashiftrt "none")])
+
;; <fcond> is the c.cond.fmt condition associated with a particular code.
(define_code_attr fcond [(unordered "un")
(uneq "ueq")
@@ -1114,14 +1150,19 @@
"")
(define_insn "*add<mode>3"
- [(set (match_operand:GPR 0 "register_operand" "=d,d")
- (plus:GPR (match_operand:GPR 1 "register_operand" "d,d")
- (match_operand:GPR 2 "arith_operand" "d,Q")))]
+ [(set (match_operand:GPR 0 "register_operand" "=!u,d,!u,!u,!ks,!d,d")
+ (plus:GPR (match_operand:GPR 1 "register_operand" "!u,d,!u,!ks,!ks,0,d")
+ (match_operand:GPR 2 "arith_operand" "!u,d,Uead,Uuw6,Uesp,Usb4,Q")))]
"!TARGET_MIPS16"
- "@
- <d>addu\t%0,%1,%2
- <d>addiu\t%0,%1,%2"
+{
+ if (which_alternative == 0
+ || which_alternative == 1)
+ return "<d>addu\t%0,%1,%2";
+ else
+ return "<d>addiu\t%0,%1,%2";
+}
[(set_attr "alu_type" "add")
+ (set_attr "compression" "micromips,*,micromips,micromips,micromips,micromips,*")
(set_attr "mode" "<MODE>")])
(define_insn "*add<mode>3_mips16"
@@ -1330,12 +1371,13 @@
(set_attr "mode" "<UNITMODE>")])
(define_insn "sub<mode>3"
- [(set (match_operand:GPR 0 "register_operand" "=d")
- (minus:GPR (match_operand:GPR 1 "register_operand" "d")
- (match_operand:GPR 2 "register_operand" "d")))]
+ [(set (match_operand:GPR 0 "register_operand" "=!u,d")
+ (minus:GPR (match_operand:GPR 1 "register_operand" "!u,d")
+ (match_operand:GPR 2 "register_operand" "!u,d")))]
""
"<d>subu\t%0,%1,%2"
[(set_attr "alu_type" "sub")
+ (set_attr "compression" "micromips,*")
(set_attr "mode" "<MODE>")])
(define_insn "*subsi3_extended"
@@ -2811,8 +2853,8 @@
(set_attr "mode" "<UNITMODE>")])
(define_insn "one_cmpl<mode>2"
- [(set (match_operand:GPR 0 "register_operand" "=d")
- (not:GPR (match_operand:GPR 1 "register_operand" "d")))]
+ [(set (match_operand:GPR 0 "register_operand" "=!u,d")
+ (not:GPR (match_operand:GPR 1 "register_operand" "!u,d")))]
""
{
if (TARGET_MIPS16)
@@ -2821,6 +2863,7 @@
return "nor\t%0,%.,%1";
}
[(set_attr "alu_type" "not")
+ (set_attr "compression" "micromips,*")
(set_attr "mode" "<MODE>")])
;;
@@ -2861,9 +2904,9 @@
;; register =op1 x
(define_insn "*and<mode>3"
- [(set (match_operand:GPR 0 "register_operand" "=d,d,d,d,d,d,d")
- (and:GPR (match_operand:GPR 1 "nonimmediate_operand" "o,o,W,d,d,d,d")
- (match_operand:GPR 2 "and_operand" "Yb,Yh,Yw,K,Yx,Yw,d")))]
+ [(set (match_operand:GPR 0 "register_operand" "=d,d,d,!u,d,d,d,!u,d")
+ (and:GPR (match_operand:GPR 1 "nonimmediate_operand" "o,o,W,!u,d,d,d,0,d")
+ (match_operand:GPR 2 "and_operand" "Yb,Yh,Yw,Uean,K,Yx,Yw,!u,d")))]
"!TARGET_MIPS16 && and_operands_ok (<MODE>mode, operands[1], operands[2])"
{
int len;
@@ -2880,20 +2923,23 @@
operands[1] = gen_lowpart (SImode, operands[1]);
return "lwu\t%0,%1";
case 3:
- return "andi\t%0,%1,%x2";
case 4:
+ return "andi\t%0,%1,%x2";
+ case 5:
len = low_bitmask_len (<MODE>mode, INTVAL (operands[2]));
operands[2] = GEN_INT (len);
return "<d>ext\t%0,%1,0,%2";
- case 5:
- return "#";
case 6:
+ return "#";
+ case 7:
+ case 8:
return "and\t%0,%1,%2";
default:
gcc_unreachable ();
}
}
- [(set_attr "move_type" "load,load,load,andi,ext_ins,shift_shift,logical")
+ [(set_attr "move_type" "load,load,load,andi,andi,ext_ins,shift_shift,logical,logical")
+ (set_attr "compression" "*,*,*,micromips,*,*,*,micromips,*")
(set_attr "mode" "<MODE>")])
(define_insn "*and<mode>3_mips16"
@@ -2935,14 +2981,16 @@
})
(define_insn "*ior<mode>3"
- [(set (match_operand:GPR 0 "register_operand" "=d,d")
- (ior:GPR (match_operand:GPR 1 "register_operand" "%d,d")
- (match_operand:GPR 2 "uns_arith_operand" "d,K")))]
+ [(set (match_operand:GPR 0 "register_operand" "=!u,d,d")
+ (ior:GPR (match_operand:GPR 1 "register_operand" "%0,d,d")
+ (match_operand:GPR 2 "uns_arith_operand" "!u,d,K")))]
"!TARGET_MIPS16"
"@
or\t%0,%1,%2
+ or\t%0,%1,%2
ori\t%0,%1,%x2"
[(set_attr "alu_type" "or")
+ (set_attr "compression" "micromips,*,*")
(set_attr "mode" "<MODE>")])
(define_insn "*ior<mode>3_mips16"
@@ -2962,14 +3010,16 @@
"")
(define_insn ""
- [(set (match_operand:GPR 0 "register_operand" "=d,d")
- (xor:GPR (match_operand:GPR 1 "register_operand" "%d,d")
- (match_operand:GPR 2 "uns_arith_operand" "d,K")))]
+ [(set (match_operand:GPR 0 "register_operand" "=!u,d,d")
+ (xor:GPR (match_operand:GPR 1 "register_operand" "%0,d,d")
+ (match_operand:GPR 2 "uns_arith_operand" "!u,d,K")))]
"!TARGET_MIPS16"
"@
xor\t%0,%1,%2
+ xor\t%0,%1,%2
xori\t%0,%1,%x2"
[(set_attr "alu_type" "xor")
+ (set_attr "compression" "micromips,*,*")
(set_attr "mode" "<MODE>")])
(define_insn ""
@@ -3145,14 +3195,16 @@
})
(define_insn "*zero_extend<SHORT:mode><GPR:mode>2"
- [(set (match_operand:GPR 0 "register_operand" "=d,d")
+ [(set (match_operand:GPR 0 "register_operand" "=!u,d,d")
(zero_extend:GPR
- (match_operand:SHORT 1 "nonimmediate_operand" "d,m")))]
+ (match_operand:SHORT 1 "nonimmediate_operand" "!u,d,m")))]
"!TARGET_MIPS16"
"@
andi\t%0,%1,<SHORT:mask>
+ andi\t%0,%1,<SHORT:mask>
l<SHORT:size>u\t%0,%1"
- [(set_attr "move_type" "andi,load")
+ [(set_attr "move_type" "andi,andi,load")
+ (set_attr "compression" "micromips,*,*")
(set_attr "mode" "<GPR:MODE>")])
(define_insn "*zero_extend<SHORT:mode><GPR:mode>2_mips16e"
@@ -3937,7 +3989,7 @@
(define_insn "mov_<load>l"
[(set (match_operand:GPR 0 "register_operand" "=d")
(unspec:GPR [(match_operand:BLK 1 "memory_operand" "m")
- (match_operand:QI 2 "memory_operand" "m")]
+ (match_operand:QI 2 "memory_operand" "ZC")]
UNSPEC_LOAD_LEFT))]
"!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[1])"
"<load>l\t%0,%2"
@@ -3947,7 +3999,7 @@
(define_insn "mov_<load>r"
[(set (match_operand:GPR 0 "register_operand" "=d")
(unspec:GPR [(match_operand:BLK 1 "memory_operand" "m")
- (match_operand:QI 2 "memory_operand" "m")
+ (match_operand:QI 2 "memory_operand" "ZC")
(match_operand:GPR 3 "register_operand" "0")]
UNSPEC_LOAD_RIGHT))]
"!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[1])"
@@ -3958,7 +4010,7 @@
(define_insn "mov_<store>l"
[(set (match_operand:BLK 0 "memory_operand" "=m")
(unspec:BLK [(match_operand:GPR 1 "reg_or_0_operand" "dJ")
- (match_operand:QI 2 "memory_operand" "m")]
+ (match_operand:QI 2 "memory_operand" "ZC")]
UNSPEC_STORE_LEFT))]
"!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[0])"
"<store>l\t%z1,%2"
@@ -3968,7 +4020,7 @@
(define_insn "mov_<store>r"
[(set (match_operand:BLK 0 "memory_operand" "+m")
(unspec:BLK [(match_operand:GPR 1 "reg_or_0_operand" "dJ")
- (match_operand:QI 2 "memory_operand" "m")
+ (match_operand:QI 2 "memory_operand" "ZC")
(match_dup 0)]
UNSPEC_STORE_RIGHT))]
"!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[0])"
@@ -4268,7 +4320,7 @@
(define_insn "*movdi_64bit"
[(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,e,d,m,*f,*f,*d,*m,*a,*d,*B*C*D,*B*C*D,*d,*m")
- (match_operand:DI 1 "move_operand" "d,U,T,m,dJ,*d*J,*m,*f,*f,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))]
+ (match_operand:DI 1 "move_operand" "d,Yd,Yf,m,dJ,*d*J,*m,*f,*f,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))]
"TARGET_64BIT && !TARGET_MIPS16
&& (register_operand (operands[0], DImode)
|| reg_or_0_operand (operands[1], DImode))"
@@ -4278,7 +4330,7 @@
(define_insn "*movdi_64bit_mips16"
[(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,d,m,*d")
- (match_operand:DI 1 "move_operand" "d,d,y,K,N,U,kf,m,d,*a"))]
+ (match_operand:DI 1 "move_operand" "d,d,y,K,N,Yd,kf,m,d,*a"))]
"TARGET_64BIT && TARGET_MIPS16
&& (register_operand (operands[0], DImode)
|| register_operand (operands[1], DImode))"
@@ -4345,18 +4397,19 @@
;; in FP registers (off by default, use -mdebugh to enable).
(define_insn "*mov<mode>_internal"
- [(set (match_operand:IMOVE32 0 "nonimmediate_operand" "=d,d,e,d,m,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*m")
- (match_operand:IMOVE32 1 "move_operand" "d,U,T,m,dJ,*d*J,*m,*f,*f,*z,*d,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))]
+ [(set (match_operand:IMOVE32 0 "nonimmediate_operand" "=d,!u,!u,d,e,!u,!ks,d,ZS,ZT,m,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*m")
+ (match_operand:IMOVE32 1 "move_operand" "d,J,Udb7,Yd,Yf,ZT,ZS,m,!ks,!u,dJ,*d*J,*m,*f,*f,*z,*d,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))]
"!TARGET_MIPS16
&& (register_operand (operands[0], <MODE>mode)
|| reg_or_0_operand (operands[1], <MODE>mode))"
{ return mips_output_move (operands[0], operands[1]); }
- [(set_attr "move_type" "move,const,const,load,store,mtc,fpload,mfc,fpstore,mfc,mtc,mtlo,mflo,mtc,fpload,mfc,fpstore")
+ [(set_attr "move_type" "move,move,const,const,const,load,load,load,store,store,store,mtc,fpload,mfc,fpstore,mfc,mtc,mtlo,mflo,mtc,fpload,mfc,fpstore")
+ (set_attr "compression" "all,micromips,micromips,*,*,micromips,micromips,*,micromips,micromips,*,*,*,*,*,*,*,*,*,*,*,*,*")
(set_attr "mode" "SI")])
(define_insn "*mov<mode>_mips16"
[(set (match_operand:IMOVE32 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,d,m,*d")
- (match_operand:IMOVE32 1 "move_operand" "d,d,y,K,N,U,kf,m,d,*a"))]
+ (match_operand:IMOVE32 1 "move_operand" "d,d,y,K,N,Yd,kf,m,d,*a"))]
"TARGET_MIPS16
&& (register_operand (operands[0], <MODE>mode)
|| register_operand (operands[1], <MODE>mode))"
@@ -5208,9 +5261,9 @@
})
(define_insn "*<optab><mode>3"
- [(set (match_operand:GPR 0 "register_operand" "=d")
- (any_shift:GPR (match_operand:GPR 1 "register_operand" "d")
- (match_operand:SI 2 "arith_operand" "dI")))]
+ [(set (match_operand:GPR 0 "register_operand" "=!u,d")
+ (any_shift:GPR (match_operand:GPR 1 "register_operand" "!u,d")
+ (match_operand:SI 2 "arith_operand" "Uib3,dI")))]
"!TARGET_MIPS16"
{
if (CONST_INT_P (operands[2]))
@@ -5220,6 +5273,7 @@
return "<d><insn>\t%0,%1,%2";
}
[(set_attr "type" "shift")
+ (set_attr "compression" "<shift_compression>,none")
(set_attr "mode" "<MODE>")])
(define_insn "*<optab>si3_extend"
@@ -5447,6 +5501,14 @@
(pc)))]
"!TARGET_MIPS16"
{
+ /* For a simple BNEZ or BEQZ microMIPS branch. */
+ if (TARGET_MICROMIPS
+ && operands[3] == const0_rtx
+ && get_attr_length (insn) <= 8)
+ return mips_output_conditional_branch (insn, operands,
+ "%*b%C1z%:\t%2,%0",
+ "%*b%N1z%:\t%2,%0");
+
return mips_output_conditional_branch (insn, operands,
MIPS_BRANCH ("b%C1", "%2,%z3,%0"),
MIPS_BRANCH ("b%N1", "%2,%z3,%0"));
@@ -5463,6 +5525,14 @@
(label_ref (match_operand 0 "" ""))))]
"!TARGET_MIPS16"
{
+ /* For a simple BNEZ or BEQZ microMIPS branch. */
+ if (TARGET_MICROMIPS
+ && operands[3] == const0_rtx
+ && get_attr_length (insn) <= 8)
+ return mips_output_conditional_branch (insn, operands,
+ "%*b%N0z%:\t%2,%1",
+ "%*b%C0z%:\t%2,%1");
+
return mips_output_conditional_branch (insn, operands,
MIPS_BRANCH ("b%N1", "%2,%z3,%0"),
MIPS_BRANCH ("b%C1", "%2,%z3,%0"));
@@ -5766,7 +5836,14 @@
[(set (pc)
(label_ref (match_operand 0)))]
"!TARGET_MIPS16 && TARGET_ABSOLUTE_JUMPS"
- { return MIPS_ABSOLUTE_JUMP ("%*j\t%l0%/"); }
+{
+ /* Use a branch for microMIPS. The assembler will choose
+ a 16-bit branch, a 32-bit branch, or a 32-bit jump. */
+ if (TARGET_MICROMIPS && !TARGET_ABICALLS_PIC2)
+ return "%*b\t%l0%/";
+ else
+ return MIPS_ABSOLUTE_JUMP ("%*j\t%l0%/");
+}
[(set_attr "type" "jump")])
(define_insn "*jump_pic"
@@ -5829,7 +5906,12 @@
(define_insn "indirect_jump_<mode>"
[(set (pc) (match_operand:P 0 "register_operand" "d"))]
""
- "%*j\t%0%/"
+{
+ if (TARGET_MICROMIPS)
+ return "%*jr%:\t%0";
+ else
+ return "%*j\t%0%/";
+}
[(set_attr "type" "jump")
(set_attr "mode" "none")])
@@ -5873,7 +5955,12 @@
(match_operand:P 0 "register_operand" "d"))
(use (label_ref (match_operand 1 "" "")))]
""
- "%*j\t%0%/"
+{
+ if (TARGET_MICROMIPS)
+ return "%*jr%:\t%0";
+ else
+ return "%*j\t%0%/";
+}
[(set_attr "type" "jump")
(set_attr "mode" "none")])
@@ -6094,7 +6181,12 @@
[(any_return)
(use (match_operand 0 "pmode_register_operand" ""))]
""
- "%*j\t%0%/"
+{
+ if (TARGET_MICROMIPS)
+ return "%*jr%:\t%0";
+ else
+ return "%*j\t%0%/";
+}
[(set_attr "type" "jump")
(set_attr "mode" "none")])
@@ -6350,7 +6442,12 @@
[(call (mem:SI (match_operand 0 "call_insn_operand" "j,S"))
(match_operand 1 "" ""))]
"TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
- { return MIPS_CALL ("j", operands, 0, 1); }
+{
+ if (TARGET_MICROMIPS)
+ return MICROMIPS_J ("j", operands, 0);
+ else
+ return MIPS_CALL ("j", operands, 0, 1);
+}
[(set_attr "jal" "indirect,direct")
(set_attr "jal_macro" "no")])
@@ -6371,7 +6468,12 @@
(call (mem:SI (match_operand 1 "call_insn_operand" "j,S"))
(match_operand 2 "" "")))]
"TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
- { return MIPS_CALL ("j", operands, 1, 2); }
+{
+ if (TARGET_MICROMIPS)
+ return MICROMIPS_J ("j", operands, 1);
+ else
+ return MIPS_CALL ("j", operands, 1, 2);
+}
[(set_attr "jal" "indirect,direct")
(set_attr "jal_macro" "no")])
@@ -6383,7 +6485,12 @@
(call (mem:SI (match_dup 1))
(match_dup 2)))]
"TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
- { return MIPS_CALL ("j", operands, 1, 2); }
+{
+ if (TARGET_MICROMIPS)
+ return MICROMIPS_J ("j", operands, 1);
+ else
+ return MIPS_CALL ("j", operands, 1, 2);
+}
[(set_attr "jal" "indirect,direct")
(set_attr "jal_macro" "no")])
@@ -6629,7 +6736,7 @@
(define_insn "prefetch"
- [(prefetch (match_operand:QI 0 "address_operand" "p")
+ [(prefetch (match_operand:QI 0 "address_operand" "ZD")
(match_operand 1 "const_int_operand" "n")
(match_operand 2 "const_int_operand" "n"))]
"ISA_HAS_PREFETCH && TARGET_EXPLICIT_RELOCS"
@@ -6922,6 +7029,9 @@
; MIPS fixed-point instructions.
(include "mips-fixed.md")
+; microMIPS patterns.
+(include "micromips.md")
+
; ST-Microelectronics Loongson-2E/2F-specific patterns.
(include "loongson.md")
diff --git a/gcc/config/mips/mips.opt b/gcc/config/mips/mips.opt
index d8ef2e7712e..f9e88b3cd72 100644
--- a/gcc/config/mips/mips.opt
+++ b/gcc/config/mips/mips.opt
@@ -217,9 +217,13 @@ mhard-float
Target Report RejectNegative InverseMask(SOFT_FLOAT_ABI, HARD_FLOAT_ABI)
Allow the use of hardware floating-point ABI and instructions
+minterlink-compressed
+Target Report Var(TARGET_INTERLINK_COMPRESSED) Init(0)
+Generate code that is link-compatible with MIPS16 and microMIPS code.
+
minterlink-mips16
-Target Report Var(TARGET_INTERLINK_MIPS16) Init(0)
-Generate code that can be safely linked with MIPS16 code.
+Target Report Var(TARGET_INTERLINK_COMPRESSED) Init(0)
+An alias for minterlink-compressed provided for backward-compatibility.
mips
Target RejectNegative Joined ToLower Enum(mips_mips_opt_value) Var(mips_isa_option)
@@ -261,6 +265,10 @@ mmemcpy
Target Report Mask(MEMCPY)
Don't optimize block moves
+mmicromips
+Target Report Mask(MICROMIPS)
+Use microMIPS instructions
+
mmt
Target Report Var(TARGET_MT)
Allow the use of MT instructions
diff --git a/gcc/config/mips/predicates.md b/gcc/config/mips/predicates.md
index 397d541f9be..57996fa8960 100644
--- a/gcc/config/mips/predicates.md
+++ b/gcc/config/mips/predicates.md
@@ -122,6 +122,98 @@
? M16_REG_P (REGNO (op))
: GP_REG_P (REGNO (op))")))
+(define_predicate "lwsp_swsp_operand"
+ (and (match_code "mem")
+ (match_test "lwsp_swsp_address_p (XEXP (op, 0), mode)")))
+
+(define_predicate "lw16_sw16_operand"
+ (and (match_code "mem")
+ (match_test "m16_based_address_p (XEXP (op, 0), mode, uw4_operand)")))
+
+(define_predicate "lhu16_sh16_operand"
+ (and (match_code "mem")
+ (match_test "m16_based_address_p (XEXP (op, 0), mode, uh4_operand)")))
+
+(define_predicate "lbu16_operand"
+ (and (match_code "mem")
+ (match_test "m16_based_address_p (XEXP (op, 0), mode, db4_operand)")))
+
+(define_predicate "sb16_operand"
+ (and (match_code "mem")
+ (match_test "m16_based_address_p (XEXP (op, 0), mode, ub4_operand)")))
+
+(define_predicate "db4_operand"
+ (and (match_code "const_int")
+ (match_test "mips_unsigned_immediate_p (INTVAL (op) + 1, 4, 0)")))
+
+(define_predicate "db7_operand"
+ (and (match_code "const_int")
+ (match_test "mips_unsigned_immediate_p (INTVAL (op) + 1, 7, 0)")))
+
+(define_predicate "ib3_operand"
+ (and (match_code "const_int")
+ (match_test "mips_unsigned_immediate_p (INTVAL (op) - 1, 3, 0)")))
+
+(define_predicate "sb4_operand"
+ (and (match_code "const_int")
+ (match_test "mips_signed_immediate_p (INTVAL (op), 4, 0)")))
+
+(define_predicate "ub4_operand"
+ (and (match_code "const_int")
+ (match_test "mips_unsigned_immediate_p (INTVAL (op), 4, 0)")))
+
+(define_predicate "uh4_operand"
+ (and (match_code "const_int")
+ (match_test "mips_unsigned_immediate_p (INTVAL (op), 4, 1)")))
+
+(define_predicate "uw4_operand"
+ (and (match_code "const_int")
+ (match_test "mips_unsigned_immediate_p (INTVAL (op), 4, 2)")))
+
+(define_predicate "uw5_operand"
+ (and (match_code "const_int")
+ (match_test "mips_unsigned_immediate_p (INTVAL (op), 5, 2)")))
+
+(define_predicate "uw6_operand"
+ (and (match_code "const_int")
+ (match_test "mips_unsigned_immediate_p (INTVAL (op), 6, 2)")))
+
+(define_predicate "addiur2_operand"
+ (and (match_code "const_int")
+ (ior (match_test "INTVAL (op) == -1")
+ (match_test "INTVAL (op) == 1")
+ (match_test "INTVAL (op) == 4")
+ (match_test "INTVAL (op) == 8")
+ (match_test "INTVAL (op) == 12")
+ (match_test "INTVAL (op) == 16")
+ (match_test "INTVAL (op) == 20")
+ (match_test "INTVAL (op) == 24"))))
+
+(define_predicate "addiusp_operand"
+ (and (match_code "const_int")
+ (ior (match_test "(IN_RANGE (INTVAL (op), 2, 257))")
+ (match_test "(IN_RANGE (INTVAL (op), -258, -3))"))))
+
+(define_predicate "andi16_operand"
+ (and (match_code "const_int")
+ (ior (match_test "IN_RANGE (INTVAL (op), 1, 4)")
+ (match_test "IN_RANGE (INTVAL (op), 7, 8)")
+ (match_test "IN_RANGE (INTVAL (op), 15, 16)")
+ (match_test "IN_RANGE (INTVAL (op), 31, 32)")
+ (match_test "IN_RANGE (INTVAL (op), 63, 64)")
+ (match_test "INTVAL (op) == 255")
+ (match_test "INTVAL (op) == 32768")
+ (match_test "INTVAL (op) == 65535"))))
+
+(define_predicate "movep_src_register"
+ (and (match_code "reg")
+ (ior (match_test ("IN_RANGE (REGNO (op), 2, 3)"))
+ (match_test ("IN_RANGE (REGNO (op), 16, 20)")))))
+
+(define_predicate "movep_src_operand"
+ (ior (match_operand 0 "const_0_operand")
+ (match_operand 0 "movep_src_register")))
+
(define_predicate "lo_operand"
(and (match_code "reg")
(match_test "REGNO (op) == LO_REGNUM")))
@@ -371,3 +463,8 @@
(define_predicate "mem_noofs_operand"
(and (match_code "mem")
(match_code "reg" "0")))
+
+;; Return 1 if the operand is in non-volatile memory.
+(define_predicate "non_volatile_mem_operand"
+ (and (match_operand 0 "memory_operand")
+ (not (match_test "MEM_VOLATILE_P (op)"))))
diff --git a/gcc/config/mips/sync.md b/gcc/config/mips/sync.md
index 3cd8343ef45..d40c2246bb1 100644
--- a/gcc/config/mips/sync.md
+++ b/gcc/config/mips/sync.md
@@ -59,7 +59,7 @@
;; Can be removed in favor of atomic_compare_and_swap below.
(define_insn "sync_compare_and_swap<mode>"
[(set (match_operand:GPR 0 "register_operand" "=&d,&d")
- (match_operand:GPR 1 "memory_operand" "+R,R"))
+ (match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
(set (match_dup 1)
(unspec_volatile:GPR [(match_operand:GPR 2 "reg_or_0_operand" "dJ,dJ")
(match_operand:GPR 3 "arith_operand" "I,d")]
@@ -89,7 +89,7 @@
;; Helper insn for mips_expand_atomic_qihi.
(define_insn "compare_and_swap_12"
[(set (match_operand:SI 0 "register_operand" "=&d,&d")
- (match_operand:SI 1 "memory_operand" "+R,R"))
+ (match_operand:SI 1 "memory_operand" "+ZR,ZR"))
(set (match_dup 1)
(unspec_volatile:SI [(match_operand:SI 2 "register_operand" "d,d")
(match_operand:SI 3 "register_operand" "d,d")
@@ -106,7 +106,7 @@
(set_attr "sync_insn1_op2" "5")])
(define_insn "sync_add<mode>"
- [(set (match_operand:GPR 0 "memory_operand" "+R,R")
+ [(set (match_operand:GPR 0 "memory_operand" "+ZR,ZR")
(unspec_volatile:GPR
[(plus:GPR (match_dup 0)
(match_operand:GPR 1 "arith_operand" "I,d"))]
@@ -134,7 +134,7 @@
;; Helper insn for sync_<optab><mode>
(define_insn "sync_<optab>_12"
- [(set (match_operand:SI 0 "memory_operand" "+R")
+ [(set (match_operand:SI 0 "memory_operand" "+ZR")
(unspec_volatile:SI
[(match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "register_operand" "d")
@@ -174,7 +174,7 @@
;; Helper insn for sync_old_<optab><mode>
(define_insn "sync_old_<optab>_12"
[(set (match_operand:SI 0 "register_operand" "=&d")
- (match_operand:SI 1 "memory_operand" "+R"))
+ (match_operand:SI 1 "memory_operand" "+ZR"))
(set (match_dup 1)
(unspec_volatile:SI
[(match_operand:SI 2 "register_operand" "d")
@@ -217,7 +217,7 @@
(define_insn "sync_new_<optab>_12"
[(set (match_operand:SI 0 "register_operand" "=&d")
(unspec_volatile:SI
- [(match_operand:SI 1 "memory_operand" "+R")
+ [(match_operand:SI 1 "memory_operand" "+ZR")
(match_operand:SI 2 "register_operand" "d")
(match_operand:SI 3 "register_operand" "d")
(atomic_hiqi_op:SI (match_dup 0)
@@ -257,7 +257,7 @@
;; Helper insn for sync_nand<mode>
(define_insn "sync_nand_12"
- [(set (match_operand:SI 0 "memory_operand" "+R")
+ [(set (match_operand:SI 0 "memory_operand" "+ZR")
(unspec_volatile:SI
[(match_operand:SI 1 "register_operand" "d")
(match_operand:SI 2 "register_operand" "d")
@@ -296,7 +296,7 @@
;; Helper insn for sync_old_nand<mode>
(define_insn "sync_old_nand_12"
[(set (match_operand:SI 0 "register_operand" "=&d")
- (match_operand:SI 1 "memory_operand" "+R"))
+ (match_operand:SI 1 "memory_operand" "+ZR"))
(set (match_dup 1)
(unspec_volatile:SI
[(match_operand:SI 2 "register_operand" "d")
@@ -337,7 +337,7 @@
(define_insn "sync_new_nand_12"
[(set (match_operand:SI 0 "register_operand" "=&d")
(unspec_volatile:SI
- [(match_operand:SI 1 "memory_operand" "+R")
+ [(match_operand:SI 1 "memory_operand" "+ZR")
(match_operand:SI 2 "register_operand" "d")
(match_operand:SI 3 "register_operand" "d")
(match_operand:SI 4 "reg_or_0_operand" "dJ")]
@@ -360,7 +360,7 @@
(set_attr "sync_insn1_op2" "4")])
(define_insn "sync_sub<mode>"
- [(set (match_operand:GPR 0 "memory_operand" "+R")
+ [(set (match_operand:GPR 0 "memory_operand" "+ZR")
(unspec_volatile:GPR
[(minus:GPR (match_dup 0)
(match_operand:GPR 1 "register_operand" "d"))]
@@ -374,7 +374,7 @@
;; Can be removed in favor of atomic_fetch_add below.
(define_insn "sync_old_add<mode>"
[(set (match_operand:GPR 0 "register_operand" "=&d,&d")
- (match_operand:GPR 1 "memory_operand" "+R,R"))
+ (match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
(set (match_dup 1)
(unspec_volatile:GPR
[(plus:GPR (match_dup 1)
@@ -389,7 +389,7 @@
(define_insn "sync_old_sub<mode>"
[(set (match_operand:GPR 0 "register_operand" "=&d")
- (match_operand:GPR 1 "memory_operand" "+R"))
+ (match_operand:GPR 1 "memory_operand" "+ZR"))
(set (match_dup 1)
(unspec_volatile:GPR
[(minus:GPR (match_dup 1)
@@ -404,7 +404,7 @@
(define_insn "sync_new_add<mode>"
[(set (match_operand:GPR 0 "register_operand" "=&d,&d")
- (plus:GPR (match_operand:GPR 1 "memory_operand" "+R,R")
+ (plus:GPR (match_operand:GPR 1 "memory_operand" "+ZR,ZR")
(match_operand:GPR 2 "arith_operand" "I,d")))
(set (match_dup 1)
(unspec_volatile:GPR
@@ -420,7 +420,7 @@
(define_insn "sync_new_sub<mode>"
[(set (match_operand:GPR 0 "register_operand" "=&d")
- (minus:GPR (match_operand:GPR 1 "memory_operand" "+R")
+ (minus:GPR (match_operand:GPR 1 "memory_operand" "+ZR")
(match_operand:GPR 2 "register_operand" "d")))
(set (match_dup 1)
(unspec_volatile:GPR
@@ -435,7 +435,7 @@
(set_attr "sync_insn1_op2" "2")])
(define_insn "sync_<optab><mode>"
- [(set (match_operand:GPR 0 "memory_operand" "+R,R")
+ [(set (match_operand:GPR 0 "memory_operand" "+ZR,ZR")
(unspec_volatile:GPR
[(fetchop_bit:GPR (match_operand:GPR 1 "uns_arith_operand" "K,d")
(match_dup 0))]
@@ -448,7 +448,7 @@
(define_insn "sync_old_<optab><mode>"
[(set (match_operand:GPR 0 "register_operand" "=&d,&d")
- (match_operand:GPR 1 "memory_operand" "+R,R"))
+ (match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
(set (match_dup 1)
(unspec_volatile:GPR
[(fetchop_bit:GPR (match_operand:GPR 2 "uns_arith_operand" "K,d")
@@ -463,7 +463,7 @@
(define_insn "sync_new_<optab><mode>"
[(set (match_operand:GPR 0 "register_operand" "=&d,&d")
- (match_operand:GPR 1 "memory_operand" "+R,R"))
+ (match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
(set (match_dup 1)
(unspec_volatile:GPR
[(fetchop_bit:GPR (match_operand:GPR 2 "uns_arith_operand" "K,d")
@@ -478,7 +478,7 @@
(set_attr "sync_insn1_op2" "2")])
(define_insn "sync_nand<mode>"
- [(set (match_operand:GPR 0 "memory_operand" "+R,R")
+ [(set (match_operand:GPR 0 "memory_operand" "+ZR,ZR")
(unspec_volatile:GPR [(match_operand:GPR 1 "uns_arith_operand" "K,d")]
UNSPEC_SYNC_OLD_OP))]
"GENERATE_LL_SC"
@@ -490,7 +490,7 @@
(define_insn "sync_old_nand<mode>"
[(set (match_operand:GPR 0 "register_operand" "=&d,&d")
- (match_operand:GPR 1 "memory_operand" "+R,R"))
+ (match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
(set (match_dup 1)
(unspec_volatile:GPR [(match_operand:GPR 2 "uns_arith_operand" "K,d")]
UNSPEC_SYNC_OLD_OP))]
@@ -504,7 +504,7 @@
(define_insn "sync_new_nand<mode>"
[(set (match_operand:GPR 0 "register_operand" "=&d,&d")
- (match_operand:GPR 1 "memory_operand" "+R,R"))
+ (match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
(set (match_dup 1)
(unspec_volatile:GPR [(match_operand:GPR 2 "uns_arith_operand" "K,d")]
UNSPEC_SYNC_NEW_OP))]
@@ -519,7 +519,7 @@
(define_insn "sync_lock_test_and_set<mode>"
[(set (match_operand:GPR 0 "register_operand" "=&d,&d")
- (match_operand:GPR 1 "memory_operand" "+R,R"))
+ (match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
(set (match_dup 1)
(unspec_volatile:GPR [(match_operand:GPR 2 "arith_operand" "I,d")]
UNSPEC_SYNC_EXCHANGE))]
@@ -546,7 +546,7 @@
(define_insn "test_and_set_12"
[(set (match_operand:SI 0 "register_operand" "=&d")
- (match_operand:SI 1 "memory_operand" "+R"))
+ (match_operand:SI 1 "memory_operand" "+ZR"))
(set (match_dup 1)
(unspec_volatile:SI [(match_operand:SI 2 "register_operand" "d")
(match_operand:SI 3 "register_operand" "d")
@@ -576,7 +576,7 @@
;; TODO: the obscuring unspec can be relaxed for permissive memory
;; models.
;; Same applies to other atomic_* patterns.
- (unspec_volatile:GPR [(match_operand:GPR 2 "memory_operand" "+R,R")
+ (unspec_volatile:GPR [(match_operand:GPR 2 "memory_operand" "+ZR,ZR")
(match_operand:GPR 3 "reg_or_0_operand" "dJ,dJ")]
UNSPEC_ATOMIC_COMPARE_AND_SWAP))
(set (match_operand:GPR 1 "register_operand" "=&d,&d")
@@ -629,7 +629,7 @@
(define_insn "atomic_exchange<mode>_llsc"
[(set (match_operand:GPR 0 "register_operand" "=&d,&d")
- (unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+R,R")]
+ (unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+ZR,ZR")]
UNSPEC_ATOMIC_EXCHANGE))
(set (match_dup 1)
(unspec_volatile:GPR [(match_operand:GPR 2 "arith_operand" "I,d")]
@@ -684,7 +684,7 @@
(define_insn "atomic_fetch_add<mode>_llsc"
[(set (match_operand:GPR 0 "register_operand" "=&d,&d")
- (unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+R,R")]
+ (unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+ZR,ZR")]
UNSPEC_ATOMIC_FETCH_OP))
(set (match_dup 1)
(unspec_volatile:GPR
diff --git a/gcc/config/mips/t-sde b/gcc/config/mips/t-sde
index 075f8f3da67..15f506f8afe 100644
--- a/gcc/config/mips/t-sde
+++ b/gcc/config/mips/t-sde
@@ -16,8 +16,8 @@
# along with GCC; see the file COPYING3. If not see
# <http://www.gnu.org/licenses/>.
-MULTILIB_OPTIONS = EL/EB mips32/mips32r2/mips64/mips64r2 mips16 msoft-float/mfp64 mcode-readable=no
-MULTILIB_DIRNAMES = el eb mips32 mips32r2 mips64 mips64r2 mips16 sof f64 spram
+MULTILIB_OPTIONS = EL/EB mips32/mips32r2/mips64/mips64r2 mips16/mmicromips msoft-float/mfp64 mcode-readable=no
+MULTILIB_DIRNAMES = el eb mips32 mips32r2 mips64 mips64r2 mips16 micromips sof f64 spram
MULTILIB_MATCHES = EL=mel EB=meb
# The -mfp64 option is only valid in conjunction with -mips32r2.
diff --git a/gcc/config/mmix/mmix.c b/gcc/config/mmix/mmix.c
index 1a81d4cde16..1af09e559b0 100644
--- a/gcc/config/mmix/mmix.c
+++ b/gcc/config/mmix/mmix.c
@@ -1728,7 +1728,7 @@ mmix_print_operand (FILE *stream, rtx x, int code)
if (CONSTANT_P (modified_x)
/* Strangely enough, this is not included in CONSTANT_P.
FIXME: Ask/check about sanity here. */
- || GET_CODE (modified_x) == CODE_LABEL)
+ || LABEL_P (modified_x))
{
output_addr_const (stream, modified_x);
return;
diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c
index f490e2d8e21..df563d03eac 100644
--- a/gcc/config/mn10300/mn10300.c
+++ b/gcc/config/mn10300/mn10300.c
@@ -622,6 +622,7 @@ mn10300_can_use_rets_insn (void)
/* Returns the set of live, callee-saved registers as a bitmask. The
callee-saved extended registers cannot be stored individually, so
+ all of them will be included in the mask if any one of them is used.
Also returns the number of bytes in the registers in the mask if
BYTES_SAVED is not NULL. */
diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c
index 0d39483d908..1cad695cf0d 100644
--- a/gcc/config/pa/pa.c
+++ b/gcc/config/pa/pa.c
@@ -3320,7 +3320,7 @@ remove_useless_addtr_insns (int check_notes)
rtx tmp;
/* Ignore anything that isn't an INSN or a JUMP_INSN. */
- if (GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN)
+ if (! NONJUMP_INSN_P (insn) && ! JUMP_P (insn))
continue;
tmp = PATTERN (insn);
@@ -3359,7 +3359,7 @@ remove_useless_addtr_insns (int check_notes)
rtx tmp, next;
/* Ignore anything that isn't an INSN. */
- if (GET_CODE (insn) != INSN)
+ if (! NONJUMP_INSN_P (insn))
continue;
tmp = PATTERN (insn);
@@ -3382,13 +3382,11 @@ remove_useless_addtr_insns (int check_notes)
while (next)
{
/* Jumps, calls and labels stop our search. */
- if (GET_CODE (next) == JUMP_INSN
- || GET_CODE (next) == CALL_INSN
- || GET_CODE (next) == CODE_LABEL)
+ if (JUMP_P (next) || CALL_P (next) || LABEL_P (next))
break;
/* As does another fcmp insn. */
- if (GET_CODE (next) == INSN
+ if (NONJUMP_INSN_P (next)
&& GET_CODE (PATTERN (next)) == SET
&& GET_CODE (SET_DEST (PATTERN (next))) == REG
&& REGNO (SET_DEST (PATTERN (next))) == 0)
@@ -3398,8 +3396,7 @@ remove_useless_addtr_insns (int check_notes)
}
/* Is NEXT_INSN a branch? */
- if (next
- && GET_CODE (next) == JUMP_INSN)
+ if (next && JUMP_P (next))
{
rtx pattern = PATTERN (next);
@@ -4160,16 +4157,16 @@ pa_output_function_epilogue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
always point to a valid instruction in the current function. */
/* Get the last real insn. */
- if (GET_CODE (insn) == NOTE)
+ if (NOTE_P (insn))
insn = prev_real_insn (insn);
/* If it is a sequence, then look inside. */
- if (insn && GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SEQUENCE)
+ if (insn && NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == SEQUENCE)
insn = XVECEXP (PATTERN (insn), 0, 0);
/* If insn is a CALL_INSN, then it must be a call to a volatile
function (otherwise there would be epilogue insns). */
- if (insn && GET_CODE (insn) == CALL_INSN)
+ if (insn && CALL_P (insn))
{
fputs ("\tnop\n", file);
last_address += 4;
@@ -4930,12 +4927,12 @@ pa_adjust_insn_length (rtx insn, int length)
/* Jumps inside switch tables which have unfilled delay slots need
adjustment. */
- if (GET_CODE (insn) == JUMP_INSN
+ if (JUMP_P (insn)
&& GET_CODE (pat) == PARALLEL
&& get_attr_type (insn) == TYPE_BTABLE_BRANCH)
length += 4;
/* Block move pattern. */
- else if (GET_CODE (insn) == INSN
+ else if (NONJUMP_INSN_P (insn)
&& GET_CODE (pat) == PARALLEL
&& GET_CODE (XVECEXP (pat, 0, 0)) == SET
&& GET_CODE (XEXP (XVECEXP (pat, 0, 0), 0)) == MEM
@@ -4944,7 +4941,7 @@ pa_adjust_insn_length (rtx insn, int length)
&& GET_MODE (XEXP (XVECEXP (pat, 0, 0), 1)) == BLKmode)
length += compute_movmem_length (insn) - 4;
/* Block clear pattern. */
- else if (GET_CODE (insn) == INSN
+ else if (NONJUMP_INSN_P (insn)
&& GET_CODE (pat) == PARALLEL
&& GET_CODE (XVECEXP (pat, 0, 0)) == SET
&& GET_CODE (XEXP (XVECEXP (pat, 0, 0), 0)) == MEM
@@ -4952,7 +4949,7 @@ pa_adjust_insn_length (rtx insn, int length)
&& GET_MODE (XEXP (XVECEXP (pat, 0, 0), 0)) == BLKmode)
length += compute_clrmem_length (insn) - 4;
/* Conditional branch with an unfilled delay slot. */
- else if (GET_CODE (insn) == JUMP_INSN && ! simplejump_p (insn))
+ else if (JUMP_P (insn) && ! simplejump_p (insn))
{
/* Adjust a short backwards conditional with an unfilled delay slot. */
if (GET_CODE (pat) == SET
@@ -5846,7 +5843,7 @@ pa_output_arg_descriptor (rtx call_insn)
return;
}
- gcc_assert (GET_CODE (call_insn) == CALL_INSN);
+ gcc_assert (CALL_P (call_insn));
for (link = CALL_INSN_FUNCTION_USAGE (call_insn);
link; link = XEXP (link, 1))
{
@@ -6641,7 +6638,7 @@ pa_output_lbranch (rtx dest, rtx insn, int xdelay)
if (xdelay && dbr_sequence_length () != 0)
{
/* We can't handle a jump in the delay slot. */
- gcc_assert (GET_CODE (NEXT_INSN (insn)) != JUMP_INSN);
+ gcc_assert (! JUMP_P (NEXT_INSN (insn)));
final_scan_insn (NEXT_INSN (insn), asm_out_file,
optimize, 0, NULL);
@@ -7650,7 +7647,7 @@ pa_output_millicode_call (rtx insn, rtx call_dest)
output_asm_insn ("nop", xoperands);
/* We are done if there isn't a jump in the delay slot. */
- if (seq_length == 0 || GET_CODE (NEXT_INSN (insn)) != JUMP_INSN)
+ if (seq_length == 0 || ! JUMP_P (NEXT_INSN (insn)))
return "";
/* This call has an unconditional jump in its delay slot. */
@@ -7708,7 +7705,7 @@ pa_attr_length_call (rtx insn, int sibcall)
rtx pat = PATTERN (insn);
unsigned long distance = -1;
- gcc_assert (GET_CODE (insn) == CALL_INSN);
+ gcc_assert (CALL_P (insn));
if (INSN_ADDRESSES_SET_P ())
{
@@ -7822,7 +7819,7 @@ pa_output_call (rtx insn, rtx call_dest, int sibcall)
delay slot. We can't do this in a sibcall as we don't
have a second call-clobbered scratch register available. */
if (seq_length != 0
- && GET_CODE (NEXT_INSN (insn)) != JUMP_INSN
+ && ! JUMP_P (NEXT_INSN (insn))
&& !sibcall)
{
final_scan_insn (NEXT_INSN (insn), asm_out_file,
@@ -7866,7 +7863,7 @@ pa_output_call (rtx insn, rtx call_dest, int sibcall)
indirect_call = 1;
if (seq_length != 0
- && GET_CODE (NEXT_INSN (insn)) != JUMP_INSN
+ && ! JUMP_P (NEXT_INSN (insn))
&& !sibcall
&& (!TARGET_PA_20
|| indirect_call
@@ -8032,7 +8029,7 @@ pa_output_call (rtx insn, rtx call_dest, int sibcall)
/* We are done if there isn't a jump in the delay slot. */
if (seq_length == 0
|| delay_insn_deleted
- || GET_CODE (NEXT_INSN (insn)) != JUMP_INSN)
+ || ! JUMP_P (NEXT_INSN (insn)))
return "";
/* A sibcall should never have a branch in the delay slot. */
@@ -8826,12 +8823,12 @@ int
pa_jump_in_call_delay (rtx insn)
{
- if (GET_CODE (insn) != JUMP_INSN)
+ if (! JUMP_P (insn))
return 0;
if (PREV_INSN (insn)
&& PREV_INSN (PREV_INSN (insn))
- && GET_CODE (next_real_insn (PREV_INSN (PREV_INSN (insn)))) == INSN)
+ && NONJUMP_INSN_P (next_real_insn (PREV_INSN (PREV_INSN (insn)))))
{
rtx test_insn = next_real_insn (PREV_INSN (PREV_INSN (insn)));
@@ -8928,14 +8925,14 @@ pa_following_call (rtx insn)
/* Find the previous real insn, skipping NOTEs. */
insn = PREV_INSN (insn);
- while (insn && GET_CODE (insn) == NOTE)
+ while (insn && NOTE_P (insn))
insn = PREV_INSN (insn);
/* Check for CALL_INSNs and millicode calls. */
if (insn
- && ((GET_CODE (insn) == CALL_INSN
+ && ((CALL_P (insn)
&& get_attr_type (insn) != TYPE_DYNCALL)
- || (GET_CODE (insn) == INSN
+ || (NONJUMP_INSN_P (insn)
&& GET_CODE (PATTERN (insn)) != SEQUENCE
&& GET_CODE (PATTERN (insn)) != USE
&& GET_CODE (PATTERN (insn)) != CLOBBER
@@ -9000,7 +8997,7 @@ pa_reorg (void)
unsigned int length, i;
/* Find an ADDR_VEC or ADDR_DIFF_VEC insn to explode. */
- if (GET_CODE (insn) != JUMP_INSN
+ if (! JUMP_P (insn)
|| (GET_CODE (PATTERN (insn)) != ADDR_VEC
&& GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC))
continue;
@@ -9059,7 +9056,7 @@ pa_reorg (void)
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
/* Find an ADDR_VEC insn. */
- if (GET_CODE (insn) != JUMP_INSN
+ if (! JUMP_P (insn)
|| (GET_CODE (PATTERN (insn)) != ADDR_VEC
&& GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC))
continue;
@@ -9140,9 +9137,7 @@ pa_combine_instructions (void)
/* We only care about INSNs, JUMP_INSNs, and CALL_INSNs.
Also ignore any special USE insns. */
- if ((GET_CODE (anchor) != INSN
- && GET_CODE (anchor) != JUMP_INSN
- && GET_CODE (anchor) != CALL_INSN)
+ if ((! NONJUMP_INSN_P (anchor) && ! JUMP_P (anchor) && ! CALL_P (anchor))
|| GET_CODE (PATTERN (anchor)) == USE
|| GET_CODE (PATTERN (anchor)) == CLOBBER
|| GET_CODE (PATTERN (anchor)) == ADDR_VEC
@@ -9162,14 +9157,14 @@ pa_combine_instructions (void)
floater;
floater = PREV_INSN (floater))
{
- if (GET_CODE (floater) == NOTE
- || (GET_CODE (floater) == INSN
+ if (NOTE_P (floater)
+ || (NONJUMP_INSN_P (floater)
&& (GET_CODE (PATTERN (floater)) == USE
|| GET_CODE (PATTERN (floater)) == CLOBBER)))
continue;
/* Anything except a regular INSN will stop our search. */
- if (GET_CODE (floater) != INSN
+ if (! NONJUMP_INSN_P (floater)
|| GET_CODE (PATTERN (floater)) == ADDR_VEC
|| GET_CODE (PATTERN (floater)) == ADDR_DIFF_VEC)
{
@@ -9223,15 +9218,15 @@ pa_combine_instructions (void)
{
for (floater = anchor; floater; floater = NEXT_INSN (floater))
{
- if (GET_CODE (floater) == NOTE
- || (GET_CODE (floater) == INSN
+ if (NOTE_P (floater)
+ || (NONJUMP_INSN_P (floater)
&& (GET_CODE (PATTERN (floater)) == USE
|| GET_CODE (PATTERN (floater)) == CLOBBER)))
continue;
/* Anything except a regular INSN will stop our search. */
- if (GET_CODE (floater) != INSN
+ if (! NONJUMP_INSN_P (floater)
|| GET_CODE (PATTERN (floater)) == ADDR_VEC
|| GET_CODE (PATTERN (floater)) == ADDR_DIFF_VEC)
{
@@ -9386,7 +9381,7 @@ pa_can_combine_p (rtx new_rtx, rtx anchor, rtx floater, int reversed, rtx dest,
int
pa_insn_refs_are_delayed (rtx insn)
{
- return ((GET_CODE (insn) == INSN
+ return ((NONJUMP_INSN_P (insn)
&& GET_CODE (PATTERN (insn)) != SEQUENCE
&& GET_CODE (PATTERN (insn)) != USE
&& GET_CODE (PATTERN (insn)) != CLOBBER
diff --git a/gcc/config/rs6000/constraints.md b/gcc/config/rs6000/constraints.md
index ccb61edce45..463d69c6ba4 100644
--- a/gcc/config/rs6000/constraints.md
+++ b/gcc/config/rs6000/constraints.md
@@ -64,10 +64,27 @@
(define_register_constraint "ws" "rs6000_constraints[RS6000_CONSTRAINT_ws]"
"@internal")
+;; TImode in VSX registers
+(define_register_constraint "wt" "rs6000_constraints[RS6000_CONSTRAINT_wt]"
+ "@internal")
+
;; any VSX register
(define_register_constraint "wa" "rs6000_constraints[RS6000_CONSTRAINT_wa]"
"@internal")
+;; Register constraints to simplify move patterns
+(define_register_constraint "wg" "rs6000_constraints[RS6000_CONSTRAINT_wg]"
+ "Floating point register if -mmfpgpr is used, or NO_REGS.")
+
+(define_register_constraint "wl" "rs6000_constraints[RS6000_CONSTRAINT_wl]"
+ "Floating point register if the LFIWAX instruction is enabled or NO_REGS.")
+
+(define_register_constraint "wx" "rs6000_constraints[RS6000_CONSTRAINT_wx]"
+ "Floating point register if the STFIWX instruction is enabled or NO_REGS.")
+
+(define_register_constraint "wz" "rs6000_constraints[RS6000_CONSTRAINT_wz]"
+ "Floating point register if the LFIWZX instruction is enabled or NO_REGS.")
+
;; Altivec style load/store that ignores the bottom bits of the address
(define_memory_constraint "wZ"
"Indexed or indirect memory operand, ignoring the bottom 4 bits"
diff --git a/gcc/config/rs6000/dfp.md b/gcc/config/rs6000/dfp.md
index f73e115e342..052ac482e0f 100644
--- a/gcc/config/rs6000/dfp.md
+++ b/gcc/config/rs6000/dfp.md
@@ -29,77 +29,6 @@
])
-(define_expand "movsd"
- [(set (match_operand:SD 0 "nonimmediate_operand" "")
- (match_operand:SD 1 "any_operand" ""))]
- "TARGET_HARD_FLOAT && TARGET_FPRS"
- "{ rs6000_emit_move (operands[0], operands[1], SDmode); DONE; }")
-
-(define_split
- [(set (match_operand:SD 0 "gpc_reg_operand" "")
- (match_operand:SD 1 "const_double_operand" ""))]
- "reload_completed
- && ((GET_CODE (operands[0]) == REG && REGNO (operands[0]) <= 31)
- || (GET_CODE (operands[0]) == SUBREG
- && GET_CODE (SUBREG_REG (operands[0])) == REG
- && REGNO (SUBREG_REG (operands[0])) <= 31))"
- [(set (match_dup 2) (match_dup 3))]
- "
-{
- long l;
- REAL_VALUE_TYPE rv;
-
- REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
- REAL_VALUE_TO_TARGET_DECIMAL32 (rv, l);
-
- if (! TARGET_POWERPC64)
- operands[2] = operand_subword (operands[0], 0, 0, SDmode);
- else
- operands[2] = gen_lowpart (SImode, operands[0]);
-
- operands[3] = gen_int_mode (l, SImode);
-}")
-
-(define_insn "movsd_hardfloat"
- [(set (match_operand:SD 0 "nonimmediate_operand" "=r,r,m,f,*c*l,!r,*h,!r,!r")
- (match_operand:SD 1 "input_operand" "r,m,r,f,r,h,0,G,Fn"))]
- "(gpc_reg_operand (operands[0], SDmode)
- || gpc_reg_operand (operands[1], SDmode))
- && (TARGET_HARD_FLOAT && TARGET_FPRS)"
- "@
- mr %0,%1
- lwz%U1%X1 %0,%1
- stw%U0%X0 %1,%0
- fmr %0,%1
- mt%0 %1
- mf%1 %0
- nop
- #
- #"
- [(set_attr "type" "*,load,store,fp,mtjmpr,mfjmpr,*,*,*")
- (set_attr "length" "4,4,4,4,4,4,4,4,8")])
-
-(define_insn "movsd_softfloat"
- [(set (match_operand:SD 0 "nonimmediate_operand" "=r,cl,r,r,m,r,r,r,r,r,*h")
- (match_operand:SD 1 "input_operand" "r,r,h,m,r,I,L,R,G,Fn,0"))]
- "(gpc_reg_operand (operands[0], SDmode)
- || gpc_reg_operand (operands[1], SDmode))
- && (TARGET_SOFT_FLOAT || !TARGET_FPRS)"
- "@
- mr %0,%1
- mt%0 %1
- mf%1 %0
- lwz%U1%X1 %0,%1
- stw%U0%X0 %1,%0
- li %0,%1
- lis %0,%v1
- la %0,%a1
- #
- #
- nop"
- [(set_attr "type" "*,mtjmpr,mfjmpr,load,store,*,*,*,*,*,*")
- (set_attr "length" "4,4,4,4,4,4,4,4,4,8,4")])
-
(define_insn "movsd_store"
[(set (match_operand:DD 0 "nonimmediate_operand" "=m")
(unspec:DD [(match_operand:SD 1 "input_operand" "d")]
@@ -108,7 +37,14 @@
|| gpc_reg_operand (operands[1], SDmode))
&& TARGET_HARD_FLOAT && TARGET_FPRS"
"stfd%U0%X0 %1,%0"
- [(set_attr "type" "fpstore")
+ [(set (attr "type")
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[0], VOIDmode)")
+ (const_string "fpstore_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[0], VOIDmode)")
+ (const_string "fpstore_u")
+ (const_string "fpstore"))))
(set_attr "length" "4")])
(define_insn "movsd_load"
@@ -119,7 +55,14 @@
|| gpc_reg_operand (operands[1], DDmode))
&& TARGET_HARD_FLOAT && TARGET_FPRS"
"lfd%U1%X1 %0,%1"
- [(set_attr "type" "fpload")
+ [(set (attr "type")
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[1], VOIDmode)")
+ (const_string "fpload_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[1], VOIDmode)")
+ (const_string "fpload_u")
+ (const_string "fpload"))))
(set_attr "length" "4")])
;; Hardware support for decimal floating point operations.
@@ -182,211 +125,6 @@
"fnabs %0,%1"
[(set_attr "type" "fp")])
-(define_expand "movdd"
- [(set (match_operand:DD 0 "nonimmediate_operand" "")
- (match_operand:DD 1 "any_operand" ""))]
- ""
- "{ rs6000_emit_move (operands[0], operands[1], DDmode); DONE; }")
-
-(define_split
- [(set (match_operand:DD 0 "gpc_reg_operand" "")
- (match_operand:DD 1 "const_int_operand" ""))]
- "! TARGET_POWERPC64 && reload_completed
- && ((GET_CODE (operands[0]) == REG && REGNO (operands[0]) <= 31)
- || (GET_CODE (operands[0]) == SUBREG
- && GET_CODE (SUBREG_REG (operands[0])) == REG
- && REGNO (SUBREG_REG (operands[0])) <= 31))"
- [(set (match_dup 2) (match_dup 4))
- (set (match_dup 3) (match_dup 1))]
- "
-{
- int endian = (WORDS_BIG_ENDIAN == 0);
- HOST_WIDE_INT value = INTVAL (operands[1]);
-
- operands[2] = operand_subword (operands[0], endian, 0, DDmode);
- operands[3] = operand_subword (operands[0], 1 - endian, 0, DDmode);
-#if HOST_BITS_PER_WIDE_INT == 32
- operands[4] = (value & 0x80000000) ? constm1_rtx : const0_rtx;
-#else
- operands[4] = GEN_INT (value >> 32);
- operands[1] = GEN_INT (((value & 0xffffffff) ^ 0x80000000) - 0x80000000);
-#endif
-}")
-
-(define_split
- [(set (match_operand:DD 0 "gpc_reg_operand" "")
- (match_operand:DD 1 "const_double_operand" ""))]
- "! TARGET_POWERPC64 && reload_completed
- && ((GET_CODE (operands[0]) == REG && REGNO (operands[0]) <= 31)
- || (GET_CODE (operands[0]) == SUBREG
- && GET_CODE (SUBREG_REG (operands[0])) == REG
- && REGNO (SUBREG_REG (operands[0])) <= 31))"
- [(set (match_dup 2) (match_dup 4))
- (set (match_dup 3) (match_dup 5))]
- "
-{
- int endian = (WORDS_BIG_ENDIAN == 0);
- long l[2];
- REAL_VALUE_TYPE rv;
-
- REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
- REAL_VALUE_TO_TARGET_DECIMAL64 (rv, l);
-
- operands[2] = operand_subword (operands[0], endian, 0, DDmode);
- operands[3] = operand_subword (operands[0], 1 - endian, 0, DDmode);
- operands[4] = gen_int_mode (l[endian], SImode);
- operands[5] = gen_int_mode (l[1 - endian], SImode);
-}")
-
-(define_split
- [(set (match_operand:DD 0 "gpc_reg_operand" "")
- (match_operand:DD 1 "const_double_operand" ""))]
- "TARGET_POWERPC64 && reload_completed
- && ((GET_CODE (operands[0]) == REG && REGNO (operands[0]) <= 31)
- || (GET_CODE (operands[0]) == SUBREG
- && GET_CODE (SUBREG_REG (operands[0])) == REG
- && REGNO (SUBREG_REG (operands[0])) <= 31))"
- [(set (match_dup 2) (match_dup 3))]
- "
-{
- int endian = (WORDS_BIG_ENDIAN == 0);
- long l[2];
- REAL_VALUE_TYPE rv;
-#if HOST_BITS_PER_WIDE_INT >= 64
- HOST_WIDE_INT val;
-#endif
-
- REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
- REAL_VALUE_TO_TARGET_DECIMAL64 (rv, l);
-
- operands[2] = gen_lowpart (DImode, operands[0]);
- /* HIGHPART is lower memory address when WORDS_BIG_ENDIAN. */
-#if HOST_BITS_PER_WIDE_INT >= 64
- val = ((HOST_WIDE_INT)(unsigned long)l[endian] << 32
- | ((HOST_WIDE_INT)(unsigned long)l[1 - endian]));
-
- operands[3] = gen_int_mode (val, DImode);
-#else
- operands[3] = immed_double_const (l[1 - endian], l[endian], DImode);
-#endif
-}")
-
-;; Don't have reload use general registers to load a constant. First,
-;; it might not work if the output operand is the equivalent of
-;; a non-offsettable memref, but also it is less efficient than loading
-;; the constant into an FP register, since it will probably be used there.
-;; The "??" is a kludge until we can figure out a more reasonable way
-;; of handling these non-offsettable values.
-(define_insn "*movdd_hardfloat32"
- [(set (match_operand:DD 0 "nonimmediate_operand" "=!r,??r,m,d,d,m,!r,!r,!r")
- (match_operand:DD 1 "input_operand" "r,m,r,d,m,d,G,H,F"))]
- "! TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS
- && (gpc_reg_operand (operands[0], DDmode)
- || gpc_reg_operand (operands[1], DDmode))"
- "*
-{
- switch (which_alternative)
- {
- default:
- gcc_unreachable ();
- case 0:
- case 1:
- case 2:
- return \"#\";
- case 3:
- return \"fmr %0,%1\";
- case 4:
- return \"lfd%U1%X1 %0,%1\";
- case 5:
- return \"stfd%U0%X0 %1,%0\";
- case 6:
- case 7:
- case 8:
- return \"#\";
- }
-}"
- [(set_attr "type" "two,load,store,fp,fpload,fpstore,*,*,*")
- (set_attr "length" "8,16,16,4,4,4,8,12,16")])
-
-(define_insn "*movdd_softfloat32"
- [(set (match_operand:DD 0 "nonimmediate_operand" "=r,r,m,r,r,r")
- (match_operand:DD 1 "input_operand" "r,m,r,G,H,F"))]
- "! TARGET_POWERPC64 && (TARGET_SOFT_FLOAT || !TARGET_FPRS)
- && (gpc_reg_operand (operands[0], DDmode)
- || gpc_reg_operand (operands[1], DDmode))"
- "#"
- [(set_attr "type" "two,load,store,*,*,*")
- (set_attr "length" "8,8,8,8,12,16")])
-
-; ld/std require word-aligned displacements -> 'Y' constraint.
-; List Y->r and r->Y before r->r for reload.
-(define_insn "*movdd_hardfloat64_mfpgpr"
- [(set (match_operand:DD 0 "nonimmediate_operand" "=Y,r,!r,d,d,m,*c*l,!r,*h,!r,!r,!r,r,d")
- (match_operand:DD 1 "input_operand" "r,Y,r,d,m,d,r,h,0,G,H,F,d,r"))]
- "TARGET_POWERPC64 && TARGET_MFPGPR && TARGET_HARD_FLOAT && TARGET_FPRS
- && (gpc_reg_operand (operands[0], DDmode)
- || gpc_reg_operand (operands[1], DDmode))"
- "@
- std%U0%X0 %1,%0
- ld%U1%X1 %0,%1
- mr %0,%1
- fmr %0,%1
- lfd%U1%X1 %0,%1
- stfd%U0%X0 %1,%0
- mt%0 %1
- mf%1 %0
- nop
- #
- #
- #
- mftgpr %0,%1
- mffgpr %0,%1"
- [(set_attr "type" "store,load,*,fp,fpload,fpstore,mtjmpr,mfjmpr,*,*,*,*,mftgpr,mffgpr")
- (set_attr "length" "4,4,4,4,4,4,4,4,4,8,12,16,4,4")])
-
-; ld/std require word-aligned displacements -> 'Y' constraint.
-; List Y->r and r->Y before r->r for reload.
-(define_insn "*movdd_hardfloat64"
- [(set (match_operand:DD 0 "nonimmediate_operand" "=Y,r,!r,d,d,m,*c*l,!r,*h,!r,!r,!r")
- (match_operand:DD 1 "input_operand" "r,Y,r,d,m,d,r,h,0,G,H,F"))]
- "TARGET_POWERPC64 && !TARGET_MFPGPR && TARGET_HARD_FLOAT && TARGET_FPRS
- && (gpc_reg_operand (operands[0], DDmode)
- || gpc_reg_operand (operands[1], DDmode))"
- "@
- std%U0%X0 %1,%0
- ld%U1%X1 %0,%1
- mr %0,%1
- fmr %0,%1
- lfd%U1%X1 %0,%1
- stfd%U0%X0 %1,%0
- mt%0 %1
- mf%1 %0
- nop
- #
- #
- #"
- [(set_attr "type" "store,load,*,fp,fpload,fpstore,mtjmpr,mfjmpr,*,*,*,*")
- (set_attr "length" "4,4,4,4,4,4,4,4,4,8,12,16")])
-
-(define_insn "*movdd_softfloat64"
- [(set (match_operand:DD 0 "nonimmediate_operand" "=r,Y,r,cl,r,r,r,r,*h")
- (match_operand:DD 1 "input_operand" "Y,r,r,r,h,G,H,F,0"))]
- "TARGET_POWERPC64 && (TARGET_SOFT_FLOAT || !TARGET_FPRS)
- && (gpc_reg_operand (operands[0], DDmode)
- || gpc_reg_operand (operands[1], DDmode))"
- "@
- ld%U1%X1 %0,%1
- std%U0%X0 %1,%0
- mr %0,%1
- mt%0 %1
- mf%1 %0
- #
- #
- #
- nop"
- [(set_attr "type" "load,store,*,mtjmpr,mfjmpr,*,*,*,*")
- (set_attr "length" "4,4,4,4,4,8,12,16,4")])
-
(define_expand "negtd2"
[(set (match_operand:TD 0 "gpc_reg_operand" "")
(neg:TD (match_operand:TD 1 "gpc_reg_operand" "")))]
@@ -420,27 +158,6 @@
"fnabs %0,%1"
[(set_attr "type" "fp")])
-(define_expand "movtd"
- [(set (match_operand:TD 0 "general_operand" "")
- (match_operand:TD 1 "any_operand" ""))]
- "TARGET_HARD_FLOAT && TARGET_FPRS"
- "{ rs6000_emit_move (operands[0], operands[1], TDmode); DONE; }")
-
-; It's important to list the Y->r and r->Y moves before r->r because
-; otherwise reload, given m->r, will try to pick r->r and reload it,
-; which doesn't make progress.
-(define_insn_and_split "*movtd_internal"
- [(set (match_operand:TD 0 "nonimmediate_operand" "=m,d,d,Y,r,r")
- (match_operand:TD 1 "input_operand" "d,m,d,r,YGHF,r"))]
- "TARGET_HARD_FLOAT && TARGET_FPRS
- && (gpc_reg_operand (operands[0], TDmode)
- || gpc_reg_operand (operands[1], TDmode))"
- "#"
- "&& reload_completed"
- [(pc)]
-{ rs6000_split_multireg_move (operands[0], operands[1]); DONE; }
- [(set_attr "length" "8,8,8,20,20,16")])
-
;; Hardware support for decimal floating point operations.
(define_insn "extendddtd2"
diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md
index 868ba567976..8112f26fe19 100644
--- a/gcc/config/rs6000/predicates.md
+++ b/gcc/config/rs6000/predicates.md
@@ -329,6 +329,11 @@
&& mode != DImode)
return 1;
+ /* The constant 0.0 is easy under VSX. */
+ if ((mode == SFmode || mode == DFmode || mode == SDmode || mode == DDmode)
+ && VECTOR_UNIT_VSX_P (DFmode) && op == CONST0_RTX (mode))
+ return 1;
+
if (DECIMAL_FLOAT_MODE_P (mode))
return 0;
@@ -552,6 +557,28 @@
&& REG_P (XEXP (op, 1)))")
(match_operand 0 "address_operand")))
+;; Return 1 if the operand is an index-form address.
+(define_special_predicate "indexed_address"
+ (match_test "(GET_CODE (op) == PLUS
+ && REG_P (XEXP (op, 0))
+ && REG_P (XEXP (op, 1)))"))
+
+;; Return 1 if the operand is a MEM with an update-form address. This may
+;; also include update-indexed form.
+(define_special_predicate "update_address_mem"
+ (match_test "(MEM_P (op)
+ && (GET_CODE (XEXP (op, 0)) == PRE_INC
+ || GET_CODE (XEXP (op, 0)) == PRE_DEC
+ || GET_CODE (XEXP (op, 0)) == PRE_MODIFY))"))
+
+;; Return 1 if the operand is a MEM with an update-indexed-form address. Note
+;; that PRE_INC/PRE_DEC will always be non-indexed (i.e. non X-form) since the
+;; increment is based on the mode size and will therefor always be a const.
+(define_special_predicate "update_indexed_address_mem"
+ (match_test "(MEM_P (op)
+ && GET_CODE (XEXP (op, 0)) == PRE_MODIFY
+ && indexed_address (XEXP (XEXP (op, 0), 1), mode))"))
+
;; Used for the destination of the fix_truncdfsi2 expander.
;; If stfiwx will be used, the result goes to memory; otherwise,
;; we're going to emit a store and a load of a subreg, so the dest is a
diff --git a/gcc/config/rs6000/rs6000-cpus.def b/gcc/config/rs6000/rs6000-cpus.def
index 3f17c6f2395..0564018b3f0 100644
--- a/gcc/config/rs6000/rs6000-cpus.def
+++ b/gcc/config/rs6000/rs6000-cpus.def
@@ -42,7 +42,8 @@
#define ISA_2_6_MASKS_SERVER (ISA_2_5_MASKS_SERVER \
| OPTION_MASK_POPCNTD \
| OPTION_MASK_ALTIVEC \
- | OPTION_MASK_VSX)
+ | OPTION_MASK_VSX \
+ | OPTION_MASK_VSX_TIMODE)
#define POWERPC_7400_MASK (OPTION_MASK_PPC_GFXOPT | OPTION_MASK_ALTIVEC)
@@ -76,7 +77,8 @@
| OPTION_MASK_RECIP_PRECISION \
| OPTION_MASK_SOFT_FLOAT \
| OPTION_MASK_STRICT_ALIGN_OPTIONAL \
- | OPTION_MASK_VSX)
+ | OPTION_MASK_VSX \
+ | OPTION_MASK_VSX_TIMODE)
#endif
@@ -165,11 +167,11 @@ RS6000_CPU ("power6x", PROCESSOR_POWER6, MASK_POWERPC64 | MASK_PPC_GPOPT
RS6000_CPU ("power7", PROCESSOR_POWER7, /* Don't add MASK_ISEL by default */
POWERPC_7400_MASK | MASK_POWERPC64 | MASK_PPC_GPOPT | MASK_MFCRF
| MASK_POPCNTB | MASK_FPRND | MASK_CMPB | MASK_DFP | MASK_POPCNTD
- | MASK_VSX | MASK_RECIP_PRECISION)
+ | MASK_VSX | MASK_RECIP_PRECISION | MASK_VSX_TIMODE)
RS6000_CPU ("power8", PROCESSOR_POWER7, /* Don't add MASK_ISEL by default */
POWERPC_7400_MASK | MASK_POWERPC64 | MASK_PPC_GPOPT | MASK_MFCRF
| MASK_POPCNTB | MASK_FPRND | MASK_CMPB | MASK_DFP | MASK_POPCNTD
- | MASK_VSX | MASK_RECIP_PRECISION)
+ | MASK_VSX | MASK_RECIP_PRECISION | MASK_VSX_TIMODE)
RS6000_CPU ("powerpc", PROCESSOR_POWERPC, 0)
RS6000_CPU ("powerpc64", PROCESSOR_POWERPC64, MASK_PPC_GFXOPT | MASK_POWERPC64)
RS6000_CPU ("rs64", PROCESSOR_RS64A, MASK_PPC_GFXOPT | MASK_POWERPC64)
diff --git a/gcc/config/rs6000/rs6000-modes.def b/gcc/config/rs6000/rs6000-modes.def
index bc18f8a168c..54548be7038 100644
--- a/gcc/config/rs6000/rs6000-modes.def
+++ b/gcc/config/rs6000/rs6000-modes.def
@@ -41,3 +41,6 @@ VECTOR_MODE (INT, DI, 1);
VECTOR_MODES (FLOAT, 8); /* V4HF V2SF */
VECTOR_MODES (FLOAT, 16); /* V8HF V4SF V2DF */
VECTOR_MODES (FLOAT, 32); /* V16HF V8SF V4DF */
+
+/* Replacement for TImode that only is allowed in GPRs. */
+PARTIAL_INT_MODE (TI);
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index fbf57be44a3..0fe45d8b151 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -1516,8 +1516,9 @@ rs6000_hard_regno_nregs_internal (int regno, enum machine_mode mode)
{
unsigned HOST_WIDE_INT reg_size;
+ /* TF/TD modes are special in that they always take 2 registers. */
if (FP_REGNO_P (regno))
- reg_size = (VECTOR_MEM_VSX_P (mode)
+ reg_size = ((VECTOR_MEM_VSX_P (mode) && mode != TDmode && mode != TFmode)
? UNITS_PER_VSX_WORD
: UNITS_PER_FP_WORD);
@@ -1561,14 +1562,18 @@ rs6000_hard_regno_mode_ok (int regno, enum machine_mode mode)
return ALTIVEC_REGNO_P (last_regno);
}
+ /* Allow TImode in all VSX registers if the user asked for it. Note, PTImode
+ can only go in GPRs. */
+ if (mode == TImode && TARGET_VSX_TIMODE && VSX_REGNO_P (regno))
+ return 1;
+
/* The GPRs can hold any mode, but values bigger than one register
cannot go past R31. */
if (INT_REGNO_P (regno))
return INT_REGNO_P (last_regno);
/* The float registers (except for VSX vector modes) can only hold floating
- modes and DImode. This excludes the 32-bit decimal float mode for
- now. */
+ modes and DImode. */
if (FP_REGNO_P (regno))
{
if (SCALAR_FLOAT_MODE_P (mode)
@@ -1602,9 +1607,8 @@ rs6000_hard_regno_mode_ok (int regno, enum machine_mode mode)
if (SPE_SIMD_REGNO_P (regno) && TARGET_SPE && SPE_VECTOR_MODE (mode))
return 1;
- /* We cannot put TImode anywhere except general register and it must be able
- to fit within the register set. In the future, allow TImode in the
- Altivec or VSX registers. */
+ /* We cannot put non-VSX TImode or PTImode anywhere except general register
+ and it must be able to fit within the register set. */
return GET_MODE_SIZE (mode) <= UNITS_PER_WORD;
}
@@ -1693,6 +1697,7 @@ rs6000_debug_reg_global (void)
static const char *const tf[2] = { "false", "true" };
const char *nl = (const char *)0;
int m;
+ size_t m1, m2, v;
char costly_num[20];
char nop_num[20];
char flags_buffer[40];
@@ -1713,10 +1718,67 @@ rs6000_debug_reg_global (void)
"other"
};
- fprintf (stderr, "Register information: (last virtual reg = %d)\n",
- LAST_VIRTUAL_REGISTER);
- rs6000_debug_reg_print (0, 31, "gr");
- rs6000_debug_reg_print (32, 63, "fp");
+ /* Modes we want tieable information on. */
+ static const enum machine_mode print_tieable_modes[] = {
+ QImode,
+ HImode,
+ SImode,
+ DImode,
+ TImode,
+ PTImode,
+ SFmode,
+ DFmode,
+ TFmode,
+ SDmode,
+ DDmode,
+ TDmode,
+ V8QImode,
+ V4HImode,
+ V2SImode,
+ V16QImode,
+ V8HImode,
+ V4SImode,
+ V2DImode,
+ V32QImode,
+ V16HImode,
+ V8SImode,
+ V4DImode,
+ V2SFmode,
+ V4SFmode,
+ V2DFmode,
+ V8SFmode,
+ V4DFmode,
+ CCmode,
+ CCUNSmode,
+ CCEQmode,
+ };
+
+ /* Virtual regs we are interested in. */
+ const static struct {
+ int regno; /* register number. */
+ const char *name; /* register name. */
+ } virtual_regs[] = {
+ { STACK_POINTER_REGNUM, "stack pointer:" },
+ { TOC_REGNUM, "toc: " },
+ { STATIC_CHAIN_REGNUM, "static chain: " },
+ { RS6000_PIC_OFFSET_TABLE_REGNUM, "pic offset: " },
+ { HARD_FRAME_POINTER_REGNUM, "hard frame: " },
+ { ARG_POINTER_REGNUM, "arg pointer: " },
+ { FRAME_POINTER_REGNUM, "frame pointer:" },
+ { FIRST_PSEUDO_REGISTER, "first pseudo: " },
+ { FIRST_VIRTUAL_REGISTER, "first virtual:" },
+ { VIRTUAL_INCOMING_ARGS_REGNUM, "incoming_args:" },
+ { VIRTUAL_STACK_VARS_REGNUM, "stack_vars: " },
+ { VIRTUAL_STACK_DYNAMIC_REGNUM, "stack_dynamic:" },
+ { VIRTUAL_OUTGOING_ARGS_REGNUM, "outgoing_args:" },
+ { VIRTUAL_CFA_REGNUM, "cfa (frame): " },
+ { VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM, "stack boundry:" },
+ { LAST_VIRTUAL_REGISTER, "last virtual: " },
+ };
+
+ fputs ("\nHard register information:\n", stderr);
+ rs6000_debug_reg_print (FIRST_GPR_REGNO, LAST_GPR_REGNO, "gr");
+ rs6000_debug_reg_print (FIRST_FPR_REGNO, LAST_FPR_REGNO, "fp");
rs6000_debug_reg_print (FIRST_ALTIVEC_REGNO,
LAST_ALTIVEC_REGNO,
"vs");
@@ -1729,6 +1791,10 @@ rs6000_debug_reg_global (void)
rs6000_debug_reg_print (SPE_ACC_REGNO, SPE_ACC_REGNO, "spe_a");
rs6000_debug_reg_print (SPEFSCR_REGNO, SPEFSCR_REGNO, "spe_f");
+ fputs ("\nVirtual/stack/frame registers:\n", stderr);
+ for (v = 0; v < ARRAY_SIZE (virtual_regs); v++)
+ fprintf (stderr, "%s regno = %3d\n", virtual_regs[v].name, virtual_regs[v].regno);
+
fprintf (stderr,
"\n"
"d reg_class = %s\n"
@@ -1737,28 +1803,74 @@ rs6000_debug_reg_global (void)
"wa reg_class = %s\n"
"wd reg_class = %s\n"
"wf reg_class = %s\n"
- "ws reg_class = %s\n\n",
+ "wg reg_class = %s\n"
+ "wl reg_class = %s\n"
+ "ws reg_class = %s\n"
+ "wt reg_class = %s\n"
+ "wx reg_class = %s\n"
+ "wz reg_class = %s\n"
+ "\n",
reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_d]],
reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_f]],
reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_v]],
reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wa]],
reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wd]],
reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wf]],
- reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_ws]]);
+ reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wg]],
+ reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wl]],
+ reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_ws]],
+ reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wt]],
+ reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wx]],
+ reg_class_names[rs6000_constraints[RS6000_CONSTRAINT_wz]]);
for (m = 0; m < NUM_MACHINE_MODES; ++m)
- if (rs6000_vector_unit[m] || rs6000_vector_mem[m])
+ if (rs6000_vector_unit[m] || rs6000_vector_mem[m]
+ || (rs6000_vector_reload[m][0] != CODE_FOR_nothing)
+ || (rs6000_vector_reload[m][1] != CODE_FOR_nothing))
{
nl = "\n";
- fprintf (stderr, "Vector mode: %-5s arithmetic: %-8s move: %-8s\n",
+ fprintf (stderr,
+ "Vector mode: %-5s arithmetic: %-10s move: %-10s "
+ "reload-out: %c reload-in: %c\n",
GET_MODE_NAME (m),
rs6000_debug_vector_unit[ rs6000_vector_unit[m] ],
- rs6000_debug_vector_unit[ rs6000_vector_mem[m] ]);
+ rs6000_debug_vector_unit[ rs6000_vector_mem[m] ],
+ (rs6000_vector_reload[m][0] != CODE_FOR_nothing) ? 'y' : 'n',
+ (rs6000_vector_reload[m][1] != CODE_FOR_nothing) ? 'y' : 'n');
}
if (nl)
fputs (nl, stderr);
+ for (m1 = 0; m1 < ARRAY_SIZE (print_tieable_modes); m1++)
+ {
+ enum machine_mode mode1 = print_tieable_modes[m1];
+ bool first_time = true;
+
+ nl = (const char *)0;
+ for (m2 = 0; m2 < ARRAY_SIZE (print_tieable_modes); m2++)
+ {
+ enum machine_mode mode2 = print_tieable_modes[m2];
+ if (mode1 != mode2 && MODES_TIEABLE_P (mode1, mode2))
+ {
+ if (first_time)
+ {
+ fprintf (stderr, "Tieable modes %s:", GET_MODE_NAME (mode1));
+ nl = "\n";
+ first_time = false;
+ }
+
+ fprintf (stderr, " %s", GET_MODE_NAME (mode2));
+ }
+ }
+
+ if (!first_time)
+ fputs ("\n", stderr);
+ }
+
+ if (nl)
+ fputs (nl, stderr);
+
if (rs6000_recip_control)
{
fprintf (stderr, "\nReciprocal mask = 0x%x\n", rs6000_recip_control);
@@ -1938,6 +2050,9 @@ rs6000_debug_reg_global (void)
if (TARGET_LINK_STACK)
fprintf (stderr, DEBUG_FMT_S, "link_stack", "true");
+ if (targetm.lra_p ())
+ fprintf (stderr, DEBUG_FMT_S, "lra", "true");
+
fprintf (stderr, DEBUG_FMT_S, "plt-format",
TARGET_SECURE_PLT ? "secure" : "bss");
fprintf (stderr, DEBUG_FMT_S, "struct-return",
@@ -2083,6 +2198,13 @@ rs6000_init_hard_regno_mode_ok (bool global_init_p)
rs6000_vector_align[DFmode] = align64;
}
+ /* Allow TImode in VSX register and set the VSX memory macros. */
+ if (TARGET_VSX && TARGET_VSX_TIMODE)
+ {
+ rs6000_vector_mem[TImode] = VECTOR_VSX;
+ rs6000_vector_align[TImode] = align64;
+ }
+
/* TODO add SPE and paired floating point vector support. */
/* Register class constraints for the constraints that depend on compile
@@ -2106,11 +2228,27 @@ rs6000_init_hard_regno_mode_ok (bool global_init_p)
rs6000_constraints[RS6000_CONSTRAINT_ws] = (TARGET_VSX_SCALAR_MEMORY
? VSX_REGS
: FLOAT_REGS);
+ if (TARGET_VSX_TIMODE)
+ rs6000_constraints[RS6000_CONSTRAINT_wt] = VSX_REGS;
}
+ /* Add conditional constraints based on various options, to allow us to
+ collapse multiple insn patterns. */
if (TARGET_ALTIVEC)
rs6000_constraints[RS6000_CONSTRAINT_v] = ALTIVEC_REGS;
+ if (TARGET_MFPGPR)
+ rs6000_constraints[RS6000_CONSTRAINT_wg] = FLOAT_REGS;
+
+ if (TARGET_LFIWAX)
+ rs6000_constraints[RS6000_CONSTRAINT_wl] = FLOAT_REGS;
+
+ if (TARGET_STFIWX)
+ rs6000_constraints[RS6000_CONSTRAINT_wx] = FLOAT_REGS;
+
+ if (TARGET_LFIWZX)
+ rs6000_constraints[RS6000_CONSTRAINT_wz] = FLOAT_REGS;
+
/* Set up the reload helper functions. */
if (TARGET_VSX || TARGET_ALTIVEC)
{
@@ -2132,6 +2270,13 @@ rs6000_init_hard_regno_mode_ok (bool global_init_p)
{
rs6000_vector_reload[DFmode][0] = CODE_FOR_reload_df_di_store;
rs6000_vector_reload[DFmode][1] = CODE_FOR_reload_df_di_load;
+ rs6000_vector_reload[DDmode][0] = CODE_FOR_reload_dd_di_store;
+ rs6000_vector_reload[DDmode][1] = CODE_FOR_reload_dd_di_load;
+ }
+ if (TARGET_VSX_TIMODE)
+ {
+ rs6000_vector_reload[TImode][0] = CODE_FOR_reload_ti_di_store;
+ rs6000_vector_reload[TImode][1] = CODE_FOR_reload_ti_di_load;
}
}
else
@@ -2152,6 +2297,13 @@ rs6000_init_hard_regno_mode_ok (bool global_init_p)
{
rs6000_vector_reload[DFmode][0] = CODE_FOR_reload_df_si_store;
rs6000_vector_reload[DFmode][1] = CODE_FOR_reload_df_si_load;
+ rs6000_vector_reload[DDmode][0] = CODE_FOR_reload_dd_si_store;
+ rs6000_vector_reload[DDmode][1] = CODE_FOR_reload_dd_si_load;
+ }
+ if (TARGET_VSX_TIMODE)
+ {
+ rs6000_vector_reload[TImode][0] = CODE_FOR_reload_ti_si_store;
+ rs6000_vector_reload[TImode][1] = CODE_FOR_reload_ti_si_load;
}
}
}
@@ -2641,6 +2793,9 @@ rs6000_option_override_internal (bool global_init_p)
}
}
+ if (TARGET_DEBUG_REG || TARGET_DEBUG_TARGET)
+ rs6000_print_isa_options (stderr, 0, "before defaults", rs6000_isa_flags);
+
/* For the newer switches (vsx, dfp, etc.) set some of the older options,
unless the user explicitly used the -mno-<option> to disable the code. */
if (TARGET_VSX)
@@ -2658,6 +2813,16 @@ rs6000_option_override_internal (bool global_init_p)
else if (TARGET_ALTIVEC)
rs6000_isa_flags |= (OPTION_MASK_PPC_GFXOPT & ~rs6000_isa_flags_explicit);
+ if (TARGET_VSX_TIMODE && !TARGET_VSX)
+ {
+ if (rs6000_isa_flags_explicit & OPTION_MASK_VSX_TIMODE)
+ error ("-mvsx-timode requires -mvsx");
+ rs6000_isa_flags &= ~OPTION_MASK_VSX_TIMODE;
+ }
+
+ if (TARGET_DEBUG_REG || TARGET_DEBUG_TARGET)
+ rs6000_print_isa_options (stderr, 0, "after defaults", rs6000_isa_flags);
+
/* E500mc does "better" if we inline more aggressively. Respect the
user's opinion, though. */
if (rs6000_block_move_inline_limit == 0
@@ -2784,6 +2949,9 @@ rs6000_option_override_internal (bool global_init_p)
if (flag_section_anchors)
TARGET_NO_FP_IN_TOC = 1;
+ if (TARGET_DEBUG_REG || TARGET_DEBUG_TARGET)
+ rs6000_print_isa_options (stderr, 0, "before subtarget", rs6000_isa_flags);
+
#ifdef SUBTARGET_OVERRIDE_OPTIONS
SUBTARGET_OVERRIDE_OPTIONS;
#endif
@@ -2794,6 +2962,9 @@ rs6000_option_override_internal (bool global_init_p)
SUB3TARGET_OVERRIDE_OPTIONS;
#endif
+ if (TARGET_DEBUG_REG || TARGET_DEBUG_TARGET)
+ rs6000_print_isa_options (stderr, 0, "after subtarget", rs6000_isa_flags);
+
/* For the E500 family of cores, reset the single/double FP flags to let us
check that they remain constant across attributes or pragmas. Also,
clear a possible request for string instructions, not supported and which
@@ -4932,7 +5103,7 @@ invalid_e500_subreg (rtx op, enum machine_mode mode)
purpose. */
if (GET_CODE (op) == SUBREG
&& (mode == SImode || mode == DImode || mode == TImode
- || mode == DDmode || mode == TDmode)
+ || mode == DDmode || mode == TDmode || mode == PTImode)
&& REG_P (SUBREG_REG (op))
&& (GET_MODE (SUBREG_REG (op)) == DFmode
|| GET_MODE (SUBREG_REG (op)) == TFmode))
@@ -4945,6 +5116,7 @@ invalid_e500_subreg (rtx op, enum machine_mode mode)
&& REG_P (SUBREG_REG (op))
&& (GET_MODE (SUBREG_REG (op)) == DImode
|| GET_MODE (SUBREG_REG (op)) == TImode
+ || GET_MODE (SUBREG_REG (op)) == PTImode
|| GET_MODE (SUBREG_REG (op)) == DDmode
|| GET_MODE (SUBREG_REG (op)) == TDmode))
return true;
@@ -5164,7 +5336,11 @@ reg_offset_addressing_ok_p (enum machine_mode mode)
case V4SImode:
case V2DFmode:
case V2DImode:
- /* AltiVec/VSX vector modes. Only reg+reg addressing is valid. */
+ case TImode:
+ /* AltiVec/VSX vector modes. Only reg+reg addressing is valid. While
+ TImode is not a vector mode, if we want to use the VSX registers to
+ move it around, we need to restrict ourselves to reg+reg
+ addressing. */
if (VECTOR_MEM_ALTIVEC_OR_VSX_P (mode))
return false;
break;
@@ -5178,6 +5354,13 @@ reg_offset_addressing_ok_p (enum machine_mode mode)
return false;
break;
+ case SDmode:
+ /* If we can do direct load/stores of SDmode, restrict it to reg+reg
+ addressing for the LFIWZX and STFIWX instructions. */
+ if (TARGET_NO_SDMODE_STACK)
+ return false;
+ break;
+
default:
break;
}
@@ -5410,7 +5593,7 @@ rs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x,
/* If we are using VSX scalar loads, restrict ourselves to reg+reg
addressing. */
- if (mode == DFmode && VECTOR_MEM_VSX_P (DFmode))
+ if (VECTOR_MEM_VSX_P (mode))
return false;
if (!worst_case)
@@ -5424,6 +5607,7 @@ rs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x,
case TFmode:
case TDmode:
case TImode:
+ case PTImode:
if (TARGET_E500_DOUBLE)
return (SPE_CONST_OFFSET_OK (offset)
&& SPE_CONST_OFFSET_OK (offset + 8));
@@ -5597,11 +5781,12 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
case TFmode:
case TDmode:
case TImode:
+ case PTImode:
/* As in legitimate_offset_address_p we do not assume
worst-case. The mode here is just a hint as to the registers
used. A TImode is usually in gprs, but may actually be in
fprs. Leave worst-case scenario for reload to handle via
- insn constraints. */
+ insn constraints. PTImode is only GPRs. */
extra = 8;
break;
default:
@@ -6332,7 +6517,7 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
&& !(TARGET_E500_DOUBLE && (mode == DFmode || mode == TFmode
|| mode == DDmode || mode == TDmode
|| mode == DImode))
- && VECTOR_MEM_NONE_P (mode))
+ && (!VECTOR_MODE_P (mode) || VECTOR_MEM_NONE_P (mode)))
{
HOST_WIDE_INT val = INTVAL (XEXP (x, 1));
HOST_WIDE_INT low = ((val & 0xffff) ^ 0x8000) - 0x8000;
@@ -6363,7 +6548,7 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
if (GET_CODE (x) == SYMBOL_REF
&& reg_offset_p
- && VECTOR_MEM_NONE_P (mode)
+ && (!VECTOR_MODE_P (mode) || VECTOR_MEM_NONE_P (mode))
&& !SPE_VECTOR_MODE (mode)
#if TARGET_MACHO
&& DEFAULT_ABI == ABI_DARWIN
@@ -6389,6 +6574,8 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
mem is sufficiently aligned. */
&& mode != TFmode
&& mode != TDmode
+ && (mode != TImode || !TARGET_VSX_TIMODE)
+ && mode != PTImode
&& (mode != DImode || TARGET_POWERPC64)
&& ((mode != DFmode && mode != DDmode) || TARGET_POWERPC64
|| (TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT)))
@@ -6510,10 +6697,12 @@ rs6000_legitimate_address_p (enum machine_mode mode, rtx x, bool reg_ok_strict)
if (legitimate_indirect_address_p (x, reg_ok_strict))
return 1;
if ((GET_CODE (x) == PRE_INC || GET_CODE (x) == PRE_DEC)
- && !VECTOR_MEM_ALTIVEC_OR_VSX_P (mode)
+ && !ALTIVEC_OR_VSX_VECTOR_MODE (mode)
&& !SPE_VECTOR_MODE (mode)
&& mode != TFmode
&& mode != TDmode
+ && mode != TImode
+ && mode != PTImode
/* Restrict addressing for DI because of our SUBREG hackery. */
&& !(TARGET_E500_DOUBLE
&& (mode == DFmode || mode == DDmode || mode == DImode))
@@ -6538,26 +6727,28 @@ rs6000_legitimate_address_p (enum machine_mode mode, rtx x, bool reg_ok_strict)
return 1;
if (rs6000_legitimate_offset_address_p (mode, x, reg_ok_strict, false))
return 1;
- if (mode != TImode
- && mode != TFmode
+ if (mode != TFmode
&& mode != TDmode
&& ((TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT)
|| TARGET_POWERPC64
|| (mode != DFmode && mode != DDmode)
|| (TARGET_E500_DOUBLE && mode != DDmode))
&& (TARGET_POWERPC64 || mode != DImode)
+ && (mode != TImode || VECTOR_MEM_VSX_P (TImode))
+ && mode != PTImode
&& !avoiding_indexed_address_p (mode)
&& legitimate_indexed_address_p (x, reg_ok_strict))
return 1;
if (GET_CODE (x) == PRE_MODIFY
&& mode != TImode
+ && mode != PTImode
&& mode != TFmode
&& mode != TDmode
&& ((TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT)
|| TARGET_POWERPC64
|| ((mode != DFmode && mode != DDmode) || TARGET_E500_DOUBLE))
&& (TARGET_POWERPC64 || mode != DImode)
- && !VECTOR_MEM_ALTIVEC_OR_VSX_P (mode)
+ && !ALTIVEC_OR_VSX_VECTOR_MODE (mode)
&& !SPE_VECTOR_MODE (mode)
/* Restrict addressing for DI because of our SUBREG hackery. */
&& !(TARGET_E500_DOUBLE
@@ -7000,7 +7191,7 @@ rs6000_emit_set_long_const (rtx dest, HOST_WIDE_INT c1, HOST_WIDE_INT c2)
}
/* Helper for the following. Get rid of [r+r] memory refs
- in cases where it won't work (TImode, TFmode, TDmode). */
+ in cases where it won't work (TImode, TFmode, TDmode, PTImode). */
static void
rs6000_eliminate_indexed_memrefs (rtx operands[2])
@@ -7145,6 +7336,7 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
if (reload_in_progress
&& mode == SDmode
+ && cfun->machine->sdmode_stack_slot != NULL_RTX
&& MEM_P (operands[0])
&& rtx_equal_p (operands[0], cfun->machine->sdmode_stack_slot)
&& REG_P (operands[1]))
@@ -7169,6 +7361,7 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
&& mode == SDmode
&& REG_P (operands[0])
&& MEM_P (operands[1])
+ && cfun->machine->sdmode_stack_slot != NULL_RTX
&& rtx_equal_p (operands[1], cfun->machine->sdmode_stack_slot))
{
if (FP_REGNO_P (REGNO (operands[0])))
@@ -7382,6 +7575,11 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
break;
case TImode:
+ if (!VECTOR_MEM_VSX_P (TImode))
+ rs6000_eliminate_indexed_memrefs (operands);
+ break;
+
+ case PTImode:
rs6000_eliminate_indexed_memrefs (operands);
break;
@@ -13624,7 +13822,7 @@ rs6000_secondary_memory_needed_rtx (enum machine_mode mode)
static bool eliminated = false;
rtx ret;
- if (mode != SDmode)
+ if (mode != SDmode || TARGET_NO_SDMODE_STACK)
ret = assign_stack_local (mode, GET_MODE_SIZE (mode), 0);
else
{
@@ -13751,7 +13949,7 @@ rs6000_secondary_reload (bool in_p,
if (rclass == GENERAL_REGS || rclass == BASE_REGS)
{
if (!legitimate_indirect_address_p (addr, false)
- && !rs6000_legitimate_offset_address_p (TImode, addr,
+ && !rs6000_legitimate_offset_address_p (PTImode, addr,
false, true))
{
sri->icode = icode;
@@ -13761,8 +13959,20 @@ rs6000_secondary_reload (bool in_p,
+ ((GET_CODE (addr) == AND) ? 1 : 0));
}
}
- /* Loads to and stores from vector registers can only do reg+reg
- addressing. Altivec registers can also do (reg+reg)&(-16). */
+ /* Allow scalar loads to/from the traditional floating point
+ registers, even if VSX memory is set. */
+ else if ((rclass == FLOAT_REGS || rclass == NO_REGS)
+ && (GET_MODE_SIZE (mode) == 4 || GET_MODE_SIZE (mode) == 8)
+ && (legitimate_indirect_address_p (addr, false)
+ || legitimate_indirect_address_p (XEXP (addr, 0), false)
+ || rs6000_legitimate_offset_address_p (mode, addr,
+ false, true)))
+
+ ;
+ /* Loads to and stores from vector registers can only do reg+reg
+ addressing. Altivec registers can also do (reg+reg)&(-16). Allow
+ scalar modes loading up the traditional floating point registers
+ to use offset addresses. */
else if (rclass == VSX_REGS || rclass == ALTIVEC_REGS
|| rclass == FLOAT_REGS || rclass == NO_REGS)
{
@@ -13938,6 +14148,36 @@ rs6000_secondary_reload (bool in_p,
return ret;
}
+/* Better tracing for rs6000_secondary_reload_inner. */
+
+static void
+rs6000_secondary_reload_trace (int line, rtx reg, rtx mem, rtx scratch,
+ bool store_p)
+{
+ rtx set, clobber;
+
+ gcc_assert (reg != NULL_RTX && mem != NULL_RTX && scratch != NULL_RTX);
+
+ fprintf (stderr, "rs6000_secondary_reload_inner:%d, type = %s\n", line,
+ store_p ? "store" : "load");
+
+ if (store_p)
+ set = gen_rtx_SET (VOIDmode, mem, reg);
+ else
+ set = gen_rtx_SET (VOIDmode, reg, mem);
+
+ clobber = gen_rtx_CLOBBER (VOIDmode, scratch);
+ debug_rtx (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, set, clobber)));
+}
+
+static void
+rs6000_secondary_reload_fail (int line, rtx reg, rtx mem, rtx scratch,
+ bool store_p)
+{
+ rs6000_secondary_reload_trace (line, reg, mem, scratch, store_p);
+ gcc_unreachable ();
+}
+
/* Fixup reload addresses for Altivec or VSX loads/stores to change SP+offset
to SP+reg addressing. */
@@ -13956,19 +14196,14 @@ rs6000_secondary_reload_inner (rtx reg, rtx mem, rtx scratch, bool store_p)
rtx cc_clobber;
if (TARGET_DEBUG_ADDR)
- {
- fprintf (stderr, "\nrs6000_secondary_reload_inner, type = %s\n",
- store_p ? "store" : "load");
- fprintf (stderr, "reg:\n");
- debug_rtx (reg);
- fprintf (stderr, "mem:\n");
- debug_rtx (mem);
- fprintf (stderr, "scratch:\n");
- debug_rtx (scratch);
- }
+ rs6000_secondary_reload_trace (__LINE__, reg, mem, scratch, store_p);
+
+ if (regno < 0 || regno >= FIRST_PSEUDO_REGISTER)
+ rs6000_secondary_reload_fail (__LINE__, reg, mem, scratch, store_p);
+
+ if (GET_CODE (mem) != MEM)
+ rs6000_secondary_reload_fail (__LINE__, reg, mem, scratch, store_p);
- gcc_assert (regno >= 0 && regno < FIRST_PSEUDO_REGISTER);
- gcc_assert (GET_CODE (mem) == MEM);
rclass = REGNO_REG_CLASS (regno);
addr = XEXP (mem, 0);
@@ -13987,19 +14222,24 @@ rs6000_secondary_reload_inner (rtx reg, rtx mem, rtx scratch, bool store_p)
if (GET_CODE (addr) == PRE_MODIFY)
{
scratch_or_premodify = XEXP (addr, 0);
- gcc_assert (REG_P (scratch_or_premodify));
- gcc_assert (GET_CODE (XEXP (addr, 1)) == PLUS);
+ if (!REG_P (scratch_or_premodify))
+ rs6000_secondary_reload_fail (__LINE__, reg, mem, scratch, store_p);
+
+ if (GET_CODE (XEXP (addr, 1)) != PLUS)
+ rs6000_secondary_reload_fail (__LINE__, reg, mem, scratch, store_p);
+
addr = XEXP (addr, 1);
}
if (GET_CODE (addr) == PLUS
&& (and_op2 != NULL_RTX
- || !rs6000_legitimate_offset_address_p (TImode, addr,
+ || !rs6000_legitimate_offset_address_p (PTImode, addr,
false, true)))
{
addr_op1 = XEXP (addr, 0);
addr_op2 = XEXP (addr, 1);
- gcc_assert (legitimate_indirect_address_p (addr_op1, false));
+ if (!legitimate_indirect_address_p (addr_op1, false))
+ rs6000_secondary_reload_fail (__LINE__, reg, mem, scratch, store_p);
if (!REG_P (addr_op2)
&& (GET_CODE (addr_op2) != CONST_INT
@@ -14027,7 +14267,7 @@ rs6000_secondary_reload_inner (rtx reg, rtx mem, rtx scratch, bool store_p)
scratch_or_premodify = scratch;
}
else if (!legitimate_indirect_address_p (addr, false)
- && !rs6000_legitimate_offset_address_p (TImode, addr,
+ && !rs6000_legitimate_offset_address_p (PTImode, addr,
false, true))
{
if (TARGET_DEBUG_ADDR)
@@ -14043,9 +14283,21 @@ rs6000_secondary_reload_inner (rtx reg, rtx mem, rtx scratch, bool store_p)
}
break;
- /* Float/Altivec registers can only handle reg+reg addressing. Move
- other addresses into a scratch register. */
+ /* Float registers can do offset+reg addressing for scalar types. */
case FLOAT_REGS:
+ if (legitimate_indirect_address_p (addr, false) /* reg */
+ || legitimate_indexed_address_p (addr, false) /* reg+reg */
+ || ((GET_MODE_SIZE (mode) == 4 || GET_MODE_SIZE (mode) == 8)
+ && and_op2 == NULL_RTX
+ && scratch_or_premodify == scratch
+ && rs6000_legitimate_offset_address_p (mode, addr, false, false)))
+ break;
+
+ /* If this isn't a legacy floating point load/store, fall through to the
+ VSX defaults. */
+
+ /* VSX/Altivec registers can only handle reg+reg addressing. Move other
+ addresses into a scratch register. */
case VSX_REGS:
case ALTIVEC_REGS:
@@ -14065,36 +14317,38 @@ rs6000_secondary_reload_inner (rtx reg, rtx mem, rtx scratch, bool store_p)
/* If we aren't using a VSX load, save the PRE_MODIFY register and use it
as the address later. */
if (GET_CODE (addr) == PRE_MODIFY
- && (!VECTOR_MEM_VSX_P (mode)
+ && ((ALTIVEC_OR_VSX_VECTOR_MODE (mode)
+ && (rclass != FLOAT_REGS
+ || (GET_MODE_SIZE (mode) != 4 && GET_MODE_SIZE (mode) != 8)))
|| and_op2 != NULL_RTX
|| !legitimate_indexed_address_p (XEXP (addr, 1), false)))
{
scratch_or_premodify = XEXP (addr, 0);
- gcc_assert (legitimate_indirect_address_p (scratch_or_premodify,
- false));
- gcc_assert (GET_CODE (XEXP (addr, 1)) == PLUS);
+ if (!legitimate_indirect_address_p (scratch_or_premodify, false))
+ rs6000_secondary_reload_fail (__LINE__, reg, mem, scratch, store_p);
+
+ if (GET_CODE (XEXP (addr, 1)) != PLUS)
+ rs6000_secondary_reload_fail (__LINE__, reg, mem, scratch, store_p);
+
addr = XEXP (addr, 1);
}
if (legitimate_indirect_address_p (addr, false) /* reg */
|| legitimate_indexed_address_p (addr, false) /* reg+reg */
- || GET_CODE (addr) == PRE_MODIFY /* VSX pre-modify */
|| (GET_CODE (addr) == AND /* Altivec memory */
+ && rclass == ALTIVEC_REGS
&& GET_CODE (XEXP (addr, 1)) == CONST_INT
&& INTVAL (XEXP (addr, 1)) == -16
- && VECTOR_MEM_ALTIVEC_P (mode))
- || (rclass == FLOAT_REGS /* legacy float mem */
- && GET_MODE_SIZE (mode) == 8
- && and_op2 == NULL_RTX
- && scratch_or_premodify == scratch
- && rs6000_legitimate_offset_address_p (mode, addr, false, false)))
+ && (legitimate_indirect_address_p (XEXP (addr, 0), false)
+ || legitimate_indexed_address_p (XEXP (addr, 0), false))))
;
else if (GET_CODE (addr) == PLUS)
{
addr_op1 = XEXP (addr, 0);
addr_op2 = XEXP (addr, 1);
- gcc_assert (REG_P (addr_op1));
+ if (!REG_P (addr_op1))
+ rs6000_secondary_reload_fail (__LINE__, reg, mem, scratch, store_p);
if (TARGET_DEBUG_ADDR)
{
@@ -14113,7 +14367,8 @@ rs6000_secondary_reload_inner (rtx reg, rtx mem, rtx scratch, bool store_p)
}
else if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == CONST
- || GET_CODE (addr) == CONST_INT || REG_P (addr))
+ || GET_CODE (addr) == CONST_INT || GET_CODE (addr) == LO_SUM
+ || REG_P (addr))
{
if (TARGET_DEBUG_ADDR)
{
@@ -14129,12 +14384,12 @@ rs6000_secondary_reload_inner (rtx reg, rtx mem, rtx scratch, bool store_p)
}
else
- gcc_unreachable ();
+ rs6000_secondary_reload_fail (__LINE__, reg, mem, scratch, store_p);
break;
default:
- gcc_unreachable ();
+ rs6000_secondary_reload_fail (__LINE__, reg, mem, scratch, store_p);
}
/* If the original address involved a pre-modify that we couldn't use the VSX
@@ -14246,8 +14501,10 @@ rs6000_secondary_reload_gpr (rtx reg, rtx mem, rtx scratch, bool store_p)
return;
}
-/* Allocate a 64-bit stack slot to be used for copying SDmode
- values through if this function has any SDmode references. */
+/* Allocate a 64-bit stack slot to be used for copying SDmode values through if
+ this function has any SDmode references. If we are on a power7 or later, we
+ don't need the 64-bit stack slot since the LFIWZX and STIFWX instructions
+ can load/store the value. */
static void
rs6000_alloc_sdmode_stack_slot (void)
@@ -14258,6 +14515,9 @@ rs6000_alloc_sdmode_stack_slot (void)
gcc_assert (cfun->machine->sdmode_stack_slot == NULL_RTX);
+ if (TARGET_NO_SDMODE_STACK)
+ return;
+
FOR_EACH_BB (bb)
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
{
@@ -14318,8 +14578,7 @@ rs6000_preferred_reload_class (rtx x, enum reg_class rclass)
{
enum machine_mode mode = GET_MODE (x);
- if (VECTOR_UNIT_VSX_P (mode)
- && x == CONST0_RTX (mode) && VSX_REG_CLASS_P (rclass))
+ if (TARGET_VSX && x == CONST0_RTX (mode) && VSX_REG_CLASS_P (rclass))
return rclass;
if (VECTOR_UNIT_ALTIVEC_OR_VSX_P (mode)
@@ -14494,11 +14753,17 @@ rs6000_secondary_reload_class (enum reg_class rclass, enum machine_mode mode,
return (mode != SDmode) ? NO_REGS : GENERAL_REGS;
/* Memory, and FP/altivec registers can go into fp/altivec registers under
- VSX. */
+ VSX. However, for scalar variables, use the traditional floating point
+ registers so that we can use offset+register addressing. */
if (TARGET_VSX
&& (regno == -1 || VSX_REGNO_P (regno))
&& VSX_REG_CLASS_P (rclass))
- return NO_REGS;
+ {
+ if (GET_MODE_SIZE (mode) < 16)
+ return FLOAT_REGS;
+
+ return NO_REGS;
+ }
/* Memory, and AltiVec registers can go into AltiVec registers. */
if ((regno == -1 || ALTIVEC_REGNO_P (regno))
@@ -14543,8 +14808,35 @@ rs6000_cannot_change_mode_class (enum machine_mode from,
if (from_size != to_size)
{
enum reg_class xclass = (TARGET_VSX) ? VSX_REGS : FLOAT_REGS;
- return ((from_size < 8 || to_size < 8 || TARGET_IEEEQUAD)
- && reg_classes_intersect_p (xclass, rclass));
+
+ if (reg_classes_intersect_p (xclass, rclass))
+ {
+ unsigned to_nregs = hard_regno_nregs[FIRST_FPR_REGNO][to];
+ unsigned from_nregs = hard_regno_nregs[FIRST_FPR_REGNO][from];
+
+ /* Don't allow 64-bit types to overlap with 128-bit types that take a
+ single register under VSX because the scalar part of the register
+ is in the upper 64-bits, and not the lower 64-bits. Types like
+ TFmode/TDmode that take 2 scalar register can overlap. 128-bit
+ IEEE floating point can't overlap, and neither can small
+ values. */
+
+ if (TARGET_IEEEQUAD && (to == TFmode || from == TFmode))
+ return true;
+
+ if (from_size < 8 || to_size < 8)
+ return true;
+
+ if (from_size == 8 && (8 * to_nregs) != to_size)
+ return true;
+
+ if (to_size == 8 && (8 * from_nregs) != from_size)
+ return true;
+
+ return false;
+ }
+ else
+ return false;
}
if (TARGET_E500_DOUBLE
@@ -14558,9 +14850,18 @@ rs6000_cannot_change_mode_class (enum machine_mode from,
/* Since the VSX register set includes traditional floating point registers
and altivec registers, just check for the size being different instead of
trying to check whether the modes are vector modes. Otherwise it won't
- allow say DF and DI to change classes. */
+ allow say DF and DI to change classes. For types like TFmode and TDmode
+ that take 2 64-bit registers, rather than a single 128-bit register, don't
+ allow subregs of those types to other 128 bit types. */
if (TARGET_VSX && VSX_REG_CLASS_P (rclass))
- return (from_size != 8 && from_size != 16);
+ {
+ unsigned num_regs = (from_size + 15) / 16;
+ if (hard_regno_nregs[FIRST_FPR_REGNO][to] > num_regs
+ || hard_regno_nregs[FIRST_FPR_REGNO][from] > num_regs)
+ return true;
+
+ return (from_size != 8 && from_size != 16);
+ }
if (TARGET_ALTIVEC && rclass == ALTIVEC_REGS
&& (ALTIVEC_VECTOR_MODE (from) + ALTIVEC_VECTOR_MODE (to)) == 1)
@@ -15295,7 +15596,7 @@ print_operand (FILE *file, rtx x, int code)
return;
case 'Y':
- /* Like 'L', for third word of TImode */
+ /* Like 'L', for third word of TImode/PTImode */
if (REG_P (x))
fputs (reg_names[REGNO (x) + 2], file);
else if (MEM_P (x))
@@ -15345,7 +15646,7 @@ print_operand (FILE *file, rtx x, int code)
return;
case 'Z':
- /* Like 'L', for last word of TImode. */
+ /* Like 'L', for last word of TImode/PTImode. */
if (REG_P (x))
fputs (reg_names[REGNO (x) + 3], file);
else if (MEM_P (x))
@@ -15376,7 +15677,8 @@ print_operand (FILE *file, rtx x, int code)
if ((TARGET_SPE || TARGET_E500_DOUBLE)
&& (GET_MODE_SIZE (GET_MODE (x)) == 8
|| GET_MODE (x) == TFmode
- || GET_MODE (x) == TImode))
+ || GET_MODE (x) == TImode
+ || GET_MODE (x) == PTImode))
{
/* Handle [reg]. */
if (REG_P (tmp))
@@ -17541,9 +17843,8 @@ compute_save_world_info (rs6000_stack_t *info_ptr)
if (WORLD_SAVE_P (info_ptr))
{
rtx insn;
- for ( insn = get_last_insn_anywhere (); insn; insn = PREV_INSN (insn))
- if ( GET_CODE (insn) == CALL_INSN
- && SIBLING_CALL_P (insn))
+ for (insn = get_last_insn_anywhere (); insn; insn = PREV_INSN (insn))
+ if (CALL_P (insn) && SIBLING_CALL_P (insn))
{
info_ptr->world_save_p = 0;
break;
@@ -23535,7 +23836,7 @@ is_load_insn (rtx insn, rtx *load_mem)
if (!insn || !INSN_P (insn))
return false;
- if (GET_CODE (insn) == CALL_INSN)
+ if (CALL_P (insn))
return false;
return is_load_insn1 (PATTERN (insn), load_mem);
@@ -23930,7 +24231,7 @@ insn_must_be_first_in_group (rtx insn)
enum attr_type type;
if (!insn
- || GET_CODE (insn) == NOTE
+ || NOTE_P (insn)
|| DEBUG_INSN_P (insn)
|| GET_CODE (PATTERN (insn)) == USE
|| GET_CODE (PATTERN (insn)) == CLOBBER)
@@ -24061,7 +24362,7 @@ insn_must_be_last_in_group (rtx insn)
enum attr_type type;
if (!insn
- || GET_CODE (insn) == NOTE
+ || NOTE_P (insn)
|| DEBUG_INSN_P (insn)
|| GET_CODE (PATTERN (insn)) == USE
|| GET_CODE (PATTERN (insn)) == CLOBBER)
@@ -26429,7 +26730,7 @@ rs6000_register_move_cost (enum machine_mode mode,
}
/* If we have VSX, we can easily move between FPR or Altivec registers. */
- else if (VECTOR_UNIT_VSX_P (mode)
+ else if (VECTOR_MEM_VSX_P (mode)
&& reg_classes_intersect_p (to, VSX_REGS)
&& reg_classes_intersect_p (from, VSX_REGS))
ret = 2 * hard_regno_nregs[32][mode];
@@ -26470,7 +26771,8 @@ rs6000_memory_move_cost (enum machine_mode mode, reg_class_t rclass,
if (reg_classes_intersect_p (rclass, GENERAL_REGS))
ret = 4 * hard_regno_nregs[0][mode];
- else if (reg_classes_intersect_p (rclass, FLOAT_REGS))
+ else if ((reg_classes_intersect_p (rclass, FLOAT_REGS)
+ || reg_classes_intersect_p (rclass, VSX_REGS)))
ret = 4 * hard_regno_nregs[32][mode];
else if (reg_classes_intersect_p (rclass, ALTIVEC_REGS))
ret = 4 * hard_regno_nregs[FIRST_ALTIVEC_REGNO][mode];
@@ -27684,6 +27986,7 @@ static struct rs6000_opt_mask const rs6000_opt_masks[] =
{ "recip-precision", OPTION_MASK_RECIP_PRECISION, false, true },
{ "string", OPTION_MASK_STRING, false, true },
{ "vsx", OPTION_MASK_VSX, false, true },
+ { "vsx-timode", OPTION_MASK_VSX_TIMODE, false, true },
#ifdef OPTION_MASK_64BIT
#if TARGET_AIX_OS
{ "aix64", OPTION_MASK_64BIT, false, false },
diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h
index b5c79ea6e95..b7b415d69c0 100644
--- a/gcc/config/rs6000/rs6000.h
+++ b/gcc/config/rs6000/rs6000.h
@@ -479,6 +479,11 @@ extern int rs6000_vector_align[];
#define TARGET_FCTIDUZ TARGET_POPCNTD
#define TARGET_FCTIWUZ TARGET_POPCNTD
+/* Power7 has both 32-bit load and store integer for the FPRs, so we don't need
+ to allocate the SDmode stack slot to get the value into the proper location
+ in the register. */
+#define TARGET_NO_SDMODE_STACK (TARGET_LFIWZX && TARGET_STFIWX && TARGET_DFP)
+
/* In switching from using target_flags to using rs6000_isa_flags, the options
machinery creates OPTION_MASK_<xxx> instead of MASK_<xxx>. For now map
OPTION_MASK_<xxx> back into MASK_<xxx>. */
@@ -505,6 +510,7 @@ extern int rs6000_vector_align[];
#define MASK_STRING OPTION_MASK_STRING
#define MASK_UPDATE OPTION_MASK_UPDATE
#define MASK_VSX OPTION_MASK_VSX
+#define MASK_VSX_TIMODE OPTION_MASK_VSX_TIMODE
#ifndef IN_LIBGCC2
#define MASK_POWERPC64 OPTION_MASK_POWERPC64
@@ -1325,8 +1331,13 @@ enum r6000_reg_class_enum {
RS6000_CONSTRAINT_v, /* Altivec registers */
RS6000_CONSTRAINT_wa, /* Any VSX register */
RS6000_CONSTRAINT_wd, /* VSX register for V2DF */
+ RS6000_CONSTRAINT_wg, /* FPR register for -mmfpgpr */
RS6000_CONSTRAINT_wf, /* VSX register for V4SF */
+ RS6000_CONSTRAINT_wl, /* FPR register for LFIWAX */
RS6000_CONSTRAINT_ws, /* VSX register for DF */
+ RS6000_CONSTRAINT_wt, /* VSX register for TImode */
+ RS6000_CONSTRAINT_wx, /* FPR register for STFIWX */
+ RS6000_CONSTRAINT_wz, /* FPR register for LFIWZX */
RS6000_CONSTRAINT_MAX
};
@@ -1511,7 +1522,7 @@ extern enum reg_class rs6000_constraints[RS6000_CONSTRAINT_MAX];
NONLOCAL needs twice Pmode to maintain both backchain and SP. */
#define STACK_SAVEAREA_MODE(LEVEL) \
(LEVEL == SAVE_FUNCTION ? VOIDmode \
- : LEVEL == SAVE_NONLOCAL ? (TARGET_32BIT ? DImode : TImode) : Pmode)
+ : LEVEL == SAVE_NONLOCAL ? (TARGET_32BIT ? DImode : PTImode) : Pmode)
/* Minimum and maximum general purpose registers used to hold arguments. */
#define GP_ARG_MIN_REG 3
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index a665fa50abf..0a5d32728a1 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -25,10 +25,14 @@
;;
(define_constants
- [(STACK_POINTER_REGNUM 1)
+ [(FIRST_GPR_REGNO 0)
+ (STACK_POINTER_REGNUM 1)
(TOC_REGNUM 2)
(STATIC_CHAIN_REGNUM 11)
(HARD_FRAME_POINTER_REGNUM 31)
+ (LAST_GPR_REGNO 31)
+ (FIRST_FPR_REGNO 32)
+ (LAST_FPR_REGNO 63)
(LR_REGNO 65)
(CTR_REGNO 66)
(ARG_POINTER_REGNUM 67)
@@ -215,7 +219,7 @@
(define_mode_iterator GPR [SI (DI "TARGET_POWERPC64")])
; Any supported integer mode.
-(define_mode_iterator INT [QI HI SI DI TI])
+(define_mode_iterator INT [QI HI SI DI TI PTI])
; Any supported integer mode that fits in one register.
(define_mode_iterator INT1 [QI HI SI (DI "TARGET_POWERPC64")])
@@ -230,6 +234,10 @@
; (one with a '.') will compare; and the size used for arithmetic carries.
(define_mode_iterator P [(SI "TARGET_32BIT") (DI "TARGET_64BIT")])
+; Iterator to add PTImode along with TImode (TImode can go in VSX registers,
+; PTImode is GPR only)
+(define_mode_iterator TI2 [TI PTI])
+
; Any hardware-supported floating-point mode
(define_mode_iterator FP [
(SF "TARGET_HARD_FLOAT
@@ -253,6 +261,35 @@
(V2DF "VECTOR_UNIT_ALTIVEC_OR_VSX_P (V2DFmode)")
])
+; Floating point move iterators to combine binary and decimal moves
+(define_mode_iterator FMOVE32 [SF SD])
+(define_mode_iterator FMOVE64 [DF DD])
+(define_mode_iterator FMOVE64X [DI DF DD])
+(define_mode_iterator FMOVE128 [(TF "!TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128")
+ (TD "TARGET_HARD_FLOAT && TARGET_FPRS")])
+
+; Whether a floating point move is ok, don't allow SD without hardware FP
+(define_mode_attr fmove_ok [(SF "")
+ (DF "")
+ (SD "TARGET_HARD_FLOAT && TARGET_FPRS")
+ (DD "")])
+
+; Convert REAL_VALUE to the appropriate bits
+(define_mode_attr real_value_to_target [(SF "REAL_VALUE_TO_TARGET_SINGLE")
+ (DF "REAL_VALUE_TO_TARGET_DOUBLE")
+ (SD "REAL_VALUE_TO_TARGET_DECIMAL32")
+ (DD "REAL_VALUE_TO_TARGET_DECIMAL64")])
+
+; Definitions for load to 32-bit fpr register
+(define_mode_attr f32_lr [(SF "f") (SD "wz")])
+(define_mode_attr f32_lm [(SF "m") (SD "Z")])
+(define_mode_attr f32_li [(SF "lfs%U1%X1 %0,%1") (SD "lfiwzx %0,%y1")])
+
+; Definitions for store from 32-bit fpr register
+(define_mode_attr f32_sr [(SF "f") (SD "wx")])
+(define_mode_attr f32_sm [(SF "m") (SD "Z")])
+(define_mode_attr f32_si [(SF "stfs%U0%X0 %1,%0") (SD "stfiwx %1,%y0")])
+
; These modes do not fit in integer registers in 32-bit mode.
; but on e500v2, the gpr are 64 bit registers
(define_mode_iterator DIFD [DI (DF "!TARGET_E500_DOUBLE") DD])
@@ -271,7 +308,14 @@
; Various instructions that come in SI and DI forms.
; A generic w/d attribute, for things like cmpw/cmpd.
-(define_mode_attr wd [(QI "b") (HI "h") (SI "w") (DI "d")])
+(define_mode_attr wd [(QI "b")
+ (HI "h")
+ (SI "w")
+ (DI "d")
+ (V16QI "b")
+ (V8HI "h")
+ (V4SI "w")
+ (V2DI "d")])
; DImode bits
(define_mode_attr dbits [(QI "56") (HI "48") (SI "32")])
@@ -328,7 +372,15 @@
"@
l<wd>z%U1%X1 %0,%1
rldicl %0,%1,0,<dbits>"
- [(set_attr "type" "load,*")])
+ [(set_attr_alternative "type"
+ [(if_then_else
+ (match_test "update_indexed_address_mem (operands[1], VOIDmode)")
+ (const_string "load_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[1], VOIDmode)")
+ (const_string "load_u")
+ (const_string "load")))
+ (const_string "*")])])
(define_insn "*zero_extend<mode>di2_internal2"
[(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
@@ -454,7 +506,15 @@
"@
lha%U1%X1 %0,%1
extsh %0,%1"
- [(set_attr "type" "load_ext,exts")])
+ [(set_attr_alternative "type"
+ [(if_then_else
+ (match_test "update_indexed_address_mem (operands[1], VOIDmode)")
+ (const_string "load_ext_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[1], VOIDmode)")
+ (const_string "load_ext_u")
+ (const_string "load_ext")))
+ (const_string "exts")])])
(define_insn ""
[(set (match_operand:DI 0 "gpc_reg_operand" "=r")
@@ -528,7 +588,15 @@
"@
lwa%U1%X1 %0,%1
extsw %0,%1"
- [(set_attr "type" "load_ext,exts")])
+ [(set_attr_alternative "type"
+ [(if_then_else
+ (match_test "update_indexed_address_mem (operands[1], VOIDmode)")
+ (const_string "load_ext_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[1], VOIDmode)")
+ (const_string "load_ext_u")
+ (const_string "load_ext")))
+ (const_string "exts")])])
(define_insn ""
[(set (match_operand:DI 0 "gpc_reg_operand" "=r")
@@ -602,7 +670,15 @@
"@
lbz%U1%X1 %0,%1
rlwinm %0,%1,0,0xff"
- [(set_attr "type" "load,*")])
+ [(set_attr_alternative "type"
+ [(if_then_else
+ (match_test "update_indexed_address_mem (operands[1], VOIDmode)")
+ (const_string "load_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[1], VOIDmode)")
+ (const_string "load_u")
+ (const_string "load")))
+ (const_string "*")])])
(define_insn ""
[(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
@@ -722,7 +798,15 @@
"@
lbz%U1%X1 %0,%1
rlwinm %0,%1,0,0xff"
- [(set_attr "type" "load,*")])
+ [(set_attr_alternative "type"
+ [(if_then_else
+ (match_test "update_indexed_address_mem (operands[1], VOIDmode)")
+ (const_string "load_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[1], VOIDmode)")
+ (const_string "load_u")
+ (const_string "load")))
+ (const_string "*")])])
(define_insn ""
[(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
@@ -848,7 +932,15 @@
"@
lhz%U1%X1 %0,%1
rlwinm %0,%1,0,0xffff"
- [(set_attr "type" "load,*")])
+ [(set_attr_alternative "type"
+ [(if_then_else
+ (match_test "update_indexed_address_mem (operands[1], VOIDmode)")
+ (const_string "load_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[1], VOIDmode)")
+ (const_string "load_u")
+ (const_string "load")))
+ (const_string "*")])])
(define_insn ""
[(set (match_operand:CC 0 "cc_reg_operand" "=x,?y")
@@ -915,7 +1007,15 @@
"@
lha%U1%X1 %0,%1
extsh %0,%1"
- [(set_attr "type" "load_ext,exts")])
+ [(set_attr_alternative "type"
+ [(if_then_else
+ (match_test "update_indexed_address_mem (operands[1], VOIDmode)")
+ (const_string "load_ext_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[1], VOIDmode)")
+ (const_string "load_ext_u")
+ (const_string "load_ext")))
+ (const_string "exts")])])
(define_insn ""
[(set (match_operand:SI 0 "gpc_reg_operand" "=r")
@@ -4498,7 +4598,16 @@
emit_note (NOTE_INSN_DELETED);
DONE;
}
- [(set_attr "type" "fp,fp,fpload")])
+ [(set_attr_alternative "type"
+ [(const_string "fp")
+ (const_string "fp")
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[1], VOIDmode)")
+ (const_string "fpload_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[1], VOIDmode)")
+ (const_string "fpload_u")
+ (const_string "fpload")))])])
(define_expand "truncdfsf2"
[(set (match_operand:SF 0 "gpc_reg_operand" "")
@@ -7723,7 +7832,31 @@
mt%0 %1
mt%0 %1
nop"
- [(set_attr "type" "*,*,load,store,*,*,*,mfjmpr,mtjmpr,*,*")
+ [(set_attr_alternative "type"
+ [(const_string "*")
+ (const_string "*")
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[1], VOIDmode)")
+ (const_string "load_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[1], VOIDmode)")
+ (const_string "load_u")
+ (const_string "load")))
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[0], VOIDmode)")
+ (const_string "store_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[0], VOIDmode)")
+ (const_string "store_u")
+ (const_string "store")))
+ (const_string "*")
+ (const_string "*")
+ (const_string "*")
+ (const_string "mfjmpr")
+ (const_string "mtjmpr")
+ (const_string "*")
+ (const_string "*")])
+
(set_attr "length" "4,4,4,4,4,4,8,4,4,4,4")])
(define_insn "*movsi_internal1_single"
@@ -7745,7 +7878,44 @@
nop
stfs%U0%X0 %1,%0
lfs%U1%X1 %0,%1"
- [(set_attr "type" "*,*,load,store,*,*,*,mfjmpr,mtjmpr,*,*,*,*")
+ [(set_attr_alternative "type"
+ [(const_string "*")
+ (const_string "*")
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[1], VOIDmode)")
+ (const_string "load_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[1], VOIDmode)")
+ (const_string "load_u")
+ (const_string "load")))
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[0], VOIDmode)")
+ (const_string "store_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[0], VOIDmode)")
+ (const_string "store_u")
+ (const_string "store")))
+ (const_string "*")
+ (const_string "*")
+ (const_string "*")
+ (const_string "mfjmpr")
+ (const_string "mtjmpr")
+ (const_string "*")
+ (const_string "*")
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[0], VOIDmode)")
+ (const_string "fpstore_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[0], VOIDmode)")
+ (const_string "fpstore_u")
+ (const_string "fpstore")))
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[1], VOIDmode)")
+ (const_string "fpload_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[1], VOIDmode)")
+ (const_string "fpload_u")
+ (const_string "fpload")))])
(set_attr "length" "4,4,4,4,4,4,8,4,4,4,4,4,4")])
;; Split a load of a large constant into the appropriate two-insn
@@ -7808,7 +7978,26 @@
mf%1 %0
mt%0 %1
nop"
- [(set_attr "type" "*,load,store,*,mfjmpr,mtjmpr,*")])
+ [(set_attr_alternative "type"
+ [(const_string "*")
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[1], VOIDmode)")
+ (const_string "load_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[1], VOIDmode)")
+ (const_string "load_u")
+ (const_string "load")))
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[0], VOIDmode)")
+ (const_string "store_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[0], VOIDmode)")
+ (const_string "store_u")
+ (const_string "store")))
+ (const_string "*")
+ (const_string "mfjmpr")
+ (const_string "mtjmpr")
+ (const_string "*")])])
(define_expand "mov<mode>"
[(set (match_operand:INT 0 "general_operand" "")
@@ -7829,7 +8018,26 @@
mf%1 %0
mt%0 %1
nop"
- [(set_attr "type" "*,load,store,*,mfjmpr,mtjmpr,*")])
+ [(set_attr_alternative "type"
+ [(const_string "*")
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[1], VOIDmode)")
+ (const_string "load_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[1], VOIDmode)")
+ (const_string "load_u")
+ (const_string "load")))
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[0], VOIDmode)")
+ (const_string "store_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[0], VOIDmode)")
+ (const_string "store_u")
+ (const_string "store")))
+ (const_string "*")
+ (const_string "mfjmpr")
+ (const_string "mtjmpr")
+ (const_string "*")])])
;; Here is how to move condition codes around. When we store CC data in
;; an integer register or memory, we store just the high-order 4 bits.
@@ -7857,7 +8065,7 @@
mf%1 %0
mt%0 %1
lwz%U1%X1 %0,%1
- stw%U0%U1 %1,%0"
+ stw%U0%X0 %1,%0"
[(set (attr "type")
(cond [(eq_attr "alternative" "0,3")
(const_string "cr_logical")
@@ -7870,9 +8078,23 @@
(eq_attr "alternative" "9")
(const_string "mtjmpr")
(eq_attr "alternative" "10")
- (const_string "load")
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[1],
+ VOIDmode)")
+ (const_string "load_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[1], VOIDmode)")
+ (const_string "load_u")
+ (const_string "load")))
(eq_attr "alternative" "11")
- (const_string "store")
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[0],
+ VOIDmode)")
+ (const_string "store_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[0], VOIDmode)")
+ (const_string "store_u")
+ (const_string "store")))
(match_test "TARGET_MFCRF")
(const_string "mfcrf")
]
@@ -7884,15 +8106,17 @@
;; can produce floating-point values in fixed-point registers. Unless the
;; value is a simple constant or already in memory, we deal with this by
;; allocating memory and copying the value explicitly via that memory location.
-(define_expand "movsf"
- [(set (match_operand:SF 0 "nonimmediate_operand" "")
- (match_operand:SF 1 "any_operand" ""))]
- ""
- "{ rs6000_emit_move (operands[0], operands[1], SFmode); DONE; }")
+
+;; Move 32-bit binary/decimal floating point
+(define_expand "mov<mode>"
+ [(set (match_operand:FMOVE32 0 "nonimmediate_operand" "")
+ (match_operand:FMOVE32 1 "any_operand" ""))]
+ "<fmove_ok>"
+ "{ rs6000_emit_move (operands[0], operands[1], <MODE>mode); DONE; }")
(define_split
- [(set (match_operand:SF 0 "gpc_reg_operand" "")
- (match_operand:SF 1 "const_double_operand" ""))]
+ [(set (match_operand:FMOVE32 0 "gpc_reg_operand" "")
+ (match_operand:FMOVE32 1 "const_double_operand" ""))]
"reload_completed
&& ((GET_CODE (operands[0]) == REG && REGNO (operands[0]) <= 31)
|| (GET_CODE (operands[0]) == SUBREG
@@ -7905,42 +8129,81 @@
REAL_VALUE_TYPE rv;
REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
- REAL_VALUE_TO_TARGET_SINGLE (rv, l);
+ <real_value_to_target> (rv, l);
if (! TARGET_POWERPC64)
- operands[2] = operand_subword (operands[0], 0, 0, SFmode);
+ operands[2] = operand_subword (operands[0], 0, 0, <MODE>mode);
else
operands[2] = gen_lowpart (SImode, operands[0]);
operands[3] = gen_int_mode (l, SImode);
}")
-(define_insn "*movsf_hardfloat"
- [(set (match_operand:SF 0 "nonimmediate_operand" "=!r,!r,m,f,f,m,*c*l,!r,*h,!r,!r")
- (match_operand:SF 1 "input_operand" "r,m,r,f,m,f,r,h,0,G,Fn"))]
- "(gpc_reg_operand (operands[0], SFmode)
- || gpc_reg_operand (operands[1], SFmode))
+(define_insn "mov<mode>_hardfloat"
+ [(set (match_operand:FMOVE32 0 "nonimmediate_operand" "=!r,!r,m,f,wa,wa,<f32_lr>,<f32_sm>,*c*l,!r,*h,!r,!r")
+ (match_operand:FMOVE32 1 "input_operand" "r,m,r,f,wa,j,<f32_lm>,<f32_sr>,r,h,0,G,Fn"))]
+ "(gpc_reg_operand (operands[0], <MODE>mode)
+ || gpc_reg_operand (operands[1], <MODE>mode))
&& (TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT)"
"@
mr %0,%1
lwz%U1%X1 %0,%1
stw%U0%X0 %1,%0
fmr %0,%1
- lfs%U1%X1 %0,%1
- stfs%U0%X0 %1,%0
+ xxlor %x0,%x1,%x1
+ xxlxor %x0,%x0,%x0
+ <f32_li>
+ <f32_si>
mt%0 %1
mf%1 %0
nop
#
#"
- [(set_attr "type" "*,load,store,fp,fpload,fpstore,mtjmpr,mfjmpr,*,*,*")
- (set_attr "length" "4,4,4,4,4,4,4,4,4,4,8")])
-
-(define_insn "*movsf_softfloat"
- [(set (match_operand:SF 0 "nonimmediate_operand" "=r,cl,r,r,m,r,r,r,r,*h")
- (match_operand:SF 1 "input_operand" "r,r,h,m,r,I,L,G,Fn,0"))]
- "(gpc_reg_operand (operands[0], SFmode)
- || gpc_reg_operand (operands[1], SFmode))
+ [(set_attr_alternative "type"
+ [(const_string "*")
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[1], VOIDmode)")
+ (const_string "load_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[1], VOIDmode)")
+ (const_string "load_u")
+ (const_string "load")))
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[0], VOIDmode)")
+ (const_string "store_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[0], VOIDmode)")
+ (const_string "store_u")
+ (const_string "store")))
+ (const_string "fp")
+ (const_string "vecsimple")
+ (const_string "vecsimple")
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[1], VOIDmode)")
+ (const_string "fpload_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[1], VOIDmode)")
+ (const_string "fpload_u")
+ (const_string "fpload")))
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[0], VOIDmode)")
+ (const_string "fpstore_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[0], VOIDmode)")
+ (const_string "fpstore_u")
+ (const_string "fpstore")))
+ (const_string "mtjmpr")
+ (const_string "mfjmpr")
+ (const_string "*")
+ (const_string "*")
+ (const_string "*")])
+ (set_attr "length" "4,4,4,4,4,4,4,4,4,4,4,4,8")])
+
+(define_insn "*mov<mode>_softfloat"
+ [(set (match_operand:FMOVE32 0 "nonimmediate_operand" "=r,cl,r,r,m,r,r,r,r,*h")
+ (match_operand:FMOVE32 1 "input_operand" "r, r,h,m,r,I,L,G,Fn,0"))]
+ "(gpc_reg_operand (operands[0], <MODE>mode)
+ || gpc_reg_operand (operands[1], <MODE>mode))
&& (TARGET_SOFT_FLOAT || !TARGET_FPRS)"
"@
mr %0,%1
@@ -7953,19 +8216,42 @@
#
#
nop"
- [(set_attr "type" "*,mtjmpr,mfjmpr,load,store,*,*,*,*,*")
+ [(set_attr_alternative "type"
+ [(const_string "*")
+ (const_string "mtjmpr")
+ (const_string "mfjmpr")
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[1], VOIDmode)")
+ (const_string "load_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[1], VOIDmode)")
+ (const_string "load_u")
+ (const_string "load")))
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[0], VOIDmode)")
+ (const_string "store_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[0], VOIDmode)")
+ (const_string "store_u")
+ (const_string "store")))
+ (const_string "*")
+ (const_string "*")
+ (const_string "*")
+ (const_string "*")
+ (const_string "*")])
(set_attr "length" "4,4,4,4,4,4,4,4,8,4")])
-(define_expand "movdf"
- [(set (match_operand:DF 0 "nonimmediate_operand" "")
- (match_operand:DF 1 "any_operand" ""))]
+;; Move 64-bit binary/decimal floating point
+(define_expand "mov<mode>"
+ [(set (match_operand:FMOVE64 0 "nonimmediate_operand" "")
+ (match_operand:FMOVE64 1 "any_operand" ""))]
""
- "{ rs6000_emit_move (operands[0], operands[1], DFmode); DONE; }")
+ "{ rs6000_emit_move (operands[0], operands[1], <MODE>mode); DONE; }")
(define_split
- [(set (match_operand:DF 0 "gpc_reg_operand" "")
- (match_operand:DF 1 "const_int_operand" ""))]
+ [(set (match_operand:FMOVE64 0 "gpc_reg_operand" "")
+ (match_operand:FMOVE64 1 "const_int_operand" ""))]
"! TARGET_POWERPC64 && reload_completed
&& ((GET_CODE (operands[0]) == REG && REGNO (operands[0]) <= 31)
|| (GET_CODE (operands[0]) == SUBREG
@@ -7978,8 +8264,8 @@
int endian = (WORDS_BIG_ENDIAN == 0);
HOST_WIDE_INT value = INTVAL (operands[1]);
- operands[2] = operand_subword (operands[0], endian, 0, DFmode);
- operands[3] = operand_subword (operands[0], 1 - endian, 0, DFmode);
+ operands[2] = operand_subword (operands[0], endian, 0, <MODE>mode);
+ operands[3] = operand_subword (operands[0], 1 - endian, 0, <MODE>mode);
#if HOST_BITS_PER_WIDE_INT == 32
operands[4] = (value & 0x80000000) ? constm1_rtx : const0_rtx;
#else
@@ -7989,8 +8275,8 @@
}")
(define_split
- [(set (match_operand:DF 0 "gpc_reg_operand" "")
- (match_operand:DF 1 "const_double_operand" ""))]
+ [(set (match_operand:FMOVE64 0 "gpc_reg_operand" "")
+ (match_operand:FMOVE64 1 "const_double_operand" ""))]
"! TARGET_POWERPC64 && reload_completed
&& ((GET_CODE (operands[0]) == REG && REGNO (operands[0]) <= 31)
|| (GET_CODE (operands[0]) == SUBREG
@@ -8005,17 +8291,17 @@
REAL_VALUE_TYPE rv;
REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
- REAL_VALUE_TO_TARGET_DOUBLE (rv, l);
+ <real_value_to_target> (rv, l);
- operands[2] = operand_subword (operands[0], endian, 0, DFmode);
- operands[3] = operand_subword (operands[0], 1 - endian, 0, DFmode);
+ operands[2] = operand_subword (operands[0], endian, 0, <MODE>mode);
+ operands[3] = operand_subword (operands[0], 1 - endian, 0, <MODE>mode);
operands[4] = gen_int_mode (l[endian], SImode);
operands[5] = gen_int_mode (l[1 - endian], SImode);
}")
(define_split
- [(set (match_operand:DF 0 "gpc_reg_operand" "")
- (match_operand:DF 1 "const_double_operand" ""))]
+ [(set (match_operand:FMOVE64 0 "gpc_reg_operand" "")
+ (match_operand:FMOVE64 1 "const_double_operand" ""))]
"TARGET_POWERPC64 && reload_completed
&& ((GET_CODE (operands[0]) == REG && REGNO (operands[0]) <= 31)
|| (GET_CODE (operands[0]) == SUBREG
@@ -8032,7 +8318,7 @@
#endif
REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
- REAL_VALUE_TO_TARGET_DOUBLE (rv, l);
+ <real_value_to_target> (rv, l);
operands[2] = gen_lowpart (DImode, operands[0]);
/* HIGHPART is lower memory address when WORDS_BIG_ENDIAN. */
@@ -8057,12 +8343,12 @@
;; since the D-form version of the memory instructions does not need a GPR for
;; reloading.
-(define_insn "*movdf_hardfloat32"
- [(set (match_operand:DF 0 "nonimmediate_operand" "=m,d,d,ws,?wa,Z,?Z,ws,?wa,wa,Y,r,!r,!r,!r,!r")
- (match_operand:DF 1 "input_operand" "d,m,d,Z,Z,ws,wa,ws,wa,j,r,Y,r,G,H,F"))]
+(define_insn "*mov<mode>_hardfloat32"
+ [(set (match_operand:FMOVE64 0 "nonimmediate_operand" "=m,d,d,ws,?wa,Z,?Z,ws,?wa,wa,Y,r,!r,!r,!r,!r")
+ (match_operand:FMOVE64 1 "input_operand" "d,m,d,Z,Z,ws,wa,ws,wa,j,r,Y,r,G,H,F"))]
"! TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
- && (gpc_reg_operand (operands[0], DFmode)
- || gpc_reg_operand (operands[1], DFmode))"
+ && (gpc_reg_operand (operands[0], <MODE>mode)
+ || gpc_reg_operand (operands[1], <MODE>mode))"
"@
stfd%U0%X0 %1,%0
lfd%U1%X1 %0,%1
@@ -8080,93 +8366,73 @@
#
#
#"
- [(set_attr "type" "fpstore,fpload,fp,fpload,fpload,fpstore,fpstore,vecsimple,vecsimple,vecsimple,store,load,two,fp,fp,*")
+ [(set_attr_alternative "type"
+ [(if_then_else
+ (match_test "update_indexed_address_mem (operands[0], VOIDmode)")
+ (const_string "fpstore_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[0], VOIDmode)")
+ (const_string "fpstore_u")
+ (const_string "fpstore")))
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[1], VOIDmode)")
+ (const_string "fpload_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[1], VOIDmode)")
+ (const_string "fpload_u")
+ (const_string "fpload")))
+ (const_string "fp")
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[1], VOIDmode)")
+ (const_string "fpload_ux")
+ (const_string "fpload"))
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[1], VOIDmode)")
+ (const_string "fpload_ux")
+ (const_string "fpload"))
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[0], VOIDmode)")
+ (const_string "fpstore_ux")
+ (const_string "fpstore"))
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[0], VOIDmode)")
+ (const_string "fpstore_ux")
+ (const_string "fpstore"))
+ (const_string "vecsimple")
+ (const_string "vecsimple")
+ (const_string "vecsimple")
+ (const_string "store")
+ (const_string "load")
+ (const_string "two")
+ (const_string "fp")
+ (const_string "fp")
+ (const_string "*")])
(set_attr "length" "4,4,4,4,4,4,4,4,4,4,8,8,8,8,12,16")])
-(define_insn "*movdf_softfloat32"
- [(set (match_operand:DF 0 "nonimmediate_operand" "=Y,r,r,r,r,r")
- (match_operand:DF 1 "input_operand" "r,Y,r,G,H,F"))]
+(define_insn "*mov<mode>_softfloat32"
+ [(set (match_operand:FMOVE64 0 "nonimmediate_operand" "=Y,r,r,r,r,r")
+ (match_operand:FMOVE64 1 "input_operand" "r,Y,r,G,H,F"))]
"! TARGET_POWERPC64
&& ((TARGET_FPRS && TARGET_SINGLE_FLOAT)
|| TARGET_SOFT_FLOAT || TARGET_E500_SINGLE)
- && (gpc_reg_operand (operands[0], DFmode)
- || gpc_reg_operand (operands[1], DFmode))"
+ && (gpc_reg_operand (operands[0], <MODE>mode)
+ || gpc_reg_operand (operands[1], <MODE>mode))"
"#"
[(set_attr "type" "store,load,two,*,*,*")
(set_attr "length" "8,8,8,8,12,16")])
-;; Reload patterns to support gpr load/store with misaligned mem.
-;; and multiple gpr load/store at offset >= 0xfffc
-(define_expand "reload_<mode>_store"
- [(parallel [(match_operand 0 "memory_operand" "=m")
- (match_operand 1 "gpc_reg_operand" "r")
- (match_operand:GPR 2 "register_operand" "=&b")])]
- ""
-{
- rs6000_secondary_reload_gpr (operands[1], operands[0], operands[2], true);
- DONE;
-})
-
-(define_expand "reload_<mode>_load"
- [(parallel [(match_operand 0 "gpc_reg_operand" "=r")
- (match_operand 1 "memory_operand" "m")
- (match_operand:GPR 2 "register_operand" "=b")])]
- ""
-{
- rs6000_secondary_reload_gpr (operands[0], operands[1], operands[2], false);
- DONE;
-})
-
; ld/std require word-aligned displacements -> 'Y' constraint.
; List Y->r and r->Y before r->r for reload.
-(define_insn "*movdf_hardfloat64_mfpgpr"
- [(set (match_operand:DF 0 "nonimmediate_operand" "=Y,r,!r,ws,?wa,ws,?wa,Z,?Z,m,d,d,wa,*c*l,!r,*h,!r,!r,!r,r,d")
- (match_operand:DF 1 "input_operand" "r,Y,r,ws,?wa,Z,Z,ws,wa,d,m,d,j,r,h,0,G,H,F,d,r"))]
- "TARGET_POWERPC64 && TARGET_MFPGPR && TARGET_HARD_FLOAT && TARGET_FPRS
- && TARGET_DOUBLE_FLOAT
- && (gpc_reg_operand (operands[0], DFmode)
- || gpc_reg_operand (operands[1], DFmode))"
+(define_insn "*mov<mode>_hardfloat64"
+ [(set (match_operand:FMOVE64 0 "nonimmediate_operand" "=m,d,d,ws,?wa,Z,?Z,ws,?wa,wa,Y,r,!r,*c*l,!r,*h,!r,!r,!r,r,wg")
+ (match_operand:FMOVE64 1 "input_operand" "d,m,d,Z,Z,ws,wa,ws,wa,j,r,Y,r,r,h,0,G,H,F,wg,r"))]
+ "TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
+ && (gpc_reg_operand (operands[0], <MODE>mode)
+ || gpc_reg_operand (operands[1], <MODE>mode))"
"@
- std%U0%X0 %1,%0
- ld%U1%X1 %0,%1
- mr %0,%1
- xxlor %x0,%x1,%x1
- xxlor %x0,%x1,%x1
- lxsd%U1x %x0,%y1
- lxsd%U1x %x0,%y1
- stxsd%U0x %x1,%y0
- stxsd%U0x %x1,%y0
stfd%U0%X0 %1,%0
lfd%U1%X1 %0,%1
fmr %0,%1
- xxlxor %x0,%x0,%x0
- mt%0 %1
- mf%1 %0
- nop
- #
- #
- #
- mftgpr %0,%1
- mffgpr %0,%1"
- [(set_attr "type" "store,load,*,fp,fp,fpload,fpload,fpstore,fpstore,fpstore,fpload,fp,vecsimple,mtjmpr,mfjmpr,*,*,*,*,mftgpr,mffgpr")
- (set_attr "length" "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,8,12,16,4,4")])
-
-; ld/std require word-aligned displacements -> 'Y' constraint.
-; List Y->r and r->Y before r->r for reload.
-(define_insn "*movdf_hardfloat64"
- [(set (match_operand:DF 0 "nonimmediate_operand" "=m,d,d,Y,r,!r,ws,?wa,Z,?Z,ws,?wa,wa,*c*l,!r,*h,!r,!r,!r")
- (match_operand:DF 1 "input_operand" "d,m,d,r,Y,r,Z,Z,ws,wa,ws,wa,j,r,h,0,G,H,F"))]
- "TARGET_POWERPC64 && !TARGET_MFPGPR && TARGET_HARD_FLOAT && TARGET_FPRS
- && TARGET_DOUBLE_FLOAT
- && (gpc_reg_operand (operands[0], DFmode)
- || gpc_reg_operand (operands[1], DFmode))"
- "@
- stfd%U0%X0 %1,%0
- lfd%U1%X1 %0,%1
- fmr %0,%1
- std%U0%X0 %1,%0
- ld%U1%X1 %0,%1
- mr %0,%1
lxsd%U1x %x0,%y1
lxsd%U1x %x0,%y1
stxsd%U0x %x1,%y0
@@ -8174,21 +8440,83 @@
xxlor %x0,%x1,%x1
xxlor %x0,%x1,%x1
xxlxor %x0,%x0,%x0
+ std%U0%X0 %1,%0
+ ld%U1%X1 %0,%1
+ mr %0,%1
mt%0 %1
mf%1 %0
nop
#
#
- #"
- [(set_attr "type" "fpstore,fpload,fp,store,load,*,fpload,fpload,fpstore,fpstore,vecsimple,vecsimple,vecsimple,mtjmpr,mfjmpr,*,*,*,*")
- (set_attr "length" "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,8,12,16")])
+ #
+ mftgpr %0,%1
+ mffgpr %0,%1"
+ [(set_attr_alternative "type"
+ [(if_then_else
+ (match_test "update_indexed_address_mem (operands[0], VOIDmode)")
+ (const_string "fpstore_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[0], VOIDmode)")
+ (const_string "fpstore_u")
+ (const_string "fpstore")))
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[1], VOIDmode)")
+ (const_string "fpload_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[1], VOIDmode)")
+ (const_string "fpload_u")
+ (const_string "fpload")))
+ (const_string "fp")
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[1], VOIDmode)")
+ (const_string "fpload_ux")
+ (const_string "fpload"))
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[1], VOIDmode)")
+ (const_string "fpload_ux")
+ (const_string "fpload"))
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[0], VOIDmode)")
+ (const_string "fpstore_ux")
+ (const_string "fpstore"))
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[0], VOIDmode)")
+ (const_string "fpstore_ux")
+ (const_string "fpstore"))
+ (const_string "vecsimple")
+ (const_string "vecsimple")
+ (const_string "vecsimple")
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[0], VOIDmode)")
+ (const_string "store_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[0], VOIDmode)")
+ (const_string "store_u")
+ (const_string "store")))
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[1], VOIDmode)")
+ (const_string "load_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[1], VOIDmode)")
+ (const_string "load_u")
+ (const_string "load")))
+ (const_string "*")
+ (const_string "mtjmpr")
+ (const_string "mfjmpr")
+ (const_string "*")
+ (const_string "*")
+ (const_string "*")
+ (const_string "*")
+ (const_string "mftgpr")
+ (const_string "mffgpr")])
+ (set_attr "length" "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,8,12,16,4,4")])
-(define_insn "*movdf_softfloat64"
- [(set (match_operand:DF 0 "nonimmediate_operand" "=Y,r,r,cl,r,r,r,r,*h")
- (match_operand:DF 1 "input_operand" "r,Y,r,r,h,G,H,F,0"))]
+(define_insn "*mov<mode>_softfloat64"
+ [(set (match_operand:FMOVE64 0 "nonimmediate_operand" "=Y,r,r,cl,r,r,r,r,*h")
+ (match_operand:FMOVE64 1 "input_operand" "r,Y,r,r,h,G,H,F,0"))]
"TARGET_POWERPC64 && (TARGET_SOFT_FLOAT || !TARGET_FPRS)
- && (gpc_reg_operand (operands[0], DFmode)
- || gpc_reg_operand (operands[1], DFmode))"
+ && (gpc_reg_operand (operands[0], <MODE>mode)
+ || gpc_reg_operand (operands[1], <MODE>mode))"
"@
std%U0%X0 %1,%0
ld%U1%X1 %0,%1
@@ -8199,38 +8527,57 @@
#
#
nop"
- [(set_attr "type" "store,load,*,mtjmpr,mfjmpr,*,*,*,*")
+ [(set_attr_alternative "type"
+ [(if_then_else
+ (match_test "update_indexed_address_mem (operands[0], VOIDmode)")
+ (const_string "store_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[0], VOIDmode)")
+ (const_string "store_u")
+ (const_string "store")))
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[1], VOIDmode)")
+ (const_string "load_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[1], VOIDmode)")
+ (const_string "load_u")
+ (const_string "load")))
+ (const_string "*")
+ (const_string "mtjmpr")
+ (const_string "mfjmpr")
+ (const_string "*")
+ (const_string "*")
+ (const_string "*")
+ (const_string "*")])
(set_attr "length" "4,4,4,4,4,8,12,16,4")])
-(define_expand "movtf"
- [(set (match_operand:TF 0 "general_operand" "")
- (match_operand:TF 1 "any_operand" ""))]
- "!TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128"
- "{ rs6000_emit_move (operands[0], operands[1], TFmode); DONE; }")
+(define_expand "mov<mode>"
+ [(set (match_operand:FMOVE128 0 "general_operand" "")
+ (match_operand:FMOVE128 1 "any_operand" ""))]
+ ""
+ "{ rs6000_emit_move (operands[0], operands[1], <MODE>mode); DONE; }")
;; It's important to list Y->r and r->Y before r->r because otherwise
;; reload, given m->r, will try to pick r->r and reload it, which
;; doesn't make progress.
-(define_insn_and_split "*movtf_internal"
- [(set (match_operand:TF 0 "nonimmediate_operand" "=m,d,d,Y,r,r")
- (match_operand:TF 1 "input_operand" "d,m,d,r,YGHF,r"))]
- "!TARGET_IEEEQUAD
- && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128
- && (gpc_reg_operand (operands[0], TFmode)
- || gpc_reg_operand (operands[1], TFmode))"
+(define_insn_and_split "*mov<mode>_internal"
+ [(set (match_operand:FMOVE128 0 "nonimmediate_operand" "=m,d,d,Y,r,r")
+ (match_operand:FMOVE128 1 "input_operand" "d,m,d,r,YGHF,r"))]
+ "TARGET_HARD_FLOAT && TARGET_FPRS
+ && (gpc_reg_operand (operands[0], <MODE>mode)
+ || gpc_reg_operand (operands[1], <MODE>mode))"
"#"
"&& reload_completed"
[(pc)]
{ rs6000_split_multireg_move (operands[0], operands[1]); DONE; }
[(set_attr "length" "8,8,8,20,20,16")])
-(define_insn_and_split "*movtf_softfloat"
- [(set (match_operand:TF 0 "rs6000_nonimmediate_operand" "=Y,r,r")
- (match_operand:TF 1 "input_operand" "r,YGHF,r"))]
- "!TARGET_IEEEQUAD
- && (TARGET_SOFT_FLOAT || !TARGET_FPRS) && TARGET_LONG_DOUBLE_128
- && (gpc_reg_operand (operands[0], TFmode)
- || gpc_reg_operand (operands[1], TFmode))"
+(define_insn_and_split "*mov<mode>_softfloat"
+ [(set (match_operand:FMOVE128 0 "rs6000_nonimmediate_operand" "=Y,r,r")
+ (match_operand:FMOVE128 1 "input_operand" "r,YGHF,r"))]
+ "(TARGET_SOFT_FLOAT || !TARGET_FPRS)
+ && (gpc_reg_operand (operands[0], <MODE>mode)
+ || gpc_reg_operand (operands[1], <MODE>mode))"
"#"
"&& reload_completed"
[(pc)]
@@ -8515,6 +8862,33 @@
operands[6] = simplify_gen_subreg (DFmode, operands[0], TFmode, lo_word);
}")
+;; Reload helper functions used by rs6000_secondary_reload. The patterns all
+;; must have 3 arguments, and scratch register constraint must be a single
+;; constraint.
+
+;; Reload patterns to support gpr load/store with misaligned mem.
+;; and multiple gpr load/store at offset >= 0xfffc
+(define_expand "reload_<mode>_store"
+ [(parallel [(match_operand 0 "memory_operand" "=m")
+ (match_operand 1 "gpc_reg_operand" "r")
+ (match_operand:GPR 2 "register_operand" "=&b")])]
+ ""
+{
+ rs6000_secondary_reload_gpr (operands[1], operands[0], operands[2], true);
+ DONE;
+})
+
+(define_expand "reload_<mode>_load"
+ [(parallel [(match_operand 0 "gpc_reg_operand" "=r")
+ (match_operand 1 "memory_operand" "m")
+ (match_operand:GPR 2 "register_operand" "=b")])]
+ ""
+{
+ rs6000_secondary_reload_gpr (operands[0], operands[1], operands[2], false);
+ DONE;
+})
+
+
;; Next come the multi-word integer load and store and the load and store
;; multiple insns.
@@ -8537,7 +8911,27 @@
fmr %0,%1
#
xxlxor %x0,%x0,%x0"
- [(set_attr "type" "store,load,*,fpstore,fpload,fp,*,vecsimple")])
+ [(set_attr_alternative "type"
+ [(const_string "store")
+ (const_string "load")
+ (const_string "*")
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[0], VOIDmode)")
+ (const_string "fpstore_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[0], VOIDmode)")
+ (const_string "fpstore_u")
+ (const_string "fpstore")))
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[1], VOIDmode)")
+ (const_string "fpload_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[1], VOIDmode)")
+ (const_string "fpload_u")
+ (const_string "fpload")))
+ (const_string "fp")
+ (const_string "*")
+ (const_string "vecsimple")])])
(define_split
[(set (match_operand:DI 0 "gpc_reg_operand" "")
@@ -8569,10 +8963,10 @@
[(pc)]
{ rs6000_split_multireg_move (operands[0], operands[1]); DONE; })
-(define_insn "*movdi_mfpgpr"
- [(set (match_operand:DI 0 "nonimmediate_operand" "=Y,r,r,r,r,r,?m,?*d,?*d,r,*h,*h,r,?*d")
- (match_operand:DI 1 "input_operand" "r,Y,r,I,L,nF,d,m,d,*h,r,0,*d,r"))]
- "TARGET_POWERPC64 && TARGET_MFPGPR && TARGET_HARD_FLOAT && TARGET_FPRS
+(define_insn "*movdi_internal64"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=Y,r,r,r,r,r,?m,?*d,?*d,?Z,?wa,?wa,r,*h,*h,?wa,r,?*wg")
+ (match_operand:DI 1 "input_operand" "r,Y,r,I,L,nF,d,m,d,wa,Z,wa,*h,r,0,O,*wg,r"))]
+ "TARGET_POWERPC64
&& (gpc_reg_operand (operands[0], DImode)
|| gpc_reg_operand (operands[1], DImode))"
"@
@@ -8585,36 +8979,65 @@
stfd%U0%X0 %1,%0
lfd%U1%X1 %0,%1
fmr %0,%1
+ stxsd%U0x %x1,%y0
+ lxsd%U1x %x0,%y1
+ xxlor %x0,%x1,%x1
mf%1 %0
mt%0 %1
nop
+ xxlxor %x0,%x0,%x0
mftgpr %0,%1
mffgpr %0,%1"
- [(set_attr "type" "store,load,*,*,*,*,fpstore,fpload,fp,mfjmpr,mtjmpr,*,mftgpr,mffgpr")
- (set_attr "length" "4,4,4,4,4,20,4,4,4,4,4,4,4,4")])
-
-(define_insn "*movdi_internal64"
- [(set (match_operand:DI 0 "nonimmediate_operand" "=Y,r,r,r,r,r,?m,?*d,?*d,r,*h,*h,?wa")
- (match_operand:DI 1 "input_operand" "r,Y,r,I,L,nF,d,m,d,*h,r,0,O"))]
- "TARGET_POWERPC64 && (!TARGET_MFPGPR || !TARGET_HARD_FLOAT || !TARGET_FPRS)
- && (gpc_reg_operand (operands[0], DImode)
- || gpc_reg_operand (operands[1], DImode))"
- "@
- std%U0%X0 %1,%0
- ld%U1%X1 %0,%1
- mr %0,%1
- li %0,%1
- lis %0,%v1
- #
- stfd%U0%X0 %1,%0
- lfd%U1%X1 %0,%1
- fmr %0,%1
- mf%1 %0
- mt%0 %1
- nop
- xxlxor %x0,%x0,%x0"
- [(set_attr "type" "store,load,*,*,*,*,fpstore,fpload,fp,mfjmpr,mtjmpr,*,vecsimple")
- (set_attr "length" "4,4,4,4,4,20,4,4,4,4,4,4,4")])
+ [(set_attr_alternative "type"
+ [(if_then_else
+ (match_test "update_indexed_address_mem (operands[0], VOIDmode)")
+ (const_string "store_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[0], VOIDmode)")
+ (const_string "store_u")
+ (const_string "store")))
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[1], VOIDmode)")
+ (const_string "load_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[1], VOIDmode)")
+ (const_string "load_u")
+ (const_string "load")))
+ (const_string "*")
+ (const_string "*")
+ (const_string "*")
+ (const_string "*")
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[0], VOIDmode)")
+ (const_string "fpstore_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[0], VOIDmode)")
+ (const_string "fpstore_u")
+ (const_string "fpstore")))
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[1], VOIDmode)")
+ (const_string "fpload_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[1], VOIDmode)")
+ (const_string "fpload_u")
+ (const_string "fpload")))
+ (const_string "fp")
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[0], VOIDmode)")
+ (const_string "fpstore_ux")
+ (const_string "fpstore"))
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[1], VOIDmode)")
+ (const_string "fpload_ux")
+ (const_string "fpload"))
+ (const_string "vecsimple")
+ (const_string "mfjmpr")
+ (const_string "mtjmpr")
+ (const_string "*")
+ (const_string "vecsimple")
+ (const_string "mftgpr")
+ (const_string "mffgpr")])
+ (set_attr "length" "4,4,4,4,4,20,4,4,4,4,4,4,4,4,4,4,4,4")])
;; immediate value valid for a single instruction hiding in a const_double
(define_insn ""
@@ -8677,14 +9100,16 @@
FAIL;
}")
-;; TImode is similar, except that we usually want to compute the address into
-;; a register and use lsi/stsi (the exception is during reload).
+;; TImode/PTImode is similar, except that we usually want to compute the
+;; address into a register and use lsi/stsi (the exception is during reload).
-(define_insn "*movti_string"
- [(set (match_operand:TI 0 "reg_or_mem_operand" "=Q,Y,????r,????r,????r,r")
- (match_operand:TI 1 "input_operand" "r,r,Q,Y,r,n"))]
+(define_insn "*mov<mode>_string"
+ [(set (match_operand:TI2 0 "reg_or_mem_operand" "=Q,Y,????r,????r,????r,r")
+ (match_operand:TI2 1 "input_operand" "r,r,Q,Y,r,n"))]
"! TARGET_POWERPC64
- && (gpc_reg_operand (operands[0], TImode) || gpc_reg_operand (operands[1], TImode))"
+ && (<MODE>mode != TImode || VECTOR_MEM_NONE_P (TImode))
+ && (gpc_reg_operand (operands[0], <MODE>mode)
+ || gpc_reg_operand (operands[1], <MODE>mode))"
"*
{
switch (which_alternative)
@@ -8714,27 +9139,28 @@
(const_string "always")
(const_string "conditional")))])
-(define_insn "*movti_ppc64"
- [(set (match_operand:TI 0 "nonimmediate_operand" "=Y,r,r")
- (match_operand:TI 1 "input_operand" "r,Y,r"))]
- "(TARGET_POWERPC64 && (gpc_reg_operand (operands[0], TImode)
- || gpc_reg_operand (operands[1], TImode)))
- && VECTOR_MEM_NONE_P (TImode)"
+(define_insn "*mov<mode>_ppc64"
+ [(set (match_operand:TI2 0 "nonimmediate_operand" "=Y,r,r")
+ (match_operand:TI2 1 "input_operand" "r,Y,r"))]
+ "(TARGET_POWERPC64
+ && (<MODE>mode != TImode || VECTOR_MEM_NONE_P (TImode))
+ && (gpc_reg_operand (operands[0], <MODE>mode)
+ || gpc_reg_operand (operands[1], <MODE>mode)))"
"#"
[(set_attr "type" "store,load,*")])
(define_split
- [(set (match_operand:TI 0 "gpc_reg_operand" "")
- (match_operand:TI 1 "const_double_operand" ""))]
- "TARGET_POWERPC64 && VECTOR_MEM_NONE_P (TImode)"
+ [(set (match_operand:TI2 0 "gpc_reg_operand" "")
+ (match_operand:TI2 1 "const_double_operand" ""))]
+ "TARGET_POWERPC64"
[(set (match_dup 2) (match_dup 4))
(set (match_dup 3) (match_dup 5))]
"
{
operands[2] = operand_subword_force (operands[0], WORDS_BIG_ENDIAN == 0,
- TImode);
+ <MODE>mode);
operands[3] = operand_subword_force (operands[0], WORDS_BIG_ENDIAN != 0,
- TImode);
+ <MODE>mode);
if (GET_CODE (operands[1]) == CONST_DOUBLE)
{
operands[4] = GEN_INT (CONST_DOUBLE_HIGH (operands[1]));
@@ -8750,9 +9176,9 @@
}")
(define_split
- [(set (match_operand:TI 0 "nonimmediate_operand" "")
- (match_operand:TI 1 "input_operand" ""))]
- "reload_completed && VECTOR_MEM_NONE_P (TImode)
+ [(set (match_operand:TI2 0 "nonimmediate_operand" "")
+ (match_operand:TI2 1 "input_operand" ""))]
+ "reload_completed
&& gpr_or_gpr_p (operands[0], operands[1])"
[(pc)]
{ rs6000_split_multireg_move (operands[0], operands[1]); DONE; })
@@ -11252,7 +11678,14 @@
operands[1] = gen_rtx_REG (Pmode, 0);
return "st<wd>%U0%X0 %1,%0";
}
- [(set_attr "type" "store")
+ [(set (attr "type")
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[0], VOIDmode)")
+ (const_string "store_ux")
+ (if_then_else
+ (match_test "update_address_mem (operands[0], VOIDmode)")
+ (const_string "store_u")
+ (const_string "store"))))
(set_attr "length" "4")])
(define_insn "probe_stack_range<P:mode>"
diff --git a/gcc/config/rs6000/rs6000.opt b/gcc/config/rs6000/rs6000.opt
index 8e3cea12185..17b77629fa1 100644
--- a/gcc/config/rs6000/rs6000.opt
+++ b/gcc/config/rs6000/rs6000.opt
@@ -514,3 +514,7 @@ Use/do not use r11 to hold the static link in calls to functions via pointers.
msave-toc-indirect
Target Report Var(TARGET_SAVE_TOC_INDIRECT) Save
Control whether we save the TOC in the prologue for indirect calls or generate the save inline
+
+mvsx-timode
+Target Undocumented Mask(VSX_TIMODE) Var(rs6000_isa_flags)
+; Allow/disallow TImode in VSX registers
diff --git a/gcc/config/rs6000/vector.md b/gcc/config/rs6000/vector.md
index 5a6e1fb3026..c1d00ca2a9b 100644
--- a/gcc/config/rs6000/vector.md
+++ b/gcc/config/rs6000/vector.md
@@ -54,7 +54,7 @@
(define_mode_iterator VEC_64 [V2DI V2DF])
;; Vector reload iterator
-(define_mode_iterator VEC_R [V16QI V8HI V4SI V2DI V4SF V2DF DF TI])
+(define_mode_iterator VEC_R [V16QI V8HI V4SI V2DI V4SF V2DF SF SD SI DF DD DI TI])
;; Base type from vector mode
(define_mode_attr VEC_base [(V16QI "QI")
@@ -249,7 +249,7 @@
[(set (match_operand:VEC_F 0 "vfloat_operand" "")
(mult:VEC_F (match_operand:VEC_F 1 "vfloat_operand" "")
(match_operand:VEC_F 2 "vfloat_operand" "")))]
- "VECTOR_UNIT_VSX_P (<MODE>mode) || VECTOR_UNIT_ALTIVEC_P (<MODE>mode)"
+ "VECTOR_UNIT_ALTIVEC_OR_VSX_P (<MODE>mode)"
{
if (<MODE>mode == V4SFmode && VECTOR_UNIT_ALTIVEC_P (<MODE>mode))
{
@@ -395,7 +395,7 @@
(match_operand:VEC_I 5 "vint_operand" "")])
(match_operand:VEC_I 1 "vint_operand" "")
(match_operand:VEC_I 2 "vint_operand" "")))]
- "VECTOR_UNIT_ALTIVEC_P (<MODE>mode)"
+ "VECTOR_UNIT_ALTIVEC_OR_VSX_P (<MODE>mode)"
"
{
if (rs6000_emit_vector_cond_expr (operands[0], operands[1], operands[2],
@@ -451,7 +451,7 @@
(match_operand:VEC_I 5 "vint_operand" "")])
(match_operand:VEC_I 1 "vint_operand" "")
(match_operand:VEC_I 2 "vint_operand" "")))]
- "VECTOR_UNIT_ALTIVEC_P (<MODE>mode)"
+ "VECTOR_UNIT_ALTIVEC_OR_VSX_P (<MODE>mode)"
"
{
if (rs6000_emit_vector_cond_expr (operands[0], operands[1], operands[2],
@@ -505,14 +505,14 @@
[(set (match_operand:VEC_I 0 "vint_operand" "")
(gtu:VEC_I (match_operand:VEC_I 1 "vint_operand" "")
(match_operand:VEC_I 2 "vint_operand" "")))]
- "VECTOR_UNIT_ALTIVEC_P (<MODE>mode)"
+ "VECTOR_UNIT_ALTIVEC_OR_VSX_P (<MODE>mode)"
"")
(define_expand "vector_geu<mode>"
[(set (match_operand:VEC_I 0 "vint_operand" "")
(geu:VEC_I (match_operand:VEC_I 1 "vint_operand" "")
(match_operand:VEC_I 2 "vint_operand" "")))]
- "VECTOR_UNIT_ALTIVEC_P (<MODE>mode)"
+ "VECTOR_UNIT_ALTIVEC_OR_VSX_P (<MODE>mode)"
"")
(define_insn_and_split "*vector_uneq<mode>"
@@ -709,45 +709,55 @@
;; Vector logical instructions
+;; Do not support TImode logical instructions on 32-bit at present, because the
+;; compiler will see that we have a TImode and when it wanted DImode, and
+;; convert the DImode to TImode, store it on the stack, and load it in a VSX
+;; register.
(define_expand "xor<mode>3"
[(set (match_operand:VEC_L 0 "vlogical_operand" "")
(xor:VEC_L (match_operand:VEC_L 1 "vlogical_operand" "")
(match_operand:VEC_L 2 "vlogical_operand" "")))]
- "VECTOR_MEM_ALTIVEC_OR_VSX_P (<MODE>mode)"
+ "VECTOR_MEM_ALTIVEC_OR_VSX_P (<MODE>mode)
+ && (<MODE>mode != TImode || TARGET_POWERPC64)"
"")
(define_expand "ior<mode>3"
[(set (match_operand:VEC_L 0 "vlogical_operand" "")
(ior:VEC_L (match_operand:VEC_L 1 "vlogical_operand" "")
(match_operand:VEC_L 2 "vlogical_operand" "")))]
- "VECTOR_MEM_ALTIVEC_OR_VSX_P (<MODE>mode)"
+ "VECTOR_MEM_ALTIVEC_OR_VSX_P (<MODE>mode)
+ && (<MODE>mode != TImode || TARGET_POWERPC64)"
"")
(define_expand "and<mode>3"
[(set (match_operand:VEC_L 0 "vlogical_operand" "")
(and:VEC_L (match_operand:VEC_L 1 "vlogical_operand" "")
(match_operand:VEC_L 2 "vlogical_operand" "")))]
- "VECTOR_MEM_ALTIVEC_OR_VSX_P (<MODE>mode)"
+ "VECTOR_MEM_ALTIVEC_OR_VSX_P (<MODE>mode)
+ && (<MODE>mode != TImode || TARGET_POWERPC64)"
"")
(define_expand "one_cmpl<mode>2"
[(set (match_operand:VEC_L 0 "vlogical_operand" "")
(not:VEC_L (match_operand:VEC_L 1 "vlogical_operand" "")))]
- "VECTOR_MEM_ALTIVEC_OR_VSX_P (<MODE>mode)"
+ "VECTOR_MEM_ALTIVEC_OR_VSX_P (<MODE>mode)
+ && (<MODE>mode != TImode || TARGET_POWERPC64)"
"")
(define_expand "nor<mode>3"
[(set (match_operand:VEC_L 0 "vlogical_operand" "")
(not:VEC_L (ior:VEC_L (match_operand:VEC_L 1 "vlogical_operand" "")
(match_operand:VEC_L 2 "vlogical_operand" ""))))]
- "VECTOR_MEM_ALTIVEC_OR_VSX_P (<MODE>mode)"
+ "VECTOR_MEM_ALTIVEC_OR_VSX_P (<MODE>mode)
+ && (<MODE>mode != TImode || TARGET_POWERPC64)"
"")
(define_expand "andc<mode>3"
[(set (match_operand:VEC_L 0 "vlogical_operand" "")
(and:VEC_L (not:VEC_L (match_operand:VEC_L 2 "vlogical_operand" ""))
(match_operand:VEC_L 1 "vlogical_operand" "")))]
- "VECTOR_MEM_ALTIVEC_OR_VSX_P (<MODE>mode)"
+ "VECTOR_MEM_ALTIVEC_OR_VSX_P (<MODE>mode)
+ && (<MODE>mode != TImode || TARGET_POWERPC64)"
"")
;; Same size conversions
diff --git a/gcc/config/rs6000/vsx.md b/gcc/config/rs6000/vsx.md
index dcb1f64d4ee..042bb5c73d6 100644
--- a/gcc/config/rs6000/vsx.md
+++ b/gcc/config/rs6000/vsx.md
@@ -48,7 +48,7 @@
(V2DF "vd2")
(V2DI "vd2")
(DF "d")
- (TI "vw4")])
+ (TI "vd2")])
;; Map into the appropriate suffix based on the type
(define_mode_attr VSs [(V16QI "sp")
@@ -59,7 +59,7 @@
(V2DI "dp")
(DF "dp")
(SF "sp")
- (TI "sp")])
+ (TI "dp")])
;; Map the register class used
(define_mode_attr VSr [(V16QI "v")
@@ -70,7 +70,7 @@
(V2DF "wd")
(DF "ws")
(SF "d")
- (TI "wd")])
+ (TI "wt")])
;; Map the register class used for float<->int conversions
(define_mode_attr VSr2 [(V2DF "wd")
@@ -115,7 +115,6 @@
(V4SF "v")
(V2DI "v")
(V2DF "v")
- (TI "v")
(DF "s")])
;; Appropriate type for add ops (and other simple FP ops)
@@ -268,12 +267,13 @@
}
[(set_attr "type" "vecstore,vecload,vecsimple,vecstore,vecload,vecsimple,*,*,*,vecsimple,vecsimple,*,vecstore,vecload")])
-;; Unlike other VSX moves, allow the GPRs, since a normal use of TImode is for
-;; unions. However for plain data movement, slightly favor the vector loads
-(define_insn "*vsx_movti"
- [(set (match_operand:TI 0 "nonimmediate_operand" "=Z,wa,wa,?Y,?r,?r,wa,v,v,wZ")
- (match_operand:TI 1 "input_operand" "wa,Z,wa,r,Y,r,j,W,wZ,v"))]
- "VECTOR_MEM_VSX_P (TImode)
+;; Unlike other VSX moves, allow the GPRs even for reloading, since a normal
+;; use of TImode is for unions. However for plain data movement, slightly
+;; favor the vector loads
+(define_insn "*vsx_movti_64bit"
+ [(set (match_operand:TI 0 "nonimmediate_operand" "=Z,wa,wa,wa,v, v,wZ,?Y,?r,?r")
+ (match_operand:TI 1 "input_operand" "wa, Z,wa, j,W,wZ, v, r, Y, r"))]
+ "TARGET_POWERPC64 && VECTOR_MEM_VSX_P (TImode)
&& (register_operand (operands[0], TImode)
|| register_operand (operands[1], TImode))"
{
@@ -289,27 +289,87 @@
return "xxlor %x0,%x1,%x1";
case 3:
+ return "xxlxor %x0,%x0,%x0";
+
case 4:
+ return output_vec_const_move (operands);
+
case 5:
- return "#";
+ return "stvx %1,%y0";
case 6:
- return "xxlxor %x0,%x0,%x0";
+ return "lvx %0,%y1";
case 7:
+ case 8:
+ case 9:
+ return "#";
+
+ default:
+ gcc_unreachable ();
+ }
+}
+ [(set_attr "type" "vecstore,vecload,vecsimple,vecsimple,vecsimple,vecstore,vecload,*,*,*")
+ (set_attr "length" " 4, 4, 4, 4, 8, 4, 4,8,8,8")])
+
+(define_insn "*vsx_movti_32bit"
+ [(set (match_operand:TI 0 "nonimmediate_operand" "=Z,wa,wa,wa,v, v,wZ,Q,Y,????r,????r,????r,r")
+ (match_operand:TI 1 "input_operand" "wa, Z,wa, j,W,wZ, v,r,r, Q, Y, r,n"))]
+ "! TARGET_POWERPC64 && VECTOR_MEM_VSX_P (TImode)
+ && (register_operand (operands[0], TImode)
+ || register_operand (operands[1], TImode))"
+{
+ switch (which_alternative)
+ {
+ case 0:
+ return "stxvd2x %x1,%y0";
+
+ case 1:
+ return "lxvd2x %x0,%y1";
+
+ case 2:
+ return "xxlor %x0,%x1,%x1";
+
+ case 3:
+ return "xxlxor %x0,%x0,%x0";
+
+ case 4:
return output_vec_const_move (operands);
- case 8:
+ case 5:
return "stvx %1,%y0";
- case 9:
+ case 6:
return "lvx %0,%y1";
+ case 7:
+ if (TARGET_STRING)
+ return \"stswi %1,%P0,16\";
+
+ case 8:
+ return \"#\";
+
+ case 9:
+ /* If the address is not used in the output, we can use lsi. Otherwise,
+ fall through to generating four loads. */
+ if (TARGET_STRING
+ && ! reg_overlap_mentioned_p (operands[0], operands[1]))
+ return \"lswi %0,%P1,16\";
+ /* ... fall through ... */
+
+ case 10:
+ case 11:
+ case 12:
+ return \"#\";
default:
gcc_unreachable ();
}
}
- [(set_attr "type" "vecstore,vecload,vecsimple,*,*,*,vecsimple,*,vecstore,vecload")])
+ [(set_attr "type" "vecstore,vecload,vecsimple,vecsimple,vecsimple,vecstore,vecload,store_ux,store_ux,load_ux,load_ux, *, *")
+ (set_attr "length" " 4, 4, 4, 4, 8, 4, 4, 16, 16, 16, 16,16,16")
+ (set (attr "cell_micro") (if_then_else (match_test "TARGET_STRING")
+ (const_string "always")
+ (const_string "conditional")))])
;; Explicit load/store expanders for the builtin functions
(define_expand "vsx_load_<mode>"
@@ -319,8 +379,8 @@
"")
(define_expand "vsx_store_<mode>"
- [(set (match_operand:VEC_M 0 "memory_operand" "")
- (match_operand:VEC_M 1 "vsx_register_operand" ""))]
+ [(set (match_operand:VSX_M 0 "memory_operand" "")
+ (match_operand:VSX_M 1 "vsx_register_operand" ""))]
"VECTOR_MEM_VSX_P (<MODE>mode)"
"")
@@ -1026,38 +1086,46 @@
(set_attr "fp_type" "<VSfptype_simple>")])
-;; Logical and permute operations
+;; Logical operations
+;; Do not support TImode logical instructions on 32-bit at present, because the
+;; compiler will see that we have a TImode and when it wanted DImode, and
+;; convert the DImode to TImode, store it on the stack, and load it in a VSX
+;; register.
(define_insn "*vsx_and<mode>3"
[(set (match_operand:VSX_L 0 "vsx_register_operand" "=<VSr>,?wa")
(and:VSX_L
- (match_operand:VSX_L 1 "vsx_register_operand" "<VSr>,?wa")
- (match_operand:VSX_L 2 "vsx_register_operand" "<VSr>,?wa")))]
- "VECTOR_MEM_VSX_P (<MODE>mode)"
+ (match_operand:VSX_L 1 "vsx_register_operand" "<VSr>,wa")
+ (match_operand:VSX_L 2 "vsx_register_operand" "<VSr>,wa")))]
+ "VECTOR_MEM_VSX_P (<MODE>mode)
+ && (<MODE>mode != TImode || TARGET_POWERPC64)"
"xxland %x0,%x1,%x2"
[(set_attr "type" "vecsimple")])
(define_insn "*vsx_ior<mode>3"
[(set (match_operand:VSX_L 0 "vsx_register_operand" "=<VSr>,?wa")
- (ior:VSX_L (match_operand:VSX_L 1 "vsx_register_operand" "<VSr>,?wa")
- (match_operand:VSX_L 2 "vsx_register_operand" "<VSr>,?wa")))]
- "VECTOR_MEM_VSX_P (<MODE>mode)"
+ (ior:VSX_L (match_operand:VSX_L 1 "vsx_register_operand" "<VSr>,wa")
+ (match_operand:VSX_L 2 "vsx_register_operand" "<VSr>,wa")))]
+ "VECTOR_MEM_VSX_P (<MODE>mode)
+ && (<MODE>mode != TImode || TARGET_POWERPC64)"
"xxlor %x0,%x1,%x2"
[(set_attr "type" "vecsimple")])
(define_insn "*vsx_xor<mode>3"
[(set (match_operand:VSX_L 0 "vsx_register_operand" "=<VSr>,?wa")
(xor:VSX_L
- (match_operand:VSX_L 1 "vsx_register_operand" "<VSr>,?wa")
- (match_operand:VSX_L 2 "vsx_register_operand" "<VSr>,?wa")))]
- "VECTOR_MEM_VSX_P (<MODE>mode)"
+ (match_operand:VSX_L 1 "vsx_register_operand" "<VSr>,wa")
+ (match_operand:VSX_L 2 "vsx_register_operand" "<VSr>,wa")))]
+ "VECTOR_MEM_VSX_P (<MODE>mode)
+ && (<MODE>mode != TImode || TARGET_POWERPC64)"
"xxlxor %x0,%x1,%x2"
[(set_attr "type" "vecsimple")])
(define_insn "*vsx_one_cmpl<mode>2"
[(set (match_operand:VSX_L 0 "vsx_register_operand" "=<VSr>,?wa")
(not:VSX_L
- (match_operand:VSX_L 1 "vsx_register_operand" "<VSr>,?wa")))]
- "VECTOR_MEM_VSX_P (<MODE>mode)"
+ (match_operand:VSX_L 1 "vsx_register_operand" "<VSr>,wa")))]
+ "VECTOR_MEM_VSX_P (<MODE>mode)
+ && (<MODE>mode != TImode || TARGET_POWERPC64)"
"xxlnor %x0,%x1,%x1"
[(set_attr "type" "vecsimple")])
@@ -1067,7 +1135,8 @@
(ior:VSX_L
(match_operand:VSX_L 1 "vsx_register_operand" "<VSr>,?wa")
(match_operand:VSX_L 2 "vsx_register_operand" "<VSr>,?wa"))))]
- "VECTOR_MEM_VSX_P (<MODE>mode)"
+ "VECTOR_MEM_VSX_P (<MODE>mode)
+ && (<MODE>mode != TImode || TARGET_POWERPC64)"
"xxlnor %x0,%x1,%x2"
[(set_attr "type" "vecsimple")])
@@ -1077,7 +1146,8 @@
(not:VSX_L
(match_operand:VSX_L 2 "vsx_register_operand" "<VSr>,?wa"))
(match_operand:VSX_L 1 "vsx_register_operand" "<VSr>,?wa")))]
- "VECTOR_MEM_VSX_P (<MODE>mode)"
+ "VECTOR_MEM_VSX_P (<MODE>mode)
+ && (<MODE>mode != TImode || TARGET_POWERPC64)"
"xxlandc %x0,%x1,%x2"
[(set_attr "type" "vecsimple")])
@@ -1086,11 +1156,10 @@
;; Build a V2DF/V2DI vector from two scalars
(define_insn "vsx_concat_<mode>"
- [(set (match_operand:VSX_D 0 "vsx_register_operand" "=wd,?wa")
- (unspec:VSX_D
- [(match_operand:<VS_scalar> 1 "vsx_register_operand" "ws,wa")
- (match_operand:<VS_scalar> 2 "vsx_register_operand" "ws,wa")]
- UNSPEC_VSX_CONCAT))]
+ [(set (match_operand:VSX_D 0 "vsx_register_operand" "=<VSr>,?wa")
+ (vec_concat:VSX_D
+ (match_operand:<VS_scalar> 1 "vsx_register_operand" "ws,wa")
+ (match_operand:<VS_scalar> 2 "vsx_register_operand" "ws,wa")))]
"VECTOR_MEM_VSX_P (<MODE>mode)"
"xxpermdi %x0,%x1,%x2,0"
[(set_attr "type" "vecperm")])
@@ -1148,7 +1217,11 @@
(parallel [(const_int 0)])))]
"VECTOR_MEM_VSX_P (<MODE>mode) && WORDS_BIG_ENDIAN"
"lxsd%U1x %x0,%y1"
- [(set_attr "type" "fpload")
+ [(set (attr "type")
+ (if_then_else
+ (match_test "update_indexed_address_mem (operands[1], VOIDmode)")
+ (const_string "fpload_ux")
+ (const_string "fpload")))
(set_attr "length" "4")])
;; Extract a SF element from V4SF
@@ -1212,8 +1285,8 @@
if (<MODE>mode != V2DImode)
{
target = gen_lowpart (V2DImode, target);
- op0 = gen_lowpart (V2DImode, target);
- op1 = gen_lowpart (V2DImode, target);
+ op0 = gen_lowpart (V2DImode, op0);
+ op1 = gen_lowpart (V2DImode, op1);
}
}
emit_insn (gen (target, op0, op1, perm0, perm1));
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index 7e87dcd547d..f6aa581e4b8 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -5738,7 +5738,7 @@ addr_generation_dependency_p (rtx dep_rtx, rtx insn)
{
rtx target, pat;
- if (GET_CODE (dep_rtx) == INSN)
+ if (NONJUMP_INSN_P (dep_rtx))
dep_rtx = PATTERN (dep_rtx);
if (GET_CODE (dep_rtx) == SET)
@@ -5978,7 +5978,7 @@ s390_split_branches (void)
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
- if (GET_CODE (insn) != JUMP_INSN)
+ if (! JUMP_P (insn))
continue;
pat = PATTERN (insn);
@@ -6398,7 +6398,7 @@ s390_find_constant (struct constant_pool *pool, rtx val,
static rtx
s390_execute_label (rtx insn)
{
- if (GET_CODE (insn) == INSN
+ if (NONJUMP_INSN_P (insn)
&& GET_CODE (PATTERN (insn)) == PARALLEL
&& GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == UNSPEC
&& XINT (XVECEXP (PATTERN (insn), 0, 0), 1) == UNSPEC_EXECUTE)
@@ -6603,7 +6603,7 @@ s390_mainpool_start (void)
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
- if (GET_CODE (insn) == INSN
+ if (NONJUMP_INSN_P (insn)
&& GET_CODE (PATTERN (insn)) == SET
&& GET_CODE (SET_SRC (PATTERN (insn))) == UNSPEC_VOLATILE
&& XINT (SET_SRC (PATTERN (insn)), 1) == UNSPECV_MAIN_POOL)
@@ -6616,7 +6616,7 @@ s390_mainpool_start (void)
{
s390_add_execute (pool, insn);
}
- else if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
+ else if (NONJUMP_INSN_P (insn) || CALL_P (insn))
{
rtx pool_ref = NULL_RTX;
find_constant_pool_ref (PATTERN (insn), &pool_ref);
@@ -6758,7 +6758,7 @@ s390_mainpool_finish (struct constant_pool *pool)
if (INSN_P (insn))
replace_ltrel_base (&PATTERN (insn));
- if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
+ if (NONJUMP_INSN_P (insn) || CALL_P (insn))
{
rtx addr, pool_ref = NULL_RTX;
find_constant_pool_ref (PATTERN (insn), &pool_ref);
@@ -6840,7 +6840,7 @@ s390_chunkify_start (void)
s390_add_execute (curr_pool, insn);
s390_add_pool_insn (curr_pool, insn);
}
- else if (GET_CODE (insn) == INSN || CALL_P (insn))
+ else if (NONJUMP_INSN_P (insn) || CALL_P (insn))
{
rtx pool_ref = NULL_RTX;
find_constant_pool_ref (PATTERN (insn), &pool_ref);
@@ -6867,7 +6867,7 @@ s390_chunkify_start (void)
}
}
- if (GET_CODE (insn) == JUMP_INSN || GET_CODE (insn) == CODE_LABEL)
+ if (JUMP_P (insn) || LABEL_P (insn))
{
if (curr_pool)
s390_add_pool_insn (curr_pool, insn);
@@ -6911,7 +6911,7 @@ s390_chunkify_start (void)
Those will have an effect on code size, which we need to
consider here. This calculation makes rather pessimistic
worst-case assumptions. */
- if (GET_CODE (insn) == CODE_LABEL)
+ if (LABEL_P (insn))
extra_size += 6;
if (chunk_size < S390_POOL_CHUNK_MIN
@@ -6920,7 +6920,7 @@ s390_chunkify_start (void)
continue;
/* Pool chunks can only be inserted after BARRIERs ... */
- if (GET_CODE (insn) == BARRIER)
+ if (BARRIER_P (insn))
{
s390_end_pool (curr_pool, insn);
curr_pool = NULL;
@@ -6937,7 +6937,7 @@ s390_chunkify_start (void)
if (!section_switch_p)
{
/* We can insert the barrier only after a 'real' insn. */
- if (GET_CODE (insn) != INSN && GET_CODE (insn) != CALL_INSN)
+ if (! NONJUMP_INSN_P (insn) && ! CALL_P (insn))
continue;
if (get_attr_length (insn) == 0)
continue;
@@ -7009,11 +7009,11 @@ s390_chunkify_start (void)
Don't do that, however, if it is the label before
a jump table. */
- if (GET_CODE (insn) == CODE_LABEL
+ if (LABEL_P (insn)
&& (LABEL_PRESERVE_P (insn) || LABEL_NAME (insn)))
{
rtx vec_insn = next_real_insn (insn);
- rtx vec_pat = vec_insn && GET_CODE (vec_insn) == JUMP_INSN ?
+ rtx vec_pat = vec_insn && JUMP_P (vec_insn) ?
PATTERN (vec_insn) : NULL_RTX;
if (!vec_pat
|| !(GET_CODE (vec_pat) == ADDR_VEC
@@ -7023,7 +7023,7 @@ s390_chunkify_start (void)
/* If we have a direct jump (conditional or unconditional)
or a casesi jump, check all potential targets. */
- else if (GET_CODE (insn) == JUMP_INSN)
+ else if (JUMP_P (insn))
{
rtx pat = PATTERN (insn);
if (GET_CODE (pat) == PARALLEL && XVECLEN (pat, 0) > 2)
@@ -7048,7 +7048,7 @@ s390_chunkify_start (void)
/* Find the jump table used by this casesi jump. */
rtx vec_label = XEXP (XEXP (XVECEXP (pat, 0, 1), 0), 0);
rtx vec_insn = next_real_insn (vec_label);
- rtx vec_pat = vec_insn && GET_CODE (vec_insn) == JUMP_INSN ?
+ rtx vec_pat = vec_insn && JUMP_P (vec_insn) ?
PATTERN (vec_insn) : NULL_RTX;
if (vec_pat
&& (GET_CODE (vec_pat) == ADDR_VEC
@@ -7082,7 +7082,7 @@ s390_chunkify_start (void)
/* Insert base register reload insns at every far label. */
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
- if (GET_CODE (insn) == CODE_LABEL
+ if (LABEL_P (insn)
&& bitmap_bit_p (far_labels, CODE_LABEL_NUMBER (insn)))
{
struct constant_pool *pool = s390_find_pool (pool_list, insn);
@@ -7128,7 +7128,7 @@ s390_chunkify_finish (struct constant_pool *pool_list)
if (!curr_pool)
continue;
- if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN)
+ if (NONJUMP_INSN_P (insn) || CALL_P (insn))
{
rtx addr, pool_ref = NULL_RTX;
find_constant_pool_ref (PATTERN (insn), &pool_ref);
@@ -7181,9 +7181,9 @@ s390_chunkify_cancel (struct constant_pool *pool_list)
rtx jump = barrier? PREV_INSN (barrier) : NULL_RTX;
rtx label = NEXT_INSN (curr_pool->pool_insn);
- if (jump && GET_CODE (jump) == JUMP_INSN
- && barrier && GET_CODE (barrier) == BARRIER
- && label && GET_CODE (label) == CODE_LABEL
+ if (jump && JUMP_P (jump)
+ && barrier && BARRIER_P (barrier)
+ && label && LABEL_P (label)
&& GET_CODE (PATTERN (jump)) == SET
&& SET_DEST (PATTERN (jump)) == pc_rtx
&& GET_CODE (SET_SRC (PATTERN (jump))) == LABEL_REF
@@ -7203,7 +7203,7 @@ s390_chunkify_cancel (struct constant_pool *pool_list)
{
rtx next_insn = NEXT_INSN (insn);
- if (GET_CODE (insn) == INSN
+ if (NONJUMP_INSN_P (insn)
&& GET_CODE (PATTERN (insn)) == SET
&& GET_CODE (SET_SRC (PATTERN (insn))) == UNSPEC
&& XINT (SET_SRC (PATTERN (insn)), 1) == UNSPEC_RELOAD_BASE)
@@ -10080,7 +10080,7 @@ s390_optimize_prologue (void)
next_insn = NEXT_INSN (insn);
- if (GET_CODE (insn) != INSN)
+ if (! NONJUMP_INSN_P (insn))
continue;
if (GET_CODE (PATTERN (insn)) == PARALLEL
diff --git a/gcc/config/sh/linux.h b/gcc/config/sh/linux.h
index 8bc7de83ab0..9e8f32d06d1 100644
--- a/gcc/config/sh/linux.h
+++ b/gcc/config/sh/linux.h
@@ -39,8 +39,7 @@ along with GCC; see the file COPYING3. If not see
#undef TARGET_DEFAULT
#define TARGET_DEFAULT \
- (TARGET_CPU_DEFAULT | MASK_USERMODE | TARGET_ENDIAN_DEFAULT \
- | TARGET_OPT_DEFAULT)
+ (TARGET_CPU_DEFAULT | TARGET_ENDIAN_DEFAULT | TARGET_OPT_DEFAULT)
#define TARGET_ASM_FILE_END file_end_indicate_exec_stack
@@ -146,5 +145,8 @@ along with GCC; see the file COPYING3. If not see
else if (TARGET_SH1) \
sh_atomic_model_str = "soft-imask"; \
} \
+ /* Set -musermode if it hasn't been specified. */ \
+ if (global_options_set.x_TARGET_USERMODE == 0) \
+ TARGET_USERMODE = true; \
} \
while (0)
diff --git a/gcc/config/sh/netbsd-elf.h b/gcc/config/sh/netbsd-elf.h
index a390f40feea..807638a0f79 100644
--- a/gcc/config/sh/netbsd-elf.h
+++ b/gcc/config/sh/netbsd-elf.h
@@ -58,7 +58,7 @@ along with GCC; see the file COPYING3. If not see
#undef TARGET_DEFAULT
#define TARGET_DEFAULT \
- (TARGET_CPU_DEFAULT | MASK_USERMODE | TARGET_ENDIAN_DEFAULT)
+ (TARGET_CPU_DEFAULT | TARGET_ENDIAN_DEFAULT)
/* Define because we use the label and we do not need them. */
#define NO_PROFILE_COUNTERS 1
@@ -94,3 +94,13 @@ while (0)
#define SH_DIV_STRATEGY_DEFAULT SH_DIV_CALL2
#undef SH_DIV_STR_FOR_SIZE
#define SH_DIV_STR_FOR_SIZE "call2"
+
+#undef SUBTARGET_OVERRIDE_OPTIONS
+#define SUBTARGET_OVERRIDE_OPTIONS \
+ do \
+ { \
+ /* Set -musermode if it hasn't been specified. */ \
+ if (global_options_set.x_TARGET_USERMODE == 0) \
+ TARGET_USERMODE = true; \
+ } \
+ while (0)
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
index dcbd93286ed..44e1e4ce30e 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -816,8 +816,7 @@ sh_option_override (void)
if (! strcmp (sh_div_str, "call-div1"))
sh_div_strategy = SH_DIV_CALL_DIV1;
else if (! strcmp (sh_div_str, "call-fp")
- && (TARGET_FPU_DOUBLE
- || (TARGET_HARD_SH4 && TARGET_SH2E)
+ && (TARGET_FPU_DOUBLE || TARGET_FPU_SINGLE_ONLY
|| (TARGET_SHCOMPACT && TARGET_FPU_ANY)))
sh_div_strategy = SH_DIV_CALL_FP;
else if (! strcmp (sh_div_str, "call-table") && TARGET_DYNSHIFT)
diff --git a/gcc/config/sh/sh.h b/gcc/config/sh/sh.h
index ecd6c17e553..3744f980fe7 100644
--- a/gcc/config/sh/sh.h
+++ b/gcc/config/sh/sh.h
@@ -138,14 +138,16 @@ extern int code_for_indirect_jump_scratch;
| MASK_SH2 | MASK_SH1)
#define SELECT_SH2A_NOFPU (MASK_HARD_SH2A | MASK_SH2 | MASK_SH1)
#define SELECT_SH2A_SINGLE_ONLY (MASK_SH_E | MASK_HARD_SH2A | MASK_SH2 \
- | MASK_SH1 | MASK_FPU_SINGLE)
+ | MASK_SH1 | MASK_FPU_SINGLE \
+ | MASK_FPU_SINGLE_ONLY)
#define SELECT_SH2A_SINGLE (MASK_SH_E | MASK_HARD_SH2A \
| MASK_FPU_SINGLE | MASK_HARD_SH2A_DOUBLE \
| MASK_SH2 | MASK_SH1)
#define SELECT_SH3 (MASK_SH3 | SELECT_SH2)
#define SELECT_SH3E (MASK_SH_E | MASK_FPU_SINGLE | SELECT_SH3)
#define SELECT_SH4_NOFPU (MASK_HARD_SH4 | SELECT_SH3)
-#define SELECT_SH4_SINGLE_ONLY (MASK_HARD_SH4 | SELECT_SH3E)
+#define SELECT_SH4_SINGLE_ONLY (MASK_HARD_SH4 | SELECT_SH3E \
+ | MASK_FPU_SINGLE_ONLY)
#define SELECT_SH4 (MASK_SH4 | MASK_SH_E | MASK_HARD_SH4 \
| SELECT_SH3)
#define SELECT_SH4_SINGLE (MASK_FPU_SINGLE | SELECT_SH4)
@@ -212,7 +214,8 @@ extern int code_for_indirect_jump_scratch;
/* Reset all target-selection flags. */
#define MASK_ARCH (MASK_SH1 | MASK_SH2 | MASK_SH3 | MASK_SH_E | MASK_SH4 \
| MASK_HARD_SH2A | MASK_HARD_SH2A_DOUBLE | MASK_SH4A \
- | MASK_HARD_SH4 | MASK_FPU_SINGLE | MASK_SH5)
+ | MASK_HARD_SH4 | MASK_FPU_SINGLE | MASK_SH5 \
+ | MASK_FPU_SINGLE_ONLY)
/* This defaults us to big-endian. */
#ifndef TARGET_ENDIAN_DEFAULT
diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md
index 75b102c3fa7..42ef5e142d8 100644
--- a/gcc/config/sh/sh.md
+++ b/gcc/config/sh/sh.md
@@ -2154,7 +2154,7 @@
(clobber (reg:SI PR_REG))
(clobber (reg:SI R4_REG))
(use (match_operand:SI 1 "arith_reg_operand" "r"))]
- "TARGET_SH1 && (! TARGET_SH4 || TARGET_DIVIDE_CALL_DIV1)"
+ "TARGET_SH1 && TARGET_DIVIDE_CALL_DIV1"
"jsr @%1%#"
[(set_attr "type" "sfunc")
(set_attr "needs_delay_slot" "yes")])
@@ -2217,7 +2217,7 @@
(clobber (reg:SI R5_REG))
(use (reg:PSI FPSCR_REG))
(use (match_operand:SI 1 "arith_reg_operand" "r"))]
- "TARGET_SH4 && ! TARGET_FPU_SINGLE"
+ "TARGET_FPU_DOUBLE && ! TARGET_FPU_SINGLE"
"jsr @%1%#"
[(set_attr "type" "sfunc")
(set_attr "fp_mode" "double")
@@ -2236,7 +2236,8 @@
(clobber (reg:SI R4_REG))
(clobber (reg:SI R5_REG))
(use (match_operand:SI 1 "arith_reg_operand" "r"))]
- "(TARGET_HARD_SH4 || TARGET_SHCOMPACT) && TARGET_FPU_SINGLE"
+ "(TARGET_FPU_SINGLE_ONLY || TARGET_FPU_DOUBLE || TARGET_SHCOMPACT)
+ && TARGET_FPU_SINGLE"
"jsr @%1%#"
[(set_attr "type" "sfunc")
(set_attr "needs_delay_slot" "yes")])
@@ -2358,7 +2359,7 @@
(clobber (reg:SI R2_REG))
(clobber (reg:SI R3_REG))
(use (match_operand:SI 1 "arith_reg_operand" "r"))]
- "TARGET_SH1 && (! TARGET_SH4 || TARGET_DIVIDE_CALL_DIV1)"
+ "TARGET_SH1 && TARGET_DIVIDE_CALL_DIV1"
"jsr @%1%#"
[(set_attr "type" "sfunc")
(set_attr "needs_delay_slot" "yes")])
@@ -2487,7 +2488,7 @@
(clobber (reg:DF DR2_REG))
(use (reg:PSI FPSCR_REG))
(use (match_operand:SI 1 "arith_reg_operand" "r"))]
- "TARGET_SH4 && ! TARGET_FPU_SINGLE"
+ "TARGET_FPU_DOUBLE && ! TARGET_FPU_SINGLE"
"jsr @%1%#"
[(set_attr "type" "sfunc")
(set_attr "fp_mode" "double")
@@ -2501,7 +2502,8 @@
(clobber (reg:DF DR2_REG))
(clobber (reg:SI R2_REG))
(use (match_operand:SI 1 "arith_reg_operand" "r"))]
- "(TARGET_HARD_SH4 || TARGET_SHCOMPACT) && TARGET_FPU_SINGLE"
+ "(TARGET_FPU_SINGLE_ONLY || TARGET_FPU_DOUBLE || TARGET_SHCOMPACT)
+ && TARGET_FPU_SINGLE"
"jsr @%1%#"
[(set_attr "type" "sfunc")
(set_attr "needs_delay_slot" "yes")])
diff --git a/gcc/config/sh/sh.opt b/gcc/config/sh/sh.opt
index 0ee36be45fa..c314e144c21 100644
--- a/gcc/config/sh/sh.opt
+++ b/gcc/config/sh/sh.opt
@@ -24,6 +24,10 @@ Mask(SH_E)
;; Set if the default precision of th FPU is single.
Mask(FPU_SINGLE)
+;; Set if the a double-precision FPU is present but is restricted to
+;; single precision usage only.
+Mask(FPU_SINGLE_ONLY)
+
;; Set if we should generate code using type 2A insns.
Mask(HARD_SH2A)
@@ -339,7 +343,7 @@ Target RejectNegative Joined UInteger Var(sh_multcost) Init(-1)
Cost to assume for a multiply insn
musermode
-Target Report RejectNegative Mask(USERMODE)
+Target Report RejectNegative Var(TARGET_USERMODE)
Don't generate privileged-mode only code; implies -mno-inline-ic_invalidate if the inline code would not work in user mode.
;; We might want to enable this by default for TARGET_HARD_SH4, because
diff --git a/gcc/config/sol2.c b/gcc/config/sol2.c
index 95c7e0f4165..7c7c429db3d 100644
--- a/gcc/config/sol2.c
+++ b/gcc/config/sol2.c
@@ -291,8 +291,8 @@ solaris_file_end (void)
void
solaris_override_options (void)
{
- /* Don't emit DWARF3/4 unless specifically selected. Solaris ld cannot
- handle CIE version 3 in .eh_frame. */
- if (!global_options_set.x_dwarf_version)
+ /* Older versions of Solaris ld cannot handle CIE version 3 in .eh_frame.
+ Don't emit DWARF3/4 unless specifically selected if so. */
+ if (!HAVE_LD_EH_FRAME_CIEV3 && !global_options_set.x_dwarf_version)
dwarf_version = 2;
}
diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c
index 08c2894fbbc..3e98325bd3b 100644
--- a/gcc/config/sparc/sparc.c
+++ b/gcc/config/sparc/sparc.c
@@ -3063,10 +3063,10 @@ emit_cbcond_nop (rtx insn)
if (!next)
return 1;
- if (GET_CODE (next) == INSN
+ if (NONJUMP_INSN_P (next)
&& GET_CODE (PATTERN (next)) == SEQUENCE)
next = XVECEXP (PATTERN (next), 0, 0);
- else if (GET_CODE (next) == CALL_INSN
+ else if (CALL_P (next)
&& GET_CODE (PATTERN (next)) == PARALLEL)
{
rtx delay = XVECEXP (PATTERN (next), 0, 1);
@@ -3222,7 +3222,7 @@ eligible_for_return_delay (rtx trial)
int regno;
rtx pat;
- if (GET_CODE (trial) != INSN)
+ if (! NONJUMP_INSN_P (trial))
return 0;
if (get_attr_length (trial) != 1)
@@ -3293,7 +3293,7 @@ eligible_for_sibcall_delay (rtx trial)
{
rtx pat;
- if (GET_CODE (trial) != INSN || GET_CODE (PATTERN (trial)) != SET)
+ if (! NONJUMP_INSN_P (trial) || GET_CODE (PATTERN (trial)) != SET)
return 0;
if (get_attr_length (trial) != 1)
@@ -4777,7 +4777,7 @@ sparc_emit_probe_stack_range (HOST_WIDE_INT first, HOST_WIDE_INT size)
probes at FIRST + N * PROBE_INTERVAL for values of N from 1
until it is equal to ROUNDED_SIZE. */
- if (TARGET_64BIT)
+ if (TARGET_ARCH64)
emit_insn (gen_probe_stack_rangedi (g1, g1, g4));
else
emit_insn (gen_probe_stack_rangesi (g1, g1, g4));
@@ -5424,7 +5424,7 @@ sparc_asm_function_epilogue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
last_real_insn = prev_real_insn (insn);
if (last_real_insn
- && GET_CODE (last_real_insn) == INSN
+ && NONJUMP_INSN_P (last_real_insn)
&& GET_CODE (PATTERN (last_real_insn)) == SEQUENCE)
last_real_insn = XVECEXP (PATTERN (last_real_insn), 0, 0);
diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md
index b60af43334c..933991c168d 100644
--- a/gcc/config/sparc/sparc.md
+++ b/gcc/config/sparc/sparc.md
@@ -7217,7 +7217,7 @@
[(trap_if (match_operator 0 "noov_compare_operator"
[(match_operand:SI 1 "compare_operand" "")
(match_operand:SI 2 "arith_operand" "")])
- (match_operand 3 ""))]
+ (match_operand 3 "arith_operand"))]
""
"operands[1] = gen_compare_reg (operands[0]);
if (GET_MODE (operands[1]) != CCmode && GET_MODE (operands[1]) != CCXmode)
@@ -7228,7 +7228,7 @@
[(trap_if (match_operator 0 "noov_compare_operator"
[(match_operand:DI 1 "compare_operand" "")
(match_operand:DI 2 "arith_operand" "")])
- (match_operand 3 ""))]
+ (match_operand 3 "arith_operand"))]
"TARGET_ARCH64"
"operands[1] = gen_compare_reg (operands[0]);
if (GET_MODE (operands[1]) != CCmode && GET_MODE (operands[1]) != CCXmode)
diff --git a/gcc/config/spu/spu.c b/gcc/config/spu/spu.c
index 328bd5bd2ae..2d8ec9c89b2 100644
--- a/gcc/config/spu/spu.c
+++ b/gcc/config/spu/spu.c
@@ -1962,7 +1962,7 @@ struct spu_bb_info
static struct spu_bb_info *spu_bb_info;
#define STOP_HINT_P(INSN) \
- (GET_CODE(INSN) == CALL_INSN \
+ (CALL_P(INSN) \
|| INSN_CODE(INSN) == CODE_FOR_divmodsi4 \
|| INSN_CODE(INSN) == CODE_FOR_udivmodsi4)
@@ -2163,7 +2163,7 @@ spu_emit_branch_hint (rtx before, rtx branch, rtx target,
static rtx
get_branch_target (rtx branch)
{
- if (GET_CODE (branch) == JUMP_INSN)
+ if (JUMP_P (branch))
{
rtx set, src;
@@ -2212,7 +2212,7 @@ get_branch_target (rtx branch)
return src;
}
- else if (GET_CODE (branch) == CALL_INSN)
+ else if (CALL_P (branch))
{
rtx call;
/* All of our call patterns are in a PARALLEL and the CALL is
diff --git a/gcc/config/stormy16/stormy16.c b/gcc/config/stormy16/stormy16.c
index 3e20d209a18..30d6d781576 100644
--- a/gcc/config/stormy16/stormy16.c
+++ b/gcc/config/stormy16/stormy16.c
@@ -1082,7 +1082,7 @@ xstormy16_expand_prologue (void)
gen_rtx_MEM (Pmode, stack_pointer_rtx),
reg);
XVECEXP (dwarf, 0, 1) = gen_rtx_SET (Pmode, stack_pointer_rtx,
- plus_constant (Pmode, \
+ plus_constant (Pmode,
stack_pointer_rtx,
GET_MODE_SIZE (Pmode)));
add_reg_note (insn, REG_FRAME_RELATED_EXPR, dwarf);
@@ -2441,8 +2441,7 @@ combine_bnp (rtx insn)
if (reg_mentioned_p (reg, and_insn))
return;
- if (GET_CODE (and_insn) != NOTE
- && GET_CODE (and_insn) != INSN)
+ if (! NOTE_P (and_insn) && ! NONJUMP_INSN_P (and_insn))
return;
}
}
@@ -2461,8 +2460,7 @@ combine_bnp (rtx insn)
if (reg_mentioned_p (reg, and_insn))
return;
- if (GET_CODE (and_insn) != NOTE
- && GET_CODE (and_insn) != INSN)
+ if (! NOTE_P (and_insn) && ! NONJUMP_INSN_P (and_insn))
return;
}
@@ -2486,8 +2484,7 @@ combine_bnp (rtx insn)
break;
if (reg_mentioned_p (reg, shift)
- || (GET_CODE (shift) != NOTE
- && GET_CODE (shift) != INSN))
+ || (! NOTE_P (shift) && ! NONJUMP_INSN_P (shift)))
{
shift = NULL_RTX;
break;
@@ -2534,8 +2531,7 @@ combine_bnp (rtx insn)
if (reg_mentioned_p (reg, load))
return;
- if (GET_CODE (load) != NOTE
- && GET_CODE (load) != INSN)
+ if (! NOTE_P (load) && ! NONJUMP_INSN_P (load))
return;
}
if (!load)
diff --git a/gcc/config/tilegx/sync.md b/gcc/config/tilegx/sync.md
index a853996162a..a4bea6b6889 100644
--- a/gcc/config/tilegx/sync.md
+++ b/gcc/config/tilegx/sync.md
@@ -162,3 +162,49 @@
tilegx_post_atomic_barrier (model);
DONE;
})
+
+
+(define_expand "atomic_test_and_set"
+ [(match_operand:QI 0 "register_operand" "") ;; bool output
+ (match_operand:QI 1 "nonautoincmem_operand" "+U") ;; memory
+ (match_operand:SI 2 "const_int_operand" "")] ;; model
+ ""
+{
+ rtx addr, aligned_addr, aligned_mem, offset, word, shmt;
+ rtx tmp0, tmp1;
+ rtx result = operands[0];
+ rtx mem = operands[1];
+ enum memmodel model = (enum memmodel) INTVAL (operands[2]);
+
+ addr = force_reg (Pmode, XEXP (mem, 0));
+
+ aligned_addr = gen_reg_rtx (Pmode);
+ emit_move_insn (aligned_addr, gen_rtx_AND (Pmode, addr, GEN_INT (-8)));
+
+ aligned_mem = change_address (mem, DImode, aligned_addr);
+ set_mem_alias_set (aligned_mem, 0);
+
+ offset = gen_reg_rtx (DImode);
+ emit_move_insn (offset, gen_rtx_AND (DImode, gen_lowpart (DImode, addr),
+ GEN_INT (7)));
+
+ tmp0 = gen_reg_rtx (DImode);
+ emit_move_insn (tmp0, GEN_INT (1));
+
+ shmt = gen_reg_rtx (DImode);
+ emit_move_insn (shmt, gen_rtx_ASHIFT (DImode, offset, GEN_INT (3)));
+
+ word = gen_reg_rtx (DImode);
+ emit_move_insn (word, gen_rtx_ASHIFT (DImode, tmp0,
+ gen_lowpart (SImode, shmt)));
+
+ tmp1 = gen_reg_rtx (DImode);
+ tilegx_pre_atomic_barrier (model);
+ emit_insn (gen_atomic_fetch_or_baredi (tmp1, aligned_mem, word));
+ tilegx_post_atomic_barrier (model);
+
+ emit_move_insn (gen_lowpart (DImode, result),
+ gen_rtx_LSHIFTRT (DImode, tmp1,
+ gen_lowpart (SImode, shmt)));
+ DONE;
+})
diff --git a/gcc/config/v850/v850.c b/gcc/config/v850/v850.c
index 67cc2c26716..4a746aa1424 100644
--- a/gcc/config/v850/v850.c
+++ b/gcc/config/v850/v850.c
@@ -1133,13 +1133,13 @@ Saved %d bytes (%d uses of register %s) in function %s, starting as insn %d, end
IDENTIFIER_POINTER (DECL_NAME (current_function_decl)),
INSN_UID (first_insn), INSN_UID (last_insn));
- if (GET_CODE (first_insn) == NOTE)
+ if (NOTE_P (first_insn))
first_insn = next_nonnote_insn (first_insn);
last_insn = next_nonnote_insn (last_insn);
for (insn = first_insn; insn && insn != last_insn; insn = NEXT_INSN (insn))
{
- if (GET_CODE (insn) == INSN)
+ if (NONJUMP_INSN_P (insn))
{
rtx pattern = single_set (insn);
@@ -1199,7 +1199,7 @@ Saved %d bytes (%d uses of register %s) in function %s, starting as insn %d, end
/* Optimize back to back cases of ep <- r1 & r1 <- ep. */
insn = prev_nonnote_insn (first_insn);
- if (insn && GET_CODE (insn) == INSN
+ if (insn && NONJUMP_INSN_P (insn)
&& GET_CODE (PATTERN (insn)) == SET
&& SET_DEST (PATTERN (insn)) == *p_ep
&& SET_SRC (PATTERN (insn)) == *p_r1)
diff --git a/gcc/config/xtensa/xtensa.c b/gcc/config/xtensa/xtensa.c
index 45929ad515e..7faf7de9968 100644
--- a/gcc/config/xtensa/xtensa.c
+++ b/gcc/config/xtensa/xtensa.c
@@ -1650,7 +1650,7 @@ xtensa_emit_loop_end (rtx insn, rtx *operands)
{
rtx body = PATTERN (insn);
- if (GET_CODE (body) == JUMP_INSN)
+ if (JUMP_P (body))
{
output_asm_insn (TARGET_DENSITY ? "nop.n" : "nop", operands);
done = 1;