/* Subroutines used for code generation on the Synopsys DesignWare ARC cpu.
- Copyright (C) 1994-2015 Free Software Foundation, Inc.
+ Copyright (C) 1994-2016 Free Software Foundation, Inc.
Sources derived from work done by Sankhya Technologies (www.sankhya.com) on
behalf of Synopsys Inc.
#include "config.h"
#include "system.h"
#include "coretypes.h"
+#include "memmodel.h"
#include "backend.h"
#include "target.h"
#include "rtl.h"
#include "alias.h"
/* Which cpu we're compiling for (ARC600, ARC601, ARC700). */
-static const char *arc_cpu_string = "";
+static char arc_cpu_name[10] = "";
+static const char *arc_cpu_string = arc_cpu_name;
/* ??? Loads can handle any constant, stores can only handle small ones. */
/* OTOH, LIMMs cost extra, so their usefulness is limited. */
this to be no less than the 1/p */
#define MAX_INSNS_SKIPPED 3
-/* The values of unspec's first field. */
-enum {
- ARC_UNSPEC_PLT = 3,
- ARC_UNSPEC_GOT,
- ARC_UNSPEC_GOTOFF
-} ;
-
-
-enum arc_builtins {
- ARC_BUILTIN_NOP = 2,
- ARC_BUILTIN_NORM = 3,
- ARC_BUILTIN_NORMW = 4,
- ARC_BUILTIN_SWAP = 5,
- ARC_BUILTIN_BRK = 6,
- ARC_BUILTIN_DIVAW = 7,
- ARC_BUILTIN_EX = 8,
- ARC_BUILTIN_MUL64 = 9,
- ARC_BUILTIN_MULU64 = 10,
- ARC_BUILTIN_RTIE = 11,
- ARC_BUILTIN_SYNC = 12,
- ARC_BUILTIN_CORE_READ = 13,
- ARC_BUILTIN_CORE_WRITE = 14,
- ARC_BUILTIN_FLAG = 15,
- ARC_BUILTIN_LR = 16,
- ARC_BUILTIN_SR = 17,
- ARC_BUILTIN_SLEEP = 18,
- ARC_BUILTIN_SWI = 19,
- ARC_BUILTIN_TRAP_S = 20,
- ARC_BUILTIN_UNIMP_S = 21,
- ARC_BUILTIN_ALIGNED = 22,
-
- /* Sentinel to mark start of simd builtins. */
- ARC_SIMD_BUILTIN_BEGIN = 1000,
-
- ARC_SIMD_BUILTIN_VADDAW = 1001,
- ARC_SIMD_BUILTIN_VADDW = 1002,
- ARC_SIMD_BUILTIN_VAVB = 1003,
- ARC_SIMD_BUILTIN_VAVRB = 1004,
- ARC_SIMD_BUILTIN_VDIFAW = 1005,
- ARC_SIMD_BUILTIN_VDIFW = 1006,
- ARC_SIMD_BUILTIN_VMAXAW = 1007,
- ARC_SIMD_BUILTIN_VMAXW = 1008,
- ARC_SIMD_BUILTIN_VMINAW = 1009,
- ARC_SIMD_BUILTIN_VMINW = 1010,
- ARC_SIMD_BUILTIN_VMULAW = 1011,
- ARC_SIMD_BUILTIN_VMULFAW = 1012,
- ARC_SIMD_BUILTIN_VMULFW = 1013,
- ARC_SIMD_BUILTIN_VMULW = 1014,
- ARC_SIMD_BUILTIN_VSUBAW = 1015,
- ARC_SIMD_BUILTIN_VSUBW = 1016,
- ARC_SIMD_BUILTIN_VSUMMW = 1017,
- ARC_SIMD_BUILTIN_VAND = 1018,
- ARC_SIMD_BUILTIN_VANDAW = 1019,
- ARC_SIMD_BUILTIN_VBIC = 1020,
- ARC_SIMD_BUILTIN_VBICAW = 1021,
- ARC_SIMD_BUILTIN_VOR = 1022,
- ARC_SIMD_BUILTIN_VXOR = 1023,
- ARC_SIMD_BUILTIN_VXORAW = 1024,
- ARC_SIMD_BUILTIN_VEQW = 1025,
- ARC_SIMD_BUILTIN_VLEW = 1026,
- ARC_SIMD_BUILTIN_VLTW = 1027,
- ARC_SIMD_BUILTIN_VNEW = 1028,
- ARC_SIMD_BUILTIN_VMR1AW = 1029,
- ARC_SIMD_BUILTIN_VMR1W = 1030,
- ARC_SIMD_BUILTIN_VMR2AW = 1031,
- ARC_SIMD_BUILTIN_VMR2W = 1032,
- ARC_SIMD_BUILTIN_VMR3AW = 1033,
- ARC_SIMD_BUILTIN_VMR3W = 1034,
- ARC_SIMD_BUILTIN_VMR4AW = 1035,
- ARC_SIMD_BUILTIN_VMR4W = 1036,
- ARC_SIMD_BUILTIN_VMR5AW = 1037,
- ARC_SIMD_BUILTIN_VMR5W = 1038,
- ARC_SIMD_BUILTIN_VMR6AW = 1039,
- ARC_SIMD_BUILTIN_VMR6W = 1040,
- ARC_SIMD_BUILTIN_VMR7AW = 1041,
- ARC_SIMD_BUILTIN_VMR7W = 1042,
- ARC_SIMD_BUILTIN_VMRB = 1043,
- ARC_SIMD_BUILTIN_VH264F = 1044,
- ARC_SIMD_BUILTIN_VH264FT = 1045,
- ARC_SIMD_BUILTIN_VH264FW = 1046,
- ARC_SIMD_BUILTIN_VVC1F = 1047,
- ARC_SIMD_BUILTIN_VVC1FT = 1048,
-
- /* Va, Vb, rlimm instructions. */
- ARC_SIMD_BUILTIN_VBADDW = 1050,
- ARC_SIMD_BUILTIN_VBMAXW = 1051,
- ARC_SIMD_BUILTIN_VBMINW = 1052,
- ARC_SIMD_BUILTIN_VBMULAW = 1053,
- ARC_SIMD_BUILTIN_VBMULFW = 1054,
- ARC_SIMD_BUILTIN_VBMULW = 1055,
- ARC_SIMD_BUILTIN_VBRSUBW = 1056,
- ARC_SIMD_BUILTIN_VBSUBW = 1057,
-
- /* Va, Vb, Ic instructions. */
- ARC_SIMD_BUILTIN_VASRW = 1060,
- ARC_SIMD_BUILTIN_VSR8 = 1061,
- ARC_SIMD_BUILTIN_VSR8AW = 1062,
-
- /* Va, Vb, u6 instructions. */
- ARC_SIMD_BUILTIN_VASRRWi = 1065,
- ARC_SIMD_BUILTIN_VASRSRWi = 1066,
- ARC_SIMD_BUILTIN_VASRWi = 1067,
- ARC_SIMD_BUILTIN_VASRPWBi = 1068,
- ARC_SIMD_BUILTIN_VASRRPWBi = 1069,
- ARC_SIMD_BUILTIN_VSR8AWi = 1070,
- ARC_SIMD_BUILTIN_VSR8i = 1071,
-
- /* Va, Vb, u8 (simm) instructions. */
- ARC_SIMD_BUILTIN_VMVAW = 1075,
- ARC_SIMD_BUILTIN_VMVW = 1076,
- ARC_SIMD_BUILTIN_VMVZW = 1077,
- ARC_SIMD_BUILTIN_VD6TAPF = 1078,
-
- /* Va, rlimm, u8 (simm) instructions. */
- ARC_SIMD_BUILTIN_VMOVAW = 1080,
- ARC_SIMD_BUILTIN_VMOVW = 1081,
- ARC_SIMD_BUILTIN_VMOVZW = 1082,
-
- /* Va, Vb instructions. */
- ARC_SIMD_BUILTIN_VABSAW = 1085,
- ARC_SIMD_BUILTIN_VABSW = 1086,
- ARC_SIMD_BUILTIN_VADDSUW = 1087,
- ARC_SIMD_BUILTIN_VSIGNW = 1088,
- ARC_SIMD_BUILTIN_VEXCH1 = 1089,
- ARC_SIMD_BUILTIN_VEXCH2 = 1090,
- ARC_SIMD_BUILTIN_VEXCH4 = 1091,
- ARC_SIMD_BUILTIN_VUPBAW = 1092,
- ARC_SIMD_BUILTIN_VUPBW = 1093,
- ARC_SIMD_BUILTIN_VUPSBAW = 1094,
- ARC_SIMD_BUILTIN_VUPSBW = 1095,
-
- ARC_SIMD_BUILTIN_VDIRUN = 1100,
- ARC_SIMD_BUILTIN_VDORUN = 1101,
- ARC_SIMD_BUILTIN_VDIWR = 1102,
- ARC_SIMD_BUILTIN_VDOWR = 1103,
-
- ARC_SIMD_BUILTIN_VREC = 1105,
- ARC_SIMD_BUILTIN_VRUN = 1106,
- ARC_SIMD_BUILTIN_VRECRUN = 1107,
- ARC_SIMD_BUILTIN_VENDREC = 1108,
-
- ARC_SIMD_BUILTIN_VLD32WH = 1110,
- ARC_SIMD_BUILTIN_VLD32WL = 1111,
- ARC_SIMD_BUILTIN_VLD64 = 1112,
- ARC_SIMD_BUILTIN_VLD32 = 1113,
- ARC_SIMD_BUILTIN_VLD64W = 1114,
- ARC_SIMD_BUILTIN_VLD128 = 1115,
- ARC_SIMD_BUILTIN_VST128 = 1116,
- ARC_SIMD_BUILTIN_VST64 = 1117,
-
- ARC_SIMD_BUILTIN_VST16_N = 1120,
- ARC_SIMD_BUILTIN_VST32_N = 1121,
-
- ARC_SIMD_BUILTIN_VINTI = 1201,
-
- ARC_SIMD_BUILTIN_END
-};
-
/* A nop is needed between a 4 byte insn that sets the condition codes and
a branch that uses them (the same isn't true for an 8 byte insn that sets
the condition codes). Set by arc_ccfsm_advance. Used by
static int branch_dest (rtx);
static void arc_output_pic_addr_const (FILE *, rtx, int);
-void emit_pic_move (rtx *, machine_mode);
bool arc_legitimate_pic_operand_p (rtx);
static bool arc_function_ok_for_sibcall (tree, tree);
static rtx arc_function_value (const_tree, const_tree, bool);
static void arc_init_reg_tables (void);
static bool arc_return_in_memory (const_tree, const_tree);
-static void arc_init_simd_builtins (void);
static bool arc_vector_mode_supported_p (machine_mode);
static bool arc_can_use_doloop_p (const widest_int &, const widest_int &,
enum by_pieces_operation op,
bool);
+static const arc_cpu_t *arc_selected_cpu;
+static const arc_arch_t *arc_selected_arch;
+
+/* Global var which sets the current compilation architecture. */
+enum base_architecture arc_base_cpu;
+
/* Implements target hook vector_mode_supported_p. */
static bool
arc_vector_mode_supported_p (machine_mode mode)
{
- if (!TARGET_SIMD_SET)
- return false;
+ switch (mode)
+ {
+ case V2HImode:
+ return TARGET_PLUS_DMPY;
+ case V4HImode:
+ case V2SImode:
+ return TARGET_PLUS_QMACW;
+ case V4SImode:
+ case V8HImode:
+ return TARGET_SIMD_SET;
- if ((mode == V4SImode)
- || (mode == V8HImode))
- return true;
+ default:
+ return false;
+ }
+}
- return false;
+/* Implements target hook TARGET_VECTORIZE_PREFERRED_SIMD_MODE. */
+
+static machine_mode
+arc_preferred_simd_mode (machine_mode mode)
+{
+ switch (mode)
+ {
+ case HImode:
+ return TARGET_PLUS_QMACW ? V4HImode : V2HImode;
+ case SImode:
+ return V2SImode;
+
+ default:
+ return word_mode;
+ }
}
+/* Implements target hook
+ TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_SIZES. */
+
+static unsigned int
+arc_autovectorize_vector_sizes (void)
+{
+ return TARGET_PLUS_QMACW ? (8 | 4) : 0;
+}
/* TARGET_PRESERVE_RELOAD_P is still awaiting patch re-evaluation / review. */
static bool arc_preserve_reload_p (rtx in) ATTRIBUTE_UNUSED;
#undef TARGET_EXPAND_BUILTIN
#define TARGET_EXPAND_BUILTIN arc_expand_builtin
+#undef TARGET_BUILTIN_DECL
+#define TARGET_BUILTIN_DECL arc_builtin_decl
+
#undef TARGET_ASM_OUTPUT_MI_THUNK
#define TARGET_ASM_OUTPUT_MI_THUNK arc_output_mi_thunk
#undef TARGET_VECTOR_MODE_SUPPORTED_P
#define TARGET_VECTOR_MODE_SUPPORTED_P arc_vector_mode_supported_p
+#undef TARGET_VECTORIZE_PREFERRED_SIMD_MODE
+#define TARGET_VECTORIZE_PREFERRED_SIMD_MODE arc_preferred_simd_mode
+
+#undef TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_SIZES
+#define TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_SIZES arc_autovectorize_vector_sizes
+
#undef TARGET_CAN_USE_DOLOOP_P
#define TARGET_CAN_USE_DOLOOP_P arc_can_use_doloop_p
#undef TARGET_ASM_ALIGNED_SI_OP
#define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
+#ifdef HAVE_AS_TLS
+#undef TARGET_HAVE_TLS
+#define TARGET_HAVE_TLS HAVE_AS_TLS
+#endif
+
+#undef TARGET_DWARF_REGISTER_SPAN
+#define TARGET_DWARF_REGISTER_SPAN arc_dwarf_register_span
+
/* Try to keep the (mov:DF _, reg) as early as possible so
that the d<add/sub/mul>h-lr insns appear together and can
use the peephole2 pattern. */
/* Called by OVERRIDE_OPTIONS to initialize various things. */
-void
+static void
arc_init (void)
{
- enum attr_tune tune_dflt = TUNE_NONE;
-
- switch (arc_cpu)
- {
- case PROCESSOR_ARC600:
- arc_cpu_string = "ARC600";
- tune_dflt = TUNE_ARC600;
- break;
-
- case PROCESSOR_ARC601:
- arc_cpu_string = "ARC601";
- tune_dflt = TUNE_ARC600;
- break;
-
- case PROCESSOR_ARC700:
- arc_cpu_string = "ARC700";
- tune_dflt = TUNE_ARC700_4_2_STD;
- break;
-
- case PROCESSOR_ARCEM:
- arc_cpu_string = "EM";
- break;
-
- case PROCESSOR_ARCHS:
- arc_cpu_string = "HS";
- break;
-
- default:
- gcc_unreachable ();
- }
-
- if (arc_tune == TUNE_NONE)
- arc_tune = tune_dflt;
/* Note: arc_multcost is only used in rtx_cost if speed is true. */
if (arc_multcost < 0)
switch (arc_tune)
break;
}
- /* Support mul64 generation only for ARC600. */
- if (TARGET_MUL64_SET && (!TARGET_ARC600_FAMILY))
- error ("-mmul64 not supported for ARC700 or ARCv2");
-
/* MPY instructions valid only for ARC700 or ARCv2. */
if (TARGET_NOMPY_SET && TARGET_ARC600_FAMILY)
error ("-mno-mpy supported only for ARC700 or ARCv2");
- /* mul/mac instructions only for ARC600. */
- if (TARGET_MULMAC_32BY16_SET && (!TARGET_ARC600_FAMILY))
- error ("-mmul32x16 supported only for ARC600 or ARC601");
-
if (!TARGET_DPFP && TARGET_DPFP_DISABLE_LRSR)
error ("-mno-dpfp-lrsr supported only with -mdpfp");
if (TARGET_SPFP_FAST_SET && TARGET_ARC600_FAMILY)
error ("-mspfp_fast not available on ARC600 or ARC601");
- /* FPX-3. No FPX extensions on pre-ARC600 cores. */
- if ((TARGET_DPFP || TARGET_SPFP)
- && !TARGET_ARCOMPACT_FAMILY)
- error ("FPX extensions not available on pre-ARC600 cores");
-
- /* Only selected multiplier configurations are available for HS. */
- if (TARGET_HS && ((arc_mpy_option > 2 && arc_mpy_option < 7)
- || (arc_mpy_option == 1)))
- error ("This multiplier configuration is not available for HS cores");
+ /* FPX-4. No FPX extensions mixed with FPU extensions. */
+ if ((TARGET_DPFP_FAST_SET || TARGET_DPFP_COMPACT_SET || TARGET_SPFP)
+ && TARGET_HARD_FLOAT)
+ error ("No FPX/FPU mixing allowed");
/* Warn for unimplemented PIC in pre-ARC700 cores, and disable flag_pic. */
if (flag_pic && TARGET_ARC600_FAMILY)
flag_pic = 0;
}
- if (TARGET_ATOMIC && !(TARGET_ARC700 || TARGET_HS))
- error ("-matomic is only supported for ARC700 or ARC HS cores");
-
arc_init_reg_tables ();
/* Initialize array for PRINT_OPERAND_PUNCT_VALID_P. */
arc_override_options (void)
{
if (arc_cpu == PROCESSOR_NONE)
- arc_cpu = PROCESSOR_ARC700;
+ arc_cpu = TARGET_CPU_DEFAULT;
+
+ /* Set the default cpu options. */
+ arc_selected_cpu = &arc_cpu_types[(int) arc_cpu];
+ arc_selected_arch = &arc_arch_types[(int) arc_selected_cpu->arch];
+ arc_base_cpu = arc_selected_arch->arch;
+
+ /* Set the architectures. */
+ switch (arc_selected_arch->arch)
+ {
+ case BASE_ARCH_em:
+ arc_cpu_string = "EM";
+ break;
+ case BASE_ARCH_hs:
+ arc_cpu_string = "HS";
+ break;
+ case BASE_ARCH_700:
+ if (arc_selected_cpu->processor == PROCESSOR_nps400)
+ arc_cpu_string = "NPS400";
+ else
+ arc_cpu_string = "ARC700";
+ break;
+ case BASE_ARCH_6xx:
+ arc_cpu_string = "ARC600";
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ /* Set cpu flags accordingly to architecture/selected cpu. The cpu
+ specific flags are set in arc-common.c. The architecture forces
+ the default hardware configurations in, regardless what command
+ line options are saying. The CPU optional hw options can be
+ turned on or off. */
+#define ARC_OPT(NAME, CODE, MASK, DOC) \
+ do { \
+ if ((arc_selected_cpu->flags & CODE) \
+ && ((target_flags_explicit & MASK) == 0)) \
+ target_flags |= MASK; \
+ if (arc_selected_arch->dflags & CODE) \
+ target_flags |= MASK; \
+ } while (0);
+#define ARC_OPTX(NAME, CODE, VAR, VAL, DOC) \
+ do { \
+ if ((arc_selected_cpu->flags & CODE) \
+ && (VAR == DEFAULT_##VAR)) \
+ VAR = VAL; \
+ if (arc_selected_arch->dflags & CODE) \
+ VAR = VAL; \
+ } while (0);
+
+#include "arc-options.def"
+
+#undef ARC_OPTX
+#undef ARC_OPT
+
+ /* Check options against architecture options. Throw an error if
+ option is not allowed. */
+#define ARC_OPTX(NAME, CODE, VAR, VAL, DOC) \
+ do { \
+ if ((VAR == VAL) \
+ && (!(arc_selected_arch->flags & CODE))) \
+ { \
+ error ("%s is not available for %s architecture", \
+ DOC, arc_selected_arch->name); \
+ } \
+ } while (0);
+#define ARC_OPT(NAME, CODE, MASK, DOC) \
+ do { \
+ if ((target_flags & MASK) \
+ && (!(arc_selected_arch->flags & CODE))) \
+ error ("%s is not available for %s architecture", \
+ DOC, arc_selected_arch->name); \
+ } while (0);
+
+#include "arc-options.def"
+
+#undef ARC_OPTX
+#undef ARC_OPT
+
+ /* Set Tune option. */
+ if (arc_tune == TUNE_NONE)
+ arc_tune = (enum attr_tune) arc_selected_cpu->tune;
if (arc_size_opt_level == 3)
optimize_size = 1;
+ /* Compact casesi is not a valid option for ARCv2 family. */
+ if (TARGET_V2)
+ {
+ if (TARGET_COMPACT_CASESI)
+ {
+ warning (0, "compact-casesi is not applicable to ARCv2");
+ TARGET_COMPACT_CASESI = 0;
+ }
+ }
+ else if (optimize_size == 1
+ && !global_options_set.x_TARGET_COMPACT_CASESI)
+ TARGET_COMPACT_CASESI = 1;
+
if (flag_pic)
target_flags |= MASK_NO_SDATA_SET;
case UNEQ : return ARC_CC_LS;
default : gcc_unreachable ();
}
+ case CC_FPUmode:
+ switch (GET_CODE (comparison))
+ {
+ case EQ : return ARC_CC_EQ;
+ case NE : return ARC_CC_NE;
+ case GT : return ARC_CC_GT;
+ case GE : return ARC_CC_GE;
+ case LT : return ARC_CC_C;
+ case LE : return ARC_CC_LS;
+ case UNORDERED : return ARC_CC_V;
+ case ORDERED : return ARC_CC_NV;
+ case UNGT : return ARC_CC_HI;
+ case UNGE : return ARC_CC_HS;
+ case UNLT : return ARC_CC_LT;
+ case UNLE : return ARC_CC_LE;
+ /* UNEQ and LTGT do not have representation. */
+ case LTGT : /* Fall through. */
+ case UNEQ : /* Fall through. */
+ default : gcc_unreachable ();
+ }
+ case CC_FPU_UNEQmode:
+ switch (GET_CODE (comparison))
+ {
+ case LTGT : return ARC_CC_NE;
+ case UNEQ : return ARC_CC_EQ;
+ default : gcc_unreachable ();
+ }
default : gcc_unreachable ();
}
/*NOTREACHED*/
return CC_FP_GEmode;
default: gcc_unreachable ();
}
- else if (GET_MODE_CLASS (mode) == MODE_FLOAT && TARGET_OPTFPE)
+ else if (TARGET_HARD_FLOAT
+ && ((mode == SFmode && TARGET_FP_SP_BASE)
+ || (mode == DFmode && TARGET_FP_DP_BASE)))
switch (op)
{
- case EQ: case NE: return CC_Zmode;
- case LT: case UNGE:
- case GT: case UNLE: return CC_FP_GTmode;
- case LE: case UNGT:
- case GE: case UNLT: return CC_FP_GEmode;
- case UNEQ: case LTGT: return CC_FP_UNEQmode;
- case ORDERED: case UNORDERED: return CC_FP_ORDmode;
- default: gcc_unreachable ();
- }
+ case EQ:
+ case NE:
+ case UNORDERED:
+ case ORDERED:
+ case UNLT:
+ case UNLE:
+ case UNGT:
+ case UNGE:
+ case LT:
+ case LE:
+ case GT:
+ case GE:
+ return CC_FPUmode;
+
+ case LTGT:
+ case UNEQ:
+ return CC_FPU_UNEQmode;
+ default:
+ gcc_unreachable ();
+ }
+ else if (GET_MODE_CLASS (mode) == MODE_FLOAT && TARGET_OPTFPE)
+ {
+ switch (op)
+ {
+ case EQ: case NE: return CC_Zmode;
+ case LT: case UNGE:
+ case GT: case UNLE: return CC_FP_GTmode;
+ case LE: case UNGT:
+ case GE: case UNLT: return CC_FP_GEmode;
+ case UNEQ: case LTGT: return CC_FP_UNEQmode;
+ case ORDERED: case UNORDERED: return CC_FP_ORDmode;
+ default: gcc_unreachable ();
+ }
+ }
return CCmode;
}
arc_mode_class[i] = 0;
break;
case MODE_VECTOR_INT:
- arc_mode_class [i] = (1<< (int) V_MODE);
+ if (GET_MODE_SIZE (m) == 4)
+ arc_mode_class[i] = (1 << (int) S_MODE);
+ else if (GET_MODE_SIZE (m) == 8)
+ arc_mode_class[i] = (1 << (int) D_MODE);
+ else
+ arc_mode_class[i] = (1 << (int) V_MODE);
break;
case MODE_CC:
default:
we must explicitly check for them here. */
if (i == (int) CCmode || i == (int) CC_ZNmode || i == (int) CC_Zmode
|| i == (int) CC_Cmode
- || i == CC_FP_GTmode || i == CC_FP_GEmode || i == CC_FP_ORDmode)
+ || i == CC_FP_GTmode || i == CC_FP_GEmode || i == CC_FP_ORDmode
+ || i == CC_FPUmode || i == CC_FPU_UNEQmode)
arc_mode_class[i] = 1 << (int) C_MODE;
else
arc_mode_class[i] = 0;
strcpy (rname58, TARGET_BIG_ENDIAN ? "mhi" : "mlo");
strcpy (rname59, TARGET_BIG_ENDIAN ? "mlo" : "mhi");
}
+
+ /* The nature of arc_tp_regno is actually something more like a global
+ register, however globalize_reg requires a declaration.
+ We use EPILOGUE_USES to compensate so that sets from
+ __builtin_set_frame_pointer are not deleted. */
+ if (arc_tp_regno != -1)
+ fixed_regs[arc_tp_regno] = call_used_regs[arc_tp_regno] = 1;
+
if (TARGET_MULMAC_32BY16_SET)
{
fix_start = 56;
arc_hard_regno_mode_ok[60] = 1 << (int) S_MODE;
}
+ /* ARCHS has 64-bit data-path which makes use of the even-odd paired
+ registers. */
+ if (TARGET_HS)
+ {
+ for (regno = 1; regno < 32; regno +=2)
+ {
+ arc_hard_regno_mode_ok[regno] = S_MODES;
+ }
+ }
+
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
if (i < 29)
{
- if (TARGET_Q_CLASS && ((i <= 3) || ((i >= 12) && (i <= 15))))
+ if ((TARGET_Q_CLASS || TARGET_RRQ_CLASS)
+ && ((i <= 3) || ((i >= 12) && (i <= 15))))
arc_regno_reg_class[i] = ARCOMPACT16_REGS;
else
arc_regno_reg_class[i] = GENERAL_REGS;
arc_regno_reg_class[i] = NO_REGS;
}
- /* ARCOMPACT16_REGS is empty, if TARGET_Q_CLASS has not been activated. */
+ /* ARCOMPACT16_REGS is empty, if TARGET_Q_CLASS / TARGET_RRQ_CLASS
+ has not been activated. */
+ if (!TARGET_Q_CLASS && !TARGET_RRQ_CLASS)
+ CLEAR_HARD_REG_SET(reg_class_contents [ARCOMPACT16_REGS]);
if (!TARGET_Q_CLASS)
- {
- CLEAR_HARD_REG_SET(reg_class_contents [ARCOMPACT16_REGS]);
- CLEAR_HARD_REG_SET(reg_class_contents [AC16_BASE_REGS]);
- }
+ CLEAR_HARD_REG_SET(reg_class_contents [AC16_BASE_REGS]);
gcc_assert (FIRST_PSEUDO_REGISTER >= 144);
/* pc : r63 */
arc_regno_reg_class[PROGRAM_COUNTER_REGNO] = GENERAL_REGS;
+
+ /*ARCV2 Accumulator. */
+ if (TARGET_V2
+ && (TARGET_FP_DP_FUSED || TARGET_FP_SP_FUSED))
+ {
+ arc_regno_reg_class[ACCL_REGNO] = WRITABLE_CORE_REGS;
+ arc_regno_reg_class[ACCH_REGNO] = WRITABLE_CORE_REGS;
+ SET_HARD_REG_BIT (reg_class_contents[WRITABLE_CORE_REGS], ACCL_REGNO);
+ SET_HARD_REG_BIT (reg_class_contents[WRITABLE_CORE_REGS], ACCH_REGNO);
+ SET_HARD_REG_BIT (reg_class_contents[CHEAP_CORE_REGS], ACCL_REGNO);
+ SET_HARD_REG_BIT (reg_class_contents[CHEAP_CORE_REGS], ACCH_REGNO);
+ arc_hard_regno_mode_ok[ACC_REG_FIRST] = D_MODES;
+ }
}
/* Handle an "interrupt" attribute; arguments as in
gen_rtx_REG (CC_FPXmode, 61),
const0_rtx)));
}
+ else if (TARGET_FPX_QUARK && (cmode == SFmode))
+ {
+ switch (code)
+ {
+ case NE: case EQ: case GT: case UNLE: case GE: case UNLT:
+ case UNEQ: case LTGT: case ORDERED: case UNORDERED:
+ break;
+ case LT: case UNGE: case LE: case UNGT:
+ code = swap_condition (code);
+ tmp = x;
+ x = y;
+ y = tmp;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ emit_insn (gen_cmp_quark (cc_reg,
+ gen_rtx_COMPARE (mode, x, y)));
+ }
+ else if (TARGET_HARD_FLOAT
+ && ((cmode == SFmode && TARGET_FP_SP_BASE)
+ || (cmode == DFmode && TARGET_FP_DP_BASE)))
+ emit_insn (gen_rtx_SET (cc_reg, gen_rtx_COMPARE (mode, x, y)));
else if (GET_MODE_CLASS (cmode) == MODE_FLOAT && TARGET_OPTFPE)
{
rtx op0 = gen_rtx_REG (cmode, 0);
/* We must treat `__builtin_va_alist' as an anonymous arg. */
next_cum = *get_cumulative_args (args_so_far);
- arc_function_arg_advance (pack_cumulative_args (&next_cum), mode, type, 1);
+ arc_function_arg_advance (pack_cumulative_args (&next_cum),
+ mode, type, true);
first_anon_arg = next_cum;
- if (first_anon_arg < MAX_ARC_PARM_REGS)
+ if (FUNCTION_ARG_REGNO_P (first_anon_arg))
{
/* First anonymous (unnamed) argument is in a reg. */
case LABEL_REF :
case SYMBOL_REF :
case CONST :
+ if (TARGET_NPS_CMEM && cmem_address (addr, SImode))
+ return 0;
/* Most likely needs a LIMM. */
return COSTS_N_INSNS (1);
for (regno = 0; regno <= 31; regno++)
{
- if ((gmask & (1L << regno)) != 0)
+ machine_mode mode = SImode;
+ bool found = false;
+
+ if (TARGET_LL64
+ && (regno % 2 == 0)
+ && ((gmask & (1L << regno)) != 0)
+ && ((gmask & (1L << (regno+1))) != 0))
+ {
+ found = true;
+ mode = DImode;
+ }
+ else if ((gmask & (1L << regno)) != 0)
{
- rtx reg = gen_rtx_REG (SImode, regno);
+ found = true;
+ mode = SImode;
+ }
+
+ if (found)
+ {
+ rtx reg = gen_rtx_REG (mode, regno);
rtx addr, mem;
int cfa_adjust = *first_offset;
gcc_assert (SMALL_INT (offset));
addr = plus_constant (Pmode, base_reg, offset);
}
- mem = gen_frame_mem (SImode, addr);
+ mem = gen_frame_mem (mode, addr);
if (epilogue_p)
{
rtx insn =
else
frame_move_inc (mem, reg, base_reg, addr);
offset += UNITS_PER_WORD;
+ if (mode == DImode)
+ {
+ offset += UNITS_PER_WORD;
+ ++regno;
+ }
} /* if */
} /* for */
}/* if */
/* PIC */
+/* Helper to generate unspec constant. */
+
+static rtx
+arc_unspec_offset (rtx loc, int unspec)
+{
+ return gen_rtx_CONST (Pmode, gen_rtx_UNSPEC (Pmode, gen_rtvec (1, loc),
+ unspec));
+}
+
/* Emit special PIC prologues and epilogues. */
/* If the function has any GOTOFF relocations, then the GOTBASE
register has to be setup in the prologue
gcc_assert (flag_pic != 0);
pat = gen_rtx_SYMBOL_REF (Pmode, "_DYNAMIC");
- pat = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, pat), ARC_UNSPEC_GOT);
- pat = gen_rtx_CONST (Pmode, pat);
-
+ pat = arc_unspec_offset (pat, ARC_UNSPEC_GOT);
pat = gen_rtx_SET (baseptr_rtx, pat);
emit_insn (pat);
'Z': log2(x+1)-1
'z': log2
'M': log2(~x)
+ 'p': bit Position of lsb
+ 's': size of bit field
'#': condbranch delay slot suffix
'*': jump delay slot suffix
'?' : nonjump-insn suffix for conditional execution or short instruction
return;
+ case 'p':
+ if (GET_CODE (x) == CONST_INT)
+ fprintf (file, "%d", exact_log2 (INTVAL (x) & -INTVAL (x)));
+ else
+ output_operand_lossage ("invalid operand to %%p code");
+ return;
+
+ case 's':
+ if (GET_CODE (x) == CONST_INT)
+ {
+ HOST_WIDE_INT i = INTVAL (x);
+ HOST_WIDE_INT s = exact_log2 (i & -i);
+ fprintf (file, "%d", exact_log2 (((0xffffffffUL & i) >> s) + 1));
+ }
+ else
+ output_operand_lossage ("invalid operand to %%s code");
+ return;
+
case '#' :
/* Conditional branches depending on condition codes.
Note that this is only for branches that were known to depend on
else if (GET_CODE (x) == CONST_INT
|| GET_CODE (x) == CONST_DOUBLE)
{
- rtx first, second;
+ rtx first, second, word;
split_double (x, &first, &second);
if((WORDS_BIG_ENDIAN) == 0)
- fprintf (file, "0x%08" PRIx64,
- code == 'L' ? INTVAL (first) : INTVAL (second));
+ word = (code == 'L' ? first : second);
else
- fprintf (file, "0x%08" PRIx64,
- code == 'L' ? INTVAL (second) : INTVAL (first));
-
+ word = (code == 'L' ? second : first);
- }
+ fprintf (file, "0x%08" PRIx32, ((uint32_t) INTVAL (word)));
+ }
else
output_operand_lossage ("invalid operand to %%H/%%L code");
return;
fprintf (file, "0x%08lx", l);
break;
}
- /* Fall through. Let output_addr_const deal with it. */
+ /* FALLTHRU */
+ /* Let output_addr_const deal with it. */
default :
- if (flag_pic)
+ if (flag_pic
+ || (GET_CODE (x) == CONST
+ && GET_CODE (XEXP (x, 0)) == UNSPEC
+ && (XINT (XEXP (x, 0), 1) == UNSPEC_TLS_OFF
+ || XINT (XEXP (x, 0), 1) == UNSPEC_TLS_GD))
+ || (GET_CODE (x) == CONST
+ && GET_CODE (XEXP (x, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (x, 0), 0)) == UNSPEC
+ && (XINT (XEXP (XEXP (x, 0), 0), 1) == UNSPEC_TLS_OFF
+ || XINT (XEXP (XEXP (x, 0), 0), 1) == UNSPEC_TLS_GD)))
arc_output_pic_addr_const (file, x, code);
else
{
{
rtx c = XEXP (addr, 0);
+ if ((GET_CODE (c) == UNSPEC
+ && (XINT (c, 1) == UNSPEC_TLS_OFF
+ || XINT (c, 1) == UNSPEC_TLS_IE))
+ || (GET_CODE (c) == PLUS
+ && GET_CODE (XEXP (c, 0)) == UNSPEC
+ && (XINT (XEXP (c, 0), 1) == UNSPEC_TLS_OFF
+ || XINT (XEXP (c, 0), 1) == ARC_UNSPEC_GOTOFFPC)))
+ {
+ arc_output_pic_addr_const (file, c, 0);
+ break;
+ }
+ gcc_assert (GET_CODE (c) == PLUS);
gcc_assert (GET_CODE (XEXP (c, 0)) == SYMBOL_REF);
gcc_assert (GET_CODE (XEXP (c, 1)) == CONST_INT);
}
}
-/* Called via walk_stores. DATA points to a hash table we can use to
- establish a unique SYMBOL_REF for each counter, which corresponds to
- a caller-callee pair.
- X is a store which we want to examine for an UNSPEC_PROF, which
- would be an address loaded into a register, or directly used in a MEM.
- If we found an UNSPEC_PROF, if we encounter a new counter the first time,
- write out a description and a data allocation for a 32 bit counter.
- Also, fill in the appropriate symbol_ref into each UNSPEC_PROF instance. */
-
-static void
-write_profile_sections (rtx dest ATTRIBUTE_UNUSED, rtx x, void *data)
-{
- rtx *srcp, src;
- htab_t htab = (htab_t) data;
- rtx *slot;
-
- if (GET_CODE (x) != SET)
- return;
- srcp = &SET_SRC (x);
- if (MEM_P (*srcp))
- srcp = &XEXP (*srcp, 0);
- else if (MEM_P (SET_DEST (x)))
- srcp = &XEXP (SET_DEST (x), 0);
- src = *srcp;
- if (GET_CODE (src) != CONST)
- return;
- src = XEXP (src, 0);
- if (GET_CODE (src) != UNSPEC || XINT (src, 1) != UNSPEC_PROF)
- return;
-
- gcc_assert (XVECLEN (src, 0) == 3);
- if (!htab_elements (htab))
- {
- output_asm_insn (".section .__arc_profile_desc, \"a\"\n"
- "\t.long %0 + 1\n",
- &XVECEXP (src, 0, 0));
- }
- slot = (rtx *) htab_find_slot (htab, src, INSERT);
- if (*slot == HTAB_EMPTY_ENTRY)
- {
- static int count_nr;
- char buf[24];
- rtx count;
-
- *slot = src;
- sprintf (buf, "__prof_count%d", count_nr++);
- count = gen_rtx_SYMBOL_REF (Pmode, xstrdup (buf));
- XVECEXP (src, 0, 2) = count;
- output_asm_insn (".section\t.__arc_profile_desc, \"a\"\n"
- "\t.long\t%1\n"
- "\t.section\t.__arc_profile_counters, \"aw\"\n"
- "\t.type\t%o2, @object\n"
- "\t.size\t%o2, 4\n"
- "%o2:\t.zero 4",
- &XVECEXP (src, 0, 0));
- *srcp = count;
- }
- else
- *srcp = XVECEXP (*slot, 0, 2);
-}
-
-/* Hash function for UNSPEC_PROF htab. Use both the caller's name and
- the callee's name (if known). */
-
-static hashval_t
-unspec_prof_hash (const void *x)
-{
- const_rtx u = (const_rtx) x;
- const_rtx s1 = XVECEXP (u, 0, 1);
-
- return (htab_hash_string (XSTR (XVECEXP (u, 0, 0), 0))
- ^ (s1->code == SYMBOL_REF ? htab_hash_string (XSTR (s1, 0)) : 0));
-}
-
-/* Equality function for UNSPEC_PROF htab. Two pieces of UNSPEC_PROF rtl
- shall refer to the same counter if both caller name and callee rtl
- are identical. */
-
-static int
-unspec_prof_htab_eq (const void *x, const void *y)
-{
- const_rtx u0 = (const_rtx) x;
- const_rtx u1 = (const_rtx) y;
- const_rtx s01 = XVECEXP (u0, 0, 1);
- const_rtx s11 = XVECEXP (u1, 0, 1);
-
- return (!strcmp (XSTR (XVECEXP (u0, 0, 0), 0),
- XSTR (XVECEXP (u1, 0, 0), 0))
- && rtx_equal_p (s01, s11));
-}
-
/* Conditional execution support.
This is based on the ARM port but for now is much simpler.
&& GET_CODE (PATTERN (insn)) != ADDR_VEC
&& GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC
&& ((type = get_attr_type (insn)) == TYPE_BRANCH
- || (type == TYPE_UNCOND_BRANCH
- /* ??? Maybe should also handle TYPE_RETURN here,
- but we don't have a testcase for that. */
+ || ((type == TYPE_UNCOND_BRANCH
+ || type == TYPE_RETURN)
&& ARC_CCFSM_BRANCH_DELETED_P (state))))
{
if (ARC_CCFSM_BRANCH_DELETED_P (state))
SYMBOL_REF_FLAGS (symbol) = flags;
}
+ else if (TREE_CODE (decl) == VAR_DECL)
+ {
+ rtx symbol = XEXP (rtl, 0);
+
+ tree attr = (TREE_TYPE (decl) != error_mark_node
+ ? DECL_ATTRIBUTES (decl) : NULL_TREE);
+
+ tree sec_attr = lookup_attribute ("section", attr);
+ if (sec_attr)
+ {
+ const char *sec_name
+ = TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (sec_attr)));
+ if (strcmp (sec_name, ".cmem") == 0
+ || strcmp (sec_name, ".cmem_shared") == 0
+ || strcmp (sec_name, ".cmem_private") == 0)
+ SYMBOL_REF_FLAGS (symbol) |= SYMBOL_FLAG_CMEM;
+ }
+ }
}
/* This is how to output a definition of an internal numbered label where
case CONST_DOUBLE:
{
- rtx high, low;
+ rtx first, second;
if (TARGET_DPFP)
{
*total = COSTS_N_INSNS (1);
return true;
}
- /* FIXME: correct the order of high,low */
- split_double (x, &high, &low);
- *total = COSTS_N_INSNS (!SMALL_INT (INTVAL (high))
- + !SMALL_INT (INTVAL (low)));
+ split_double (x, &first, &second);
+ *total = COSTS_N_INSNS (!SMALL_INT (INTVAL (first))
+ + !SMALL_INT (INTVAL (second)));
return true;
}
}
}
+/* Helper used by arc_legitimate_pc_offset_p. */
+
+static bool
+arc_needs_pcl_p (rtx x)
+{
+ register const char *fmt;
+ register int i, j;
+
+ if ((GET_CODE (x) == UNSPEC)
+ && (XVECLEN (x, 0) == 1)
+ && (GET_CODE (XVECEXP (x, 0, 0)) == SYMBOL_REF))
+ switch (XINT (x, 1))
+ {
+ case ARC_UNSPEC_GOT:
+ case ARC_UNSPEC_GOTOFFPC:
+ case UNSPEC_TLS_GD:
+ case UNSPEC_TLS_IE:
+ return true;
+ default:
+ break;
+ }
+
+ fmt = GET_RTX_FORMAT (GET_CODE (x));
+ for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ {
+ if (arc_needs_pcl_p (XEXP (x, i)))
+ return true;
+ }
+ else if (fmt[i] == 'E')
+ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ if (arc_needs_pcl_p (XVECEXP (x, i, j)))
+ return true;
+ }
+
+ return false;
+}
+
/* Return true if ADDR is an address that needs to be expressed as an
explicit sum of pcl + offset. */
{
if (GET_CODE (addr) != CONST)
return false;
- addr = XEXP (addr, 0);
- if (GET_CODE (addr) == PLUS)
- {
- if (GET_CODE (XEXP (addr, 1)) != CONST_INT)
- return false;
- addr = XEXP (addr, 0);
- }
- return (GET_CODE (addr) == UNSPEC
- && XVECLEN (addr, 0) == 1
- && XINT (addr, 1) == ARC_UNSPEC_GOT
- && GET_CODE (XVECEXP (addr, 0, 0)) == SYMBOL_REF);
+
+ return arc_needs_pcl_p (addr);
}
/* Return true if ADDR is a valid pic address.
|| XVECLEN (addr, 0) != 1)
return false;
- /* Must be @GOT or @GOTOFF. */
+ /* Must be one of @GOT, @GOTOFF, @GOTOFFPC, @tlsgd, tlsie. */
if (XINT (addr, 1) != ARC_UNSPEC_GOT
- && XINT (addr, 1) != ARC_UNSPEC_GOTOFF)
+ && XINT (addr, 1) != ARC_UNSPEC_GOTOFF
+ && XINT (addr, 1) != ARC_UNSPEC_GOTOFFPC
+ && XINT (addr, 1) != UNSPEC_TLS_GD
+ && XINT (addr, 1) != UNSPEC_TLS_IE)
return false;
if (GET_CODE (XVECEXP (addr, 0, 0)) != SYMBOL_REF
if (GET_CODE (op) == SYMBOL_REF)
{
+ if (SYMBOL_REF_TLS_MODEL (op))
+ return true;
+ if (!flag_pic)
+ return false;
tree decl = SYMBOL_REF_DECL (op);
return !skip_local || !decl || !default_binds_local_p (decl);
}
return false;
}
-/* Legitimize a pic address reference in ORIG.
- The return value is the legitimated address.
- If OLDX is non-zero, it is the target to assign the address to first. */
+/* Get the thread pointer. */
-rtx
-arc_legitimize_pic_address (rtx orig, rtx oldx)
+static rtx
+arc_get_tp (void)
{
- rtx addr = orig;
- rtx pat = orig;
- rtx base;
+ /* If arc_tp_regno has been set, we can use that hard register
+ directly as a base register. */
+ if (arc_tp_regno != -1)
+ return gen_rtx_REG (Pmode, arc_tp_regno);
- if (oldx == orig)
- oldx = NULL;
+ /* Otherwise, call __read_tp. Copy the result to a pseudo to avoid
+ conflicts with function arguments / results. */
+ rtx reg = gen_reg_rtx (Pmode);
+ emit_insn (gen_tls_load_tp_soft ());
+ emit_move_insn (reg, gen_rtx_REG (Pmode, R0_REG));
+ return reg;
+}
- if (GET_CODE (addr) == LABEL_REF)
- ; /* Do nothing. */
- else if (GET_CODE (addr) == SYMBOL_REF
- && (CONSTANT_POOL_ADDRESS_P (addr)
- || SYMBOL_REF_LOCAL_P (addr)))
- {
- /* This symbol may be referenced via a displacement from the PIC
- base address (@GOTOFF). */
+/* Helper to be used by TLS Global dynamic model. */
- /* FIXME: if we had a way to emit pc-relative adds that don't
- create a GOT entry, we could do without the use of the gp register. */
- crtl->uses_pic_offset_table = 1;
- pat = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), ARC_UNSPEC_GOTOFF);
- pat = gen_rtx_CONST (Pmode, pat);
- pat = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, pat);
+static rtx
+arc_emit_call_tls_get_addr (rtx sym, int reloc, rtx eqv)
+{
+ rtx r0 = gen_rtx_REG (Pmode, R0_REG);
+ rtx call_fusage = NULL_RTX;
- if (oldx == NULL)
- oldx = gen_reg_rtx (Pmode);
+ start_sequence ();
- if (oldx != 0)
- {
- emit_move_insn (oldx, pat);
- pat = oldx;
- }
+ rtx x = arc_unspec_offset (sym, reloc);
+ emit_move_insn (r0, x);
+ use_reg (&call_fusage, r0);
- }
- else if (GET_CODE (addr) == SYMBOL_REF)
- {
- /* This symbol must be referenced via a load from the
- Global Offset Table (@GOTPC). */
+ gcc_assert (reloc == UNSPEC_TLS_GD);
+ rtx call_insn = emit_call_insn (gen_tls_gd_get_addr (sym));
+ /* Should we set RTL_CONST_CALL_P? We read memory, but not in a
+ way that the application should care. */
+ RTL_PURE_CALL_P (call_insn) = 1;
+ add_function_usage_to (call_insn, call_fusage);
- pat = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), ARC_UNSPEC_GOT);
- pat = gen_rtx_CONST (Pmode, pat);
- pat = gen_const_mem (Pmode, pat);
+ rtx_insn *insns = get_insns ();
+ end_sequence ();
- if (oldx == 0)
- oldx = gen_reg_rtx (Pmode);
+ rtx dest = gen_reg_rtx (Pmode);
+ emit_libcall_block (insns, dest, r0, eqv);
+ return dest;
+}
+
+#define DTPOFF_ZERO_SYM ".tdata"
+
+/* Return a legitimized address for ADDR,
+ which is a SYMBOL_REF with tls_model MODEL. */
+
+static rtx
+arc_legitimize_tls_address (rtx addr, enum tls_model model)
+{
+ if (!flag_pic && model == TLS_MODEL_LOCAL_DYNAMIC)
+ model = TLS_MODEL_LOCAL_EXEC;
+
+ switch (model)
+ {
+ case TLS_MODEL_LOCAL_DYNAMIC:
+ rtx base;
+ tree decl;
+ const char *base_name;
+ rtvec v;
+
+ decl = SYMBOL_REF_DECL (addr);
+ base_name = DTPOFF_ZERO_SYM;
+ if (decl && bss_initializer_p (decl))
+ base_name = ".tbss";
+
+ base = gen_rtx_SYMBOL_REF (Pmode, base_name);
+ if (strcmp (base_name, DTPOFF_ZERO_SYM) == 0)
+ {
+ if (!flag_pic)
+ goto local_exec;
+ v = gen_rtvec (1, addr);
+ }
+ else
+ v = gen_rtvec (2, addr, base);
+ addr = gen_rtx_UNSPEC (Pmode, v, UNSPEC_TLS_OFF);
+ addr = gen_rtx_CONST (Pmode, addr);
+ base = arc_legitimize_tls_address (base, TLS_MODEL_GLOBAL_DYNAMIC);
+ return gen_rtx_PLUS (Pmode, force_reg (Pmode, base), addr);
+
+ case TLS_MODEL_GLOBAL_DYNAMIC:
+ return arc_emit_call_tls_get_addr (addr, UNSPEC_TLS_GD, addr);
+
+ case TLS_MODEL_INITIAL_EXEC:
+ addr = arc_unspec_offset (addr, UNSPEC_TLS_IE);
+ addr = copy_to_mode_reg (Pmode, gen_const_mem (Pmode, addr));
+ return gen_rtx_PLUS (Pmode, arc_get_tp (), addr);
+
+ case TLS_MODEL_LOCAL_EXEC:
+ local_exec:
+ addr = arc_unspec_offset (addr, UNSPEC_TLS_OFF);
+ return gen_rtx_PLUS (Pmode, arc_get_tp (), addr);
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Legitimize a pic address reference in ORIG.
+ The return value is the legitimated address.
+ If OLDX is non-zero, it is the target to assign the address to first. */
+
+static rtx
+arc_legitimize_pic_address (rtx orig, rtx oldx)
+{
+ rtx addr = orig;
+ rtx pat = orig;
+ rtx base;
+
+ if (oldx == orig)
+ oldx = NULL;
+
+ if (GET_CODE (addr) == LABEL_REF)
+ ; /* Do nothing. */
+ else if (GET_CODE (addr) == SYMBOL_REF)
+ {
+ enum tls_model model = SYMBOL_REF_TLS_MODEL (addr);
+ if (model != 0)
+ return arc_legitimize_tls_address (addr, model);
+ else if (!flag_pic)
+ return orig;
+ else if (CONSTANT_POOL_ADDRESS_P (addr) || SYMBOL_REF_LOCAL_P (addr))
+ return arc_unspec_offset (addr, ARC_UNSPEC_GOTOFFPC);
+
+ /* This symbol must be referenced via a load from the Global
+ Offset Table (@GOTPC). */
+ pat = arc_unspec_offset (addr, ARC_UNSPEC_GOT);
+ pat = gen_const_mem (Pmode, pat);
+
+ if (oldx == NULL)
+ oldx = gen_reg_rtx (Pmode);
emit_move_insn (oldx, pat);
pat = oldx;
if (GET_CODE (addr) == UNSPEC)
{
/* Check that the unspec is one of the ones we generate? */
+ return orig;
}
else
gcc_assert (GET_CODE (addr) == PLUS);
{
rtx op0 = XEXP (addr, 0), op1 = XEXP (addr, 1);
- /* Check first to see if this is a constant offset from a @GOTOFF
- symbol reference. */
- if ((GET_CODE (op0) == LABEL_REF
- || (GET_CODE (op0) == SYMBOL_REF
- && (CONSTANT_POOL_ADDRESS_P (op0)
- || SYMBOL_REF_LOCAL_P (op0))))
- && GET_CODE (op1) == CONST_INT)
- {
- /* FIXME: like above, could do without gp reference. */
- crtl->uses_pic_offset_table = 1;
- pat
- = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op0), ARC_UNSPEC_GOTOFF);
- pat = gen_rtx_PLUS (Pmode, pat, op1);
- pat = gen_rtx_CONST (Pmode, pat);
- pat = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, pat);
-
- if (oldx != 0)
- {
- emit_move_insn (oldx, pat);
- pat = oldx;
- }
- }
- else
- {
- base = arc_legitimize_pic_address (XEXP (addr, 0), oldx);
- pat = arc_legitimize_pic_address (XEXP (addr, 1),
+ base = arc_legitimize_pic_address (op0, oldx);
+ pat = arc_legitimize_pic_address (op1,
base == oldx ? NULL_RTX : oldx);
- if (GET_CODE (pat) == CONST_INT)
- pat = plus_constant (Pmode, base, INTVAL (pat));
- else
+ if (base == op0 && pat == op1)
+ return orig;
+
+ if (GET_CODE (pat) == CONST_INT)
+ pat = plus_constant (Pmode, base, INTVAL (pat));
+ else
+ {
+ if (GET_CODE (pat) == PLUS && CONSTANT_P (XEXP (pat, 1)))
{
- if (GET_CODE (pat) == PLUS && CONSTANT_P (XEXP (pat, 1)))
- {
- base = gen_rtx_PLUS (Pmode, base, XEXP (pat, 0));
- pat = XEXP (pat, 1);
- }
- pat = gen_rtx_PLUS (Pmode, base, pat);
+ base = gen_rtx_PLUS (Pmode, base, XEXP (pat, 0));
+ pat = XEXP (pat, 1);
}
+ pat = gen_rtx_PLUS (Pmode, base, pat);
}
}
}
case UNSPEC:
- gcc_assert (XVECLEN (x, 0) == 1);
- if (XINT (x, 1) == ARC_UNSPEC_GOT)
- fputs ("pcl,", file);
- arc_output_pic_addr_const (file, XVECEXP (x, 0, 0), code);
+ const char *suffix;
+ bool pcrel; pcrel = false;
+ rtx base; base = NULL;
+ gcc_assert (XVECLEN (x, 0) >= 1);
switch (XINT (x, 1))
{
case ARC_UNSPEC_GOT:
- fputs ("@gotpc", file);
+ suffix = "@gotpc", pcrel = true;
break;
case ARC_UNSPEC_GOTOFF:
- fputs ("@gotoff", file);
+ suffix = "@gotoff";
+ break;
+ case ARC_UNSPEC_GOTOFFPC:
+ suffix = "@pcl", pcrel = true;
break;
case ARC_UNSPEC_PLT:
- fputs ("@plt", file);
+ suffix = "@plt";
+ break;
+ case UNSPEC_TLS_GD:
+ suffix = "@tlsgd", pcrel = true;
+ break;
+ case UNSPEC_TLS_IE:
+ suffix = "@tlsie", pcrel = true;
+ break;
+ case UNSPEC_TLS_OFF:
+ if (XVECLEN (x, 0) == 2)
+ base = XVECEXP (x, 0, 1);
+ if (SYMBOL_REF_TLS_MODEL (XVECEXP (x, 0, 0)) == TLS_MODEL_LOCAL_EXEC
+ || (!flag_pic && !base))
+ suffix = "@tpoff";
+ else
+ suffix = "@dtpoff";
break;
default:
+ suffix = "@invalid";
output_operand_lossage ("invalid UNSPEC as operand: %d", XINT (x,1));
break;
}
- break;
+ if (pcrel)
+ fputs ("pcl,", file);
+ arc_output_pic_addr_const (file, XVECEXP (x, 0, 0), code);
+ fputs (suffix, file);
+ if (base)
+ arc_output_pic_addr_const (file, base, code);
+ break;
default:
output_operand_lossage ("invalid expression as operand");
/* Emit insns to move operands[1] into operands[0]. */
-void
-emit_pic_move (rtx *operands, machine_mode)
+static void
+prepare_pic_move (rtx *operands, machine_mode)
{
- rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode);
-
- if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1]))
+ if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1])
+ && flag_pic)
operands[1] = force_reg (Pmode, operands[1]);
else
- operands[1] = arc_legitimize_pic_address (operands[1], temp);
+ {
+ rtx temp = (reload_in_progress ? operands[0]
+ : flag_pic? gen_reg_rtx (Pmode) : NULL_RTX);
+ operands[1] = arc_legitimize_pic_address (operands[1], temp);
+ }
}
return ret;
}
-
-
/* This function is used to control a function argument is passed in a
register, and which register.
and the rest are pushed. */
static rtx
-arc_function_arg (cumulative_args_t cum_v, machine_mode mode,
- const_tree type ATTRIBUTE_UNUSED, bool named ATTRIBUTE_UNUSED)
+arc_function_arg (cumulative_args_t cum_v,
+ machine_mode mode,
+ const_tree type ATTRIBUTE_UNUSED,
+ bool named ATTRIBUTE_UNUSED)
{
CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
int arg_num = *cum;
course function_arg_partial_nregs will come into play. */
static void
-arc_function_arg_advance (cumulative_args_t cum_v, machine_mode mode,
- const_tree type, bool named ATTRIBUTE_UNUSED)
+arc_function_arg_advance (cumulative_args_t cum_v,
+ machine_mode mode,
+ const_tree type,
+ bool named ATTRIBUTE_UNUSED)
{
CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
int bytes = (mode == BLKmode
satisfies CONSTANT_P. */
bool
-arc_legitimate_constant_p (machine_mode, rtx x)
+arc_legitimate_constant_p (machine_mode mode, rtx x)
{
- if (!flag_pic)
+ if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x))
+ return false;
+
+ if (!flag_pic && mode != Pmode)
return true;
switch (GET_CODE (x))
if (GET_CODE (x) == PLUS)
{
- if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+ if (flag_pic
+ ? GET_CODE (XEXP (x, 1)) != CONST_INT
+ : !arc_legitimate_constant_p (mode, XEXP (x, 1)))
return false;
x = XEXP (x, 0);
}
{
case ARC_UNSPEC_PLT:
case ARC_UNSPEC_GOTOFF:
+ case ARC_UNSPEC_GOTOFFPC:
case ARC_UNSPEC_GOT:
- case UNSPEC_PROF:
+ case UNSPEC_TLS_GD:
+ case UNSPEC_TLS_IE:
+ case UNSPEC_TLS_OFF:
return true;
default:
/* Return true. */
break;
- case LABEL_REF:
case SYMBOL_REF:
- return false;
+ if (SYMBOL_REF_TLS_MODEL (x))
+ return false;
+ /* Fall through. */
+ case LABEL_REF:
+ if (flag_pic)
+ return false;
+ /* Fall through. */
default:
break;
return true;
if (GET_CODE (x) == CONST_INT && LARGE_INT (INTVAL (x)))
return true;
- if ((GET_MODE_SIZE (mode) != 16)
- && (GET_CODE (x) == SYMBOL_REF
- || GET_CODE (x) == LABEL_REF
- || GET_CODE (x) == CONST))
+
+ /* When we compile for size avoid const (@sym + offset)
+ addresses. */
+ if (!flag_pic && optimize_size && !reload_completed
+ && (GET_CODE (x) == CONST)
+ && (GET_CODE (XEXP (x, 0)) == PLUS)
+ && (GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF)
+ && SYMBOL_REF_TLS_MODEL (XEXP (XEXP (x, 0), 0)) == 0
+ && !SYMBOL_REF_FUNCTION_P (XEXP (XEXP (x, 0), 0)))
{
- if (!flag_pic || arc_legitimate_pic_addr_p (x))
+ rtx addend = XEXP (XEXP (x, 0), 1);
+ gcc_assert (CONST_INT_P (addend));
+ HOST_WIDE_INT offset = INTVAL (addend);
+
+ /* Allow addresses having a large offset to pass. Anyhow they
+ will end in a limm. */
+ return !(offset > -1024 && offset < 1020);
+ }
+
+ if ((GET_MODE_SIZE (mode) != 16) && CONSTANT_P (x))
+ {
+ if (flag_pic ? arc_legitimate_pic_addr_p (x)
+ : arc_legitimate_constant_p (Pmode, x))
return true;
}
if ((GET_CODE (x) == PRE_DEC || GET_CODE (x) == PRE_INC
return !arc_legitimate_constant_p (mode, x);
}
+/* IDs for all the ARC builtins. */
+
+enum arc_builtin_id
+ {
+#define DEF_BUILTIN(NAME, N_ARGS, TYPE, ICODE, MASK) \
+ ARC_BUILTIN_ ## NAME,
+#include "builtins.def"
+#undef DEF_BUILTIN
+
+ ARC_BUILTIN_COUNT
+ };
+
+struct GTY(()) arc_builtin_description
+{
+ enum insn_code icode;
+ int n_args;
+ tree fndecl;
+};
+
+static GTY(()) struct arc_builtin_description
+arc_bdesc[ARC_BUILTIN_COUNT] =
+{
+#define DEF_BUILTIN(NAME, N_ARGS, TYPE, ICODE, MASK) \
+ { (enum insn_code) CODE_FOR_ ## ICODE, N_ARGS, NULL_TREE },
+#include "builtins.def"
+#undef DEF_BUILTIN
+};
+
+/* Transform UP into lowercase and write the result to LO.
+ You must provide enough space for LO. Return LO. */
+
+static char*
+arc_tolower (char *lo, const char *up)
+{
+ char *lo0 = lo;
+
+ for (; *up; up++, lo++)
+ *lo = TOLOWER (*up);
+
+ *lo = '\0';
+
+ return lo0;
+}
+
+/* Implement `TARGET_BUILTIN_DECL'. */
-/* Generic function to define a builtin. */
-#define def_mbuiltin(MASK, NAME, TYPE, CODE) \
- do \
- { \
- if (MASK) \
- add_builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, NULL, NULL_TREE); \
- } \
- while (0)
+static tree
+arc_builtin_decl (unsigned id, bool initialize_p ATTRIBUTE_UNUSED)
+{
+ if (id < ARC_BUILTIN_COUNT)
+ return arc_bdesc[id].fndecl;
+ return error_mark_node;
+}
static void
arc_init_builtins (void)
{
- tree endlink = void_list_node;
-
- tree void_ftype_void
- = build_function_type (void_type_node,
- endlink);
-
- tree int_ftype_int
- = build_function_type (integer_type_node,
- tree_cons (NULL_TREE, integer_type_node, endlink));
-
- tree pcvoid_type_node
- = build_pointer_type (build_qualified_type (void_type_node, TYPE_QUAL_CONST));
- tree int_ftype_pcvoid_int
- = build_function_type (integer_type_node,
- tree_cons (NULL_TREE, pcvoid_type_node,
- tree_cons (NULL_TREE, integer_type_node,
- endlink)));
-
- tree int_ftype_short_int
- = build_function_type (integer_type_node,
- tree_cons (NULL_TREE, short_integer_type_node, endlink));
-
- tree void_ftype_int_int
- = build_function_type (void_type_node,
- tree_cons (NULL_TREE, integer_type_node,
- tree_cons (NULL_TREE, integer_type_node, endlink)));
- tree void_ftype_usint_usint
- = build_function_type (void_type_node,
- tree_cons (NULL_TREE, long_unsigned_type_node,
- tree_cons (NULL_TREE, long_unsigned_type_node, endlink)));
-
- tree int_ftype_int_int
- = build_function_type (integer_type_node,
- tree_cons (NULL_TREE, integer_type_node,
- tree_cons (NULL_TREE, integer_type_node, endlink)));
-
- tree usint_ftype_usint
- = build_function_type (long_unsigned_type_node,
- tree_cons (NULL_TREE, long_unsigned_type_node, endlink));
-
- tree void_ftype_usint
- = build_function_type (void_type_node,
- tree_cons (NULL_TREE, long_unsigned_type_node, endlink));
-
- /* Add the builtins. */
- def_mbuiltin (1,"__builtin_arc_nop", void_ftype_void, ARC_BUILTIN_NOP);
- def_mbuiltin (TARGET_NORM, "__builtin_arc_norm", int_ftype_int, ARC_BUILTIN_NORM);
- def_mbuiltin (TARGET_NORM, "__builtin_arc_normw", int_ftype_short_int, ARC_BUILTIN_NORMW);
- def_mbuiltin (TARGET_SWAP, "__builtin_arc_swap", int_ftype_int, ARC_BUILTIN_SWAP);
- def_mbuiltin (TARGET_MUL64_SET,"__builtin_arc_mul64", void_ftype_int_int, ARC_BUILTIN_MUL64);
- def_mbuiltin (TARGET_MUL64_SET,"__builtin_arc_mulu64", void_ftype_usint_usint, ARC_BUILTIN_MULU64);
- def_mbuiltin (1,"__builtin_arc_rtie", void_ftype_void, ARC_BUILTIN_RTIE);
- def_mbuiltin (TARGET_ARC700,"__builtin_arc_sync", void_ftype_void, ARC_BUILTIN_SYNC);
- def_mbuiltin ((TARGET_EA_SET),"__builtin_arc_divaw", int_ftype_int_int, ARC_BUILTIN_DIVAW);
- def_mbuiltin (1,"__builtin_arc_brk", void_ftype_void, ARC_BUILTIN_BRK);
- def_mbuiltin (1,"__builtin_arc_flag", void_ftype_usint, ARC_BUILTIN_FLAG);
- def_mbuiltin (1,"__builtin_arc_sleep", void_ftype_usint, ARC_BUILTIN_SLEEP);
- def_mbuiltin (1,"__builtin_arc_swi", void_ftype_void, ARC_BUILTIN_SWI);
- def_mbuiltin (1,"__builtin_arc_core_read", usint_ftype_usint, ARC_BUILTIN_CORE_READ);
- def_mbuiltin (1,"__builtin_arc_core_write", void_ftype_usint_usint, ARC_BUILTIN_CORE_WRITE);
- def_mbuiltin (1,"__builtin_arc_lr", usint_ftype_usint, ARC_BUILTIN_LR);
- def_mbuiltin (1,"__builtin_arc_sr", void_ftype_usint_usint, ARC_BUILTIN_SR);
- def_mbuiltin (TARGET_ARC700,"__builtin_arc_trap_s", void_ftype_usint, ARC_BUILTIN_TRAP_S);
- def_mbuiltin (TARGET_ARC700,"__builtin_arc_unimp_s", void_ftype_void, ARC_BUILTIN_UNIMP_S);
- def_mbuiltin (1,"__builtin_arc_aligned", int_ftype_pcvoid_int, ARC_BUILTIN_ALIGNED);
-
- if (TARGET_SIMD_SET)
- arc_init_simd_builtins ();
-}
-
-static rtx arc_expand_simd_builtin (tree, rtx, rtx, machine_mode, int);
+ tree V4HI_type_node;
+ tree V2SI_type_node;
+ tree V2HI_type_node;
+
+ /* Vector types based on HS SIMD elements. */
+ V4HI_type_node = build_vector_type_for_mode (intHI_type_node, V4HImode);
+ V2SI_type_node = build_vector_type_for_mode (intSI_type_node, V2SImode);
+ V2HI_type_node = build_vector_type_for_mode (intHI_type_node, V2HImode);
+
+ tree pcvoid_type_node
+ = build_pointer_type (build_qualified_type (void_type_node,
+ TYPE_QUAL_CONST));
+ tree V8HI_type_node = build_vector_type_for_mode (intHI_type_node,
+ V8HImode);
+
+ tree void_ftype_void
+ = build_function_type_list (void_type_node, NULL_TREE);
+ tree int_ftype_int
+ = build_function_type_list (integer_type_node, integer_type_node,
+ NULL_TREE);
+ tree int_ftype_pcvoid_int
+ = build_function_type_list (integer_type_node, pcvoid_type_node,
+ integer_type_node, NULL_TREE);
+ tree void_ftype_usint_usint
+ = build_function_type_list (void_type_node, long_unsigned_type_node,
+ long_unsigned_type_node, NULL_TREE);
+ tree int_ftype_int_int
+ = build_function_type_list (integer_type_node, integer_type_node,
+ integer_type_node, NULL_TREE);
+ tree usint_ftype_usint
+ = build_function_type_list (long_unsigned_type_node,
+ long_unsigned_type_node, NULL_TREE);
+ tree void_ftype_usint
+ = build_function_type_list (void_type_node, long_unsigned_type_node,
+ NULL_TREE);
+ tree int_ftype_void
+ = build_function_type_list (integer_type_node, void_type_node,
+ NULL_TREE);
+ tree void_ftype_int
+ = build_function_type_list (void_type_node, integer_type_node,
+ NULL_TREE);
+ tree int_ftype_short
+ = build_function_type_list (integer_type_node, short_integer_type_node,
+ NULL_TREE);
+
+ /* Old ARC SIMD types. */
+ tree v8hi_ftype_v8hi_v8hi
+ = build_function_type_list (V8HI_type_node, V8HI_type_node,
+ V8HI_type_node, NULL_TREE);
+ tree v8hi_ftype_v8hi_int
+ = build_function_type_list (V8HI_type_node, V8HI_type_node,
+ integer_type_node, NULL_TREE);
+ tree v8hi_ftype_v8hi_int_int
+ = build_function_type_list (V8HI_type_node, V8HI_type_node,
+ integer_type_node, integer_type_node,
+ NULL_TREE);
+ tree void_ftype_v8hi_int_int
+ = build_function_type_list (void_type_node, V8HI_type_node,
+ integer_type_node, integer_type_node,
+ NULL_TREE);
+ tree void_ftype_v8hi_int_int_int
+ = build_function_type_list (void_type_node, V8HI_type_node,
+ integer_type_node, integer_type_node,
+ integer_type_node, NULL_TREE);
+ tree v8hi_ftype_int_int
+ = build_function_type_list (V8HI_type_node, integer_type_node,
+ integer_type_node, NULL_TREE);
+ tree void_ftype_int_int
+ = build_function_type_list (void_type_node, integer_type_node,
+ integer_type_node, NULL_TREE);
+ tree v8hi_ftype_v8hi
+ = build_function_type_list (V8HI_type_node, V8HI_type_node,
+ NULL_TREE);
+ /* ARCv2 SIMD types. */
+ tree long_ftype_v4hi_v4hi
+ = build_function_type_list (long_long_integer_type_node,
+ V4HI_type_node, V4HI_type_node, NULL_TREE);
+ tree int_ftype_v2hi_v2hi
+ = build_function_type_list (integer_type_node,
+ V2HI_type_node, V2HI_type_node, NULL_TREE);
+ tree v2si_ftype_v2hi_v2hi
+ = build_function_type_list (V2SI_type_node,
+ V2HI_type_node, V2HI_type_node, NULL_TREE);
+ tree v2hi_ftype_v2hi_v2hi
+ = build_function_type_list (V2HI_type_node,
+ V2HI_type_node, V2HI_type_node, NULL_TREE);
+ tree v2si_ftype_v2si_v2si
+ = build_function_type_list (V2SI_type_node,
+ V2SI_type_node, V2SI_type_node, NULL_TREE);
+ tree v4hi_ftype_v4hi_v4hi
+ = build_function_type_list (V4HI_type_node,
+ V4HI_type_node, V4HI_type_node, NULL_TREE);
+ tree long_ftype_v2si_v2hi
+ = build_function_type_list (long_long_integer_type_node,
+ V2SI_type_node, V2HI_type_node, NULL_TREE);
+
+ /* Add the builtins. */
+#define DEF_BUILTIN(NAME, N_ARGS, TYPE, ICODE, MASK) \
+ { \
+ int id = ARC_BUILTIN_ ## NAME; \
+ const char *Name = "__builtin_arc_" #NAME; \
+ char *name = (char*) alloca (1 + strlen (Name)); \
+ \
+ gcc_assert (id < ARC_BUILTIN_COUNT); \
+ if (MASK) \
+ arc_bdesc[id].fndecl \
+ = add_builtin_function (arc_tolower(name, Name), TYPE, id, \
+ BUILT_IN_MD, NULL, NULL_TREE); \
+ }
+#include "builtins.def"
+#undef DEF_BUILTIN
+}
+
+/* Helper to expand __builtin_arc_aligned (void* val, int
+ alignval). */
+
+static rtx
+arc_expand_builtin_aligned (tree exp)
+{
+ tree arg0 = CALL_EXPR_ARG (exp, 0);
+ tree arg1 = CALL_EXPR_ARG (exp, 1);
+ fold (arg1);
+ rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+ rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+
+ if (!CONST_INT_P (op1))
+ {
+ /* If we can't fold the alignment to a constant integer
+ whilst optimizing, this is probably a user error. */
+ if (optimize)
+ warning (0, "__builtin_arc_aligned with non-constant alignment");
+ }
+ else
+ {
+ HOST_WIDE_INT alignTest = INTVAL (op1);
+ /* Check alignTest is positive, and a power of two. */
+ if (alignTest <= 0 || alignTest != (alignTest & -alignTest))
+ {
+ error ("invalid alignment value for __builtin_arc_aligned");
+ return NULL_RTX;
+ }
+
+ if (CONST_INT_P (op0))
+ {
+ HOST_WIDE_INT pnt = INTVAL (op0);
+
+ if ((pnt & (alignTest - 1)) == 0)
+ return const1_rtx;
+ }
+ else
+ {
+ unsigned align = get_pointer_alignment (arg0);
+ unsigned numBits = alignTest * BITS_PER_UNIT;
+
+ if (align && align >= numBits)
+ return const1_rtx;
+ /* Another attempt to ascertain alignment. Check the type
+ we are pointing to. */
+ if (POINTER_TYPE_P (TREE_TYPE (arg0))
+ && TYPE_ALIGN (TREE_TYPE (TREE_TYPE (arg0))) >= numBits)
+ return const1_rtx;
+ }
+ }
+
+ /* Default to false. */
+ return const0_rtx;
+}
+
+/* Helper arc_expand_builtin, generates a pattern for the given icode
+ and arguments. */
+
+static rtx_insn *
+apply_GEN_FCN (enum insn_code icode, rtx *arg)
+{
+ switch (insn_data[icode].n_generator_args)
+ {
+ case 0:
+ return GEN_FCN (icode) ();
+ case 1:
+ return GEN_FCN (icode) (arg[0]);
+ case 2:
+ return GEN_FCN (icode) (arg[0], arg[1]);
+ case 3:
+ return GEN_FCN (icode) (arg[0], arg[1], arg[2]);
+ case 4:
+ return GEN_FCN (icode) (arg[0], arg[1], arg[2], arg[3]);
+ case 5:
+ return GEN_FCN (icode) (arg[0], arg[1], arg[2], arg[3], arg[4]);
+ default:
+ gcc_unreachable ();
+ }
+}
/* Expand an expression EXP that calls a built-in function,
with result going to TARGET if that's convenient
static rtx
arc_expand_builtin (tree exp,
rtx target,
- rtx subtarget,
- machine_mode mode,
- int ignore)
-{
- tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
- tree arg0;
- tree arg1;
- rtx op0;
- rtx op1;
- int fcode = DECL_FUNCTION_CODE (fndecl);
- int icode;
+ rtx subtarget ATTRIBUTE_UNUSED,
+ machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
+ unsigned int id = DECL_FUNCTION_CODE (fndecl);
+ const struct arc_builtin_description *d = &arc_bdesc[id];
+ int i, j, n_args = call_expr_nargs (exp);
+ rtx pat = NULL_RTX;
+ rtx xop[5];
+ enum insn_code icode = d->icode;
+ machine_mode tmode = insn_data[icode].operand[0].mode;
+ int nonvoid;
+ tree arg0;
+ tree arg1;
+ tree arg2;
+ tree arg3;
+ rtx op0;
+ rtx op1;
+ rtx op2;
+ rtx op3;
+ rtx op4;
machine_mode mode0;
machine_mode mode1;
+ machine_mode mode2;
+ machine_mode mode3;
+ machine_mode mode4;
- if (fcode > ARC_SIMD_BUILTIN_BEGIN && fcode < ARC_SIMD_BUILTIN_END)
- return arc_expand_simd_builtin (exp, target, subtarget, mode, ignore);
+ if (id >= ARC_BUILTIN_COUNT)
+ internal_error ("bad builtin fcode");
- switch (fcode)
+ /* 1st part: Expand special builtins. */
+ switch (id)
{
case ARC_BUILTIN_NOP:
- emit_insn (gen_nop ());
+ emit_insn (gen_nopv ());
return NULL_RTX;
- case ARC_BUILTIN_NORM:
- icode = CODE_FOR_clrsbsi2;
- arg0 = CALL_EXPR_ARG (exp, 0);
- op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
- mode0 = insn_data[icode].operand[1].mode;
- target = gen_reg_rtx (SImode);
+ case ARC_BUILTIN_RTIE:
+ case ARC_BUILTIN_SYNC:
+ case ARC_BUILTIN_BRK:
+ case ARC_BUILTIN_SWI:
+ case ARC_BUILTIN_UNIMP_S:
+ gcc_assert (icode != 0);
+ emit_insn (GEN_FCN (icode) (const1_rtx));
+ return NULL_RTX;
- if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
- op0 = copy_to_mode_reg (mode0, op0);
+ case ARC_BUILTIN_ALIGNED:
+ return arc_expand_builtin_aligned (exp);
- emit_insn (gen_clrsbsi2 (target, op0));
+ case ARC_BUILTIN_CLRI:
+ target = gen_reg_rtx (SImode);
+ emit_insn (gen_clri (target, const1_rtx));
return target;
- case ARC_BUILTIN_NORMW:
-
- /* FIXME : This should all be HImode, not SImode. */
- icode = CODE_FOR_normw;
+ case ARC_BUILTIN_TRAP_S:
+ case ARC_BUILTIN_SLEEP:
arg0 = CALL_EXPR_ARG (exp, 0);
+ fold (arg0);
op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
- mode0 = insn_data[icode].operand[1].mode;
- target = gen_reg_rtx (SImode);
- if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
- op0 = copy_to_mode_reg (mode0, convert_to_mode (mode0, op0,0));
-
- emit_insn (gen_normw (target, op0));
- return target;
+ if (!CONST_INT_P (op0) || !satisfies_constraint_L (op0))
+ {
+ error ("builtin operand should be an unsigned 6-bit value");
+ return NULL_RTX;
+ }
+ gcc_assert (icode != 0);
+ emit_insn (GEN_FCN (icode) (op0));
+ return NULL_RTX;
- case ARC_BUILTIN_MUL64:
- icode = CODE_FOR_mul64;
+ case ARC_BUILTIN_VDORUN:
+ case ARC_BUILTIN_VDIRUN:
arg0 = CALL_EXPR_ARG (exp, 0);
arg1 = CALL_EXPR_ARG (exp, 1);
- op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
- op1 = expand_expr (arg1, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+ op0 = expand_expr (arg0, NULL_RTX, SImode, EXPAND_NORMAL);
+ op1 = expand_expr (arg1, NULL_RTX, SImode, EXPAND_NORMAL);
- mode0 = insn_data[icode].operand[0].mode;
- mode1 = insn_data[icode].operand[1].mode;
+ target = gen_rtx_REG (SImode, (id == ARC_BUILTIN_VDIRUN) ? 131 : 139);
+
+ mode0 = insn_data[icode].operand[1].mode;
+ mode1 = insn_data[icode].operand[2].mode;
- if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
+ if (!insn_data[icode].operand[1].predicate (op0, mode0))
op0 = copy_to_mode_reg (mode0, op0);
- if (! (*insn_data[icode].operand[1].predicate) (op1, mode1))
+ if (!insn_data[icode].operand[2].predicate (op1, mode1))
op1 = copy_to_mode_reg (mode1, op1);
- emit_insn (gen_mul64 (op0,op1));
+ pat = GEN_FCN (icode) (target, op0, op1);
+ if (!pat)
+ return NULL_RTX;
+
+ emit_insn (pat);
return NULL_RTX;
- case ARC_BUILTIN_MULU64:
- icode = CODE_FOR_mulu64;
+ case ARC_BUILTIN_VDIWR:
+ case ARC_BUILTIN_VDOWR:
arg0 = CALL_EXPR_ARG (exp, 0);
arg1 = CALL_EXPR_ARG (exp, 1);
- op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
- op1 = expand_expr (arg1, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+ op0 = expand_expr (arg0, NULL_RTX, SImode, EXPAND_NORMAL);
+ op1 = expand_expr (arg1, NULL_RTX, SImode, EXPAND_NORMAL);
+
+ if (!CONST_INT_P (op0)
+ || !(UNSIGNED_INT3 (INTVAL (op0))))
+ error ("operand 1 should be an unsigned 3-bit immediate");
- mode0 = insn_data[icode].operand[0].mode;
mode1 = insn_data[icode].operand[1].mode;
- if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
- op0 = copy_to_mode_reg (mode0, op0);
+ if (icode == CODE_FOR_vdiwr_insn)
+ target = gen_rtx_REG (SImode,
+ ARC_FIRST_SIMD_DMA_CONFIG_IN_REG + INTVAL (op0));
+ else if (icode == CODE_FOR_vdowr_insn)
+ target = gen_rtx_REG (SImode,
+ ARC_FIRST_SIMD_DMA_CONFIG_OUT_REG + INTVAL (op0));
+ else
+ gcc_unreachable ();
- if (! (*insn_data[icode].operand[0].predicate) (op1, mode1))
+ if (!insn_data[icode].operand[2].predicate (op1, mode1))
op1 = copy_to_mode_reg (mode1, op1);
- emit_insn (gen_mulu64 (op0,op1));
- return NULL_RTX;
-
- case ARC_BUILTIN_RTIE:
- icode = CODE_FOR_rtie;
- emit_insn (gen_rtie (const1_rtx));
- return NULL_RTX;
+ pat = GEN_FCN (icode) (target, op1);
+ if (!pat)
+ return NULL_RTX;
- case ARC_BUILTIN_SYNC:
- icode = CODE_FOR_sync;
- emit_insn (gen_sync (const1_rtx));
+ emit_insn (pat);
return NULL_RTX;
- case ARC_BUILTIN_SWAP:
- icode = CODE_FOR_swap;
+ case ARC_BUILTIN_VASRW:
+ case ARC_BUILTIN_VSR8:
+ case ARC_BUILTIN_VSR8AW:
arg0 = CALL_EXPR_ARG (exp, 0);
- op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+ arg1 = CALL_EXPR_ARG (exp, 1);
+ op0 = expand_expr (arg0, NULL_RTX, V8HImode, EXPAND_NORMAL);
+ op1 = expand_expr (arg1, NULL_RTX, SImode, EXPAND_NORMAL);
+ op2 = gen_rtx_REG (V8HImode, ARC_FIRST_SIMD_VR_REG);
+
+ target = gen_reg_rtx (V8HImode);
mode0 = insn_data[icode].operand[1].mode;
- target = gen_reg_rtx (SImode);
+ mode1 = insn_data[icode].operand[2].mode;
- if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
+ if (!insn_data[icode].operand[1].predicate (op0, mode0))
op0 = copy_to_mode_reg (mode0, op0);
- emit_insn (gen_swap (target, op0));
- return target;
+ if ((!insn_data[icode].operand[2].predicate (op1, mode1))
+ || !(UNSIGNED_INT3 (INTVAL (op1))))
+ error ("operand 2 should be an unsigned 3-bit value (I0-I7)");
- case ARC_BUILTIN_DIVAW:
- icode = CODE_FOR_divaw;
- arg0 = CALL_EXPR_ARG (exp, 0);
- arg1 = CALL_EXPR_ARG (exp, 1);
+ pat = GEN_FCN (icode) (target, op0, op1, op2);
+ if (!pat)
+ return NULL_RTX;
- op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
- op1 = expand_expr (arg1, NULL_RTX, VOIDmode, EXPAND_NORMAL);
- target = gen_reg_rtx (SImode);
+ emit_insn (pat);
+ return target;
- mode0 = insn_data[icode].operand[0].mode;
- mode1 = insn_data[icode].operand[1].mode;
+ case ARC_BUILTIN_VLD32WH:
+ case ARC_BUILTIN_VLD32WL:
+ case ARC_BUILTIN_VLD64:
+ case ARC_BUILTIN_VLD32:
+ rtx src_vreg;
+ icode = d->icode;
+ arg0 = CALL_EXPR_ARG (exp, 0); /* source vreg. */
+ arg1 = CALL_EXPR_ARG (exp, 1); /* [I]0-7. */
+ arg2 = CALL_EXPR_ARG (exp, 2); /* u8. */
- if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
- op0 = copy_to_mode_reg (mode0, op0);
+ src_vreg = expand_expr (arg0, NULL_RTX, V8HImode, EXPAND_NORMAL);
+ op0 = expand_expr (arg1, NULL_RTX, SImode, EXPAND_NORMAL);
+ op1 = expand_expr (arg2, NULL_RTX, SImode, EXPAND_NORMAL);
+ op2 = gen_rtx_REG (V8HImode, ARC_FIRST_SIMD_VR_REG);
- if (! (*insn_data[icode].operand[1].predicate) (op1, mode1))
- op1 = copy_to_mode_reg (mode1, op1);
+ /* target <- src vreg. */
+ emit_insn (gen_move_insn (target, src_vreg));
- emit_insn (gen_divaw (target, op0, op1));
- return target;
+ /* target <- vec_concat: target, mem (Ib, u8). */
+ mode0 = insn_data[icode].operand[3].mode;
+ mode1 = insn_data[icode].operand[1].mode;
- case ARC_BUILTIN_BRK:
- icode = CODE_FOR_brk;
- emit_insn (gen_brk (const1_rtx));
- return NULL_RTX;
+ if ((!insn_data[icode].operand[3].predicate (op0, mode0))
+ || !(UNSIGNED_INT3 (INTVAL (op0))))
+ error ("operand 1 should be an unsigned 3-bit value (I0-I7)");
- case ARC_BUILTIN_SLEEP:
- icode = CODE_FOR_sleep;
- arg0 = CALL_EXPR_ARG (exp, 0);
+ if ((!insn_data[icode].operand[1].predicate (op1, mode1))
+ || !(UNSIGNED_INT8 (INTVAL (op1))))
+ error ("operand 2 should be an unsigned 8-bit value");
- fold (arg0);
+ pat = GEN_FCN (icode) (target, op1, op2, op0);
+ if (!pat)
+ return NULL_RTX;
- op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
- mode0 = insn_data[icode].operand[1].mode;
+ emit_insn (pat);
+ return target;
- emit_insn (gen_sleep (op0));
- return NULL_RTX;
+ case ARC_BUILTIN_VLD64W:
+ case ARC_BUILTIN_VLD128:
+ arg0 = CALL_EXPR_ARG (exp, 0); /* dest vreg. */
+ arg1 = CALL_EXPR_ARG (exp, 1); /* [I]0-7. */
- case ARC_BUILTIN_SWI:
- icode = CODE_FOR_swi;
- emit_insn (gen_swi (const1_rtx));
- return NULL_RTX;
+ op0 = gen_rtx_REG (V8HImode, ARC_FIRST_SIMD_VR_REG);
+ op1 = expand_expr (arg0, NULL_RTX, SImode, EXPAND_NORMAL);
+ op2 = expand_expr (arg1, NULL_RTX, SImode, EXPAND_NORMAL);
- case ARC_BUILTIN_FLAG:
- icode = CODE_FOR_flag;
- arg0 = CALL_EXPR_ARG (exp, 0);
- op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
- mode0 = insn_data[icode].operand[0].mode;
+ /* target <- src vreg. */
+ target = gen_reg_rtx (V8HImode);
- if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
- op0 = copy_to_mode_reg (mode0, op0);
+ /* target <- vec_concat: target, mem (Ib, u8). */
+ mode0 = insn_data[icode].operand[1].mode;
+ mode1 = insn_data[icode].operand[2].mode;
+ mode2 = insn_data[icode].operand[3].mode;
- emit_insn (gen_flag (op0));
- return NULL_RTX;
+ if ((!insn_data[icode].operand[2].predicate (op1, mode1))
+ || !(UNSIGNED_INT3 (INTVAL (op1))))
+ error ("operand 1 should be an unsigned 3-bit value (I0-I7)");
- case ARC_BUILTIN_CORE_READ:
- icode = CODE_FOR_core_read;
- arg0 = CALL_EXPR_ARG (exp, 0);
- target = gen_reg_rtx (SImode);
+ if ((!insn_data[icode].operand[3].predicate (op2, mode2))
+ || !(UNSIGNED_INT8 (INTVAL (op2))))
+ error ("operand 2 should be an unsigned 8-bit value");
- fold (arg0);
+ pat = GEN_FCN (icode) (target, op0, op1, op2);
- op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
- mode0 = insn_data[icode].operand[1].mode;
+ if (!pat)
+ return NULL_RTX;
- emit_insn (gen_core_read (target, op0));
+ emit_insn (pat);
return target;
- case ARC_BUILTIN_CORE_WRITE:
- icode = CODE_FOR_core_write;
- arg0 = CALL_EXPR_ARG (exp, 0);
- arg1 = CALL_EXPR_ARG (exp, 1);
+ case ARC_BUILTIN_VST128:
+ case ARC_BUILTIN_VST64:
+ arg0 = CALL_EXPR_ARG (exp, 0); /* src vreg. */
+ arg1 = CALL_EXPR_ARG (exp, 1); /* [I]0-7. */
+ arg2 = CALL_EXPR_ARG (exp, 2); /* u8. */
- fold (arg1);
-
- op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
- op1 = expand_expr (arg1, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+ op0 = gen_rtx_REG (V8HImode, ARC_FIRST_SIMD_VR_REG);
+ op1 = expand_expr (arg1, NULL_RTX, SImode, EXPAND_NORMAL);
+ op2 = expand_expr (arg2, NULL_RTX, SImode, EXPAND_NORMAL);
+ op3 = expand_expr (arg0, NULL_RTX, V8HImode, EXPAND_NORMAL);
mode0 = insn_data[icode].operand[0].mode;
mode1 = insn_data[icode].operand[1].mode;
+ mode2 = insn_data[icode].operand[2].mode;
+ mode3 = insn_data[icode].operand[3].mode;
- emit_insn (gen_core_write (op0, op1));
- return NULL_RTX;
-
- case ARC_BUILTIN_LR:
- icode = CODE_FOR_lr;
- arg0 = CALL_EXPR_ARG (exp, 0);
- target = gen_reg_rtx (SImode);
+ if ((!insn_data[icode].operand[1].predicate (op1, mode1))
+ || !(UNSIGNED_INT3 (INTVAL (op1))))
+ error ("operand 2 should be an unsigned 3-bit value (I0-I7)");
- fold (arg0);
+ if ((!insn_data[icode].operand[2].predicate (op2, mode2))
+ || !(UNSIGNED_INT8 (INTVAL (op2))))
+ error ("operand 3 should be an unsigned 8-bit value");
- op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
- mode0 = insn_data[icode].operand[1].mode;
+ if (!insn_data[icode].operand[3].predicate (op3, mode3))
+ op3 = copy_to_mode_reg (mode3, op3);
- emit_insn (gen_lr (target, op0));
- return target;
+ pat = GEN_FCN (icode) (op0, op1, op2, op3);
+ if (!pat)
+ return NULL_RTX;
- case ARC_BUILTIN_SR:
- icode = CODE_FOR_sr;
- arg0 = CALL_EXPR_ARG (exp, 0);
- arg1 = CALL_EXPR_ARG (exp, 1);
+ emit_insn (pat);
+ return NULL_RTX;
- fold (arg1);
+ case ARC_BUILTIN_VST16_N:
+ case ARC_BUILTIN_VST32_N:
+ arg0 = CALL_EXPR_ARG (exp, 0); /* source vreg. */
+ arg1 = CALL_EXPR_ARG (exp, 1); /* u3. */
+ arg2 = CALL_EXPR_ARG (exp, 2); /* [I]0-7. */
+ arg3 = CALL_EXPR_ARG (exp, 3); /* u8. */
- op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
- op1 = expand_expr (arg1, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+ op0 = expand_expr (arg3, NULL_RTX, SImode, EXPAND_NORMAL);
+ op1 = gen_rtx_REG (V8HImode, ARC_FIRST_SIMD_VR_REG);
+ op2 = expand_expr (arg2, NULL_RTX, SImode, EXPAND_NORMAL);
+ op3 = expand_expr (arg0, NULL_RTX, V8HImode, EXPAND_NORMAL);
+ op4 = expand_expr (arg1, NULL_RTX, SImode, EXPAND_NORMAL);
mode0 = insn_data[icode].operand[0].mode;
- mode1 = insn_data[icode].operand[1].mode;
+ mode2 = insn_data[icode].operand[2].mode;
+ mode3 = insn_data[icode].operand[3].mode;
+ mode4 = insn_data[icode].operand[4].mode;
- emit_insn (gen_sr (op0, op1));
- return NULL_RTX;
+ /* Do some correctness checks for the operands. */
+ if ((!insn_data[icode].operand[0].predicate (op0, mode0))
+ || !(UNSIGNED_INT8 (INTVAL (op0))))
+ error ("operand 4 should be an unsigned 8-bit value (0-255)");
- case ARC_BUILTIN_TRAP_S:
- icode = CODE_FOR_trap_s;
- arg0 = CALL_EXPR_ARG (exp, 0);
+ if ((!insn_data[icode].operand[2].predicate (op2, mode2))
+ || !(UNSIGNED_INT3 (INTVAL (op2))))
+ error ("operand 3 should be an unsigned 3-bit value (I0-I7)");
- fold (arg0);
+ if (!insn_data[icode].operand[3].predicate (op3, mode3))
+ op3 = copy_to_mode_reg (mode3, op3);
- op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
- mode0 = insn_data[icode].operand[1].mode;
+ if ((!insn_data[icode].operand[4].predicate (op4, mode4))
+ || !(UNSIGNED_INT3 (INTVAL (op4))))
+ error ("operand 2 should be an unsigned 3-bit value (subreg 0-7)");
+ else if (icode == CODE_FOR_vst32_n_insn
+ && ((INTVAL (op4) % 2) != 0))
+ error ("operand 2 should be an even 3-bit value (subreg 0,2,4,6)");
- /* We don't give an error for non-cost values here because
- we still want to allow things to be fixed up by later inlining /
- constant folding / dead code elimination. */
- if (CONST_INT_P (op0) && !satisfies_constraint_L (op0))
- {
- /* Keep this message in sync with the one in arc.md:trap_s,
- because *.md files don't get scanned by exgettext. */
- error ("operand to trap_s should be an unsigned 6-bit value");
- }
- emit_insn (gen_trap_s (op0));
- return NULL_RTX;
+ pat = GEN_FCN (icode) (op0, op1, op2, op3, op4);
+ if (!pat)
+ return NULL_RTX;
- case ARC_BUILTIN_UNIMP_S:
- icode = CODE_FOR_unimp_s;
- emit_insn (gen_unimp_s (const1_rtx));
+ emit_insn (pat);
return NULL_RTX;
- case ARC_BUILTIN_ALIGNED:
- /* __builtin_arc_aligned (void* val, int alignval) */
- arg0 = CALL_EXPR_ARG (exp, 0);
- arg1 = CALL_EXPR_ARG (exp, 1);
- fold (arg1);
- op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
- op1 = expand_expr (arg1, NULL_RTX, VOIDmode, EXPAND_NORMAL);
- target = gen_reg_rtx (SImode);
+ default:
+ break;
+ }
+
+ /* 2nd part: Expand regular builtins. */
+ if (icode == 0)
+ internal_error ("bad builtin fcode");
- if (!CONST_INT_P (op1))
+ nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node;
+ j = 0;
+
+ if (nonvoid)
+ {
+ if (target == NULL_RTX
+ || GET_MODE (target) != tmode
+ || !insn_data[icode].operand[0].predicate (target, tmode))
{
- /* If we can't fold the alignment to a constant integer
- whilst optimizing, this is probably a user error. */
- if (optimize)
- warning (0, "__builtin_arc_aligned with non-constant alignment");
+ target = gen_reg_rtx (tmode);
}
- else
+ xop[j++] = target;
+ }
+
+ gcc_assert (n_args <= 4);
+ for (i = 0; i < n_args; i++, j++)
+ {
+ tree arg = CALL_EXPR_ARG (exp, i);
+ machine_mode mode = insn_data[icode].operand[j].mode;
+ rtx op = expand_expr (arg, NULL_RTX, mode, EXPAND_NORMAL);
+ machine_mode opmode = GET_MODE (op);
+ char c = insn_data[icode].operand[j].constraint[0];
+
+ /* SIMD extension requires exact immediate operand match. */
+ if ((id > ARC_BUILTIN_SIMD_BEGIN)
+ && (id < ARC_BUILTIN_SIMD_END)
+ && (c != 'v')
+ && (c != 'r'))
{
- HOST_WIDE_INT alignTest = INTVAL (op1);
- /* Check alignTest is positive, and a power of two. */
- if (alignTest <= 0 || alignTest != (alignTest & -alignTest))
+ if (!CONST_INT_P (op))
+ error ("builtin requires an immediate for operand %d", j);
+ switch (c)
{
- error ("invalid alignment value for __builtin_arc_aligned");
- return NULL_RTX;
+ case 'L':
+ if (!satisfies_constraint_L (op))
+ error ("operand %d should be a 6 bit unsigned immediate", j);
+ break;
+ case 'P':
+ if (!satisfies_constraint_P (op))
+ error ("operand %d should be a 8 bit unsigned immediate", j);
+ break;
+ case 'K':
+ if (!satisfies_constraint_K (op))
+ error ("operand %d should be a 3 bit unsigned immediate", j);
+ break;
+ default:
+ error ("unknown builtin immediate operand type for operand %d",
+ j);
}
+ }
- if (CONST_INT_P (op0))
- {
- HOST_WIDE_INT pnt = INTVAL (op0);
+ if (CONST_INT_P (op))
+ opmode = mode;
- if ((pnt & (alignTest - 1)) == 0)
- return const1_rtx;
- }
- else
- {
- unsigned align = get_pointer_alignment (arg0);
- unsigned numBits = alignTest * BITS_PER_UNIT;
-
- if (align && align >= numBits)
- return const1_rtx;
- /* Another attempt to ascertain alignment. Check the type
- we are pointing to. */
- if (POINTER_TYPE_P (TREE_TYPE (arg0))
- && TYPE_ALIGN (TREE_TYPE (TREE_TYPE (arg0))) >= numBits)
- return const1_rtx;
- }
+ if ((opmode == SImode) && (mode == HImode))
+ {
+ opmode = HImode;
+ op = gen_lowpart (HImode, op);
}
- /* Default to false. */
- return const0_rtx;
+ /* In case the insn wants input operands in modes different from
+ the result, abort. */
+ gcc_assert (opmode == mode || opmode == VOIDmode);
- default:
- break;
+ if (!insn_data[icode].operand[i + nonvoid].predicate (op, mode))
+ op = copy_to_mode_reg (mode, op);
+
+ xop[j] = op;
}
- /* @@@ Should really do something sensible here. */
- return NULL_RTX;
+ pat = apply_GEN_FCN (icode, xop);
+ if (pat == NULL_RTX)
+ return NULL_RTX;
+
+ emit_insn (pat);
+
+ if (nonvoid)
+ return target;
+ else
+ return const0_rtx;
}
/* Returns true if the operands[opno] is a valid compile-time constant to be
case CONST_INT :
if( UNSIGNED_INT6 (INTVAL (operands[opno])))
return true;
+ /* FALLTHRU */
default:
fatal_error (input_location,
"operand for sleep instruction must be an unsigned 6 bit compile-time constant");
}
-/* Emit profiling code for calling CALLEE. Return true if a special
- call pattern needs to be generated. */
-
-bool
-arc_profile_call (rtx callee)
-{
- rtx from = XEXP (DECL_RTL (current_function_decl), 0);
-
- if (TARGET_UCB_MCOUNT)
- /* Profiling is done by instrumenting the callee. */
- return false;
-
- if (CONSTANT_P (callee))
- {
- rtx count_ptr
- = gen_rtx_CONST (Pmode,
- gen_rtx_UNSPEC (Pmode,
- gen_rtvec (3, from, callee,
- CONST0_RTX (Pmode)),
- UNSPEC_PROF));
- rtx counter = gen_rtx_MEM (SImode, count_ptr);
- /* ??? The increment would better be done atomically, but as there is
- no proper hardware support, that would be too expensive. */
- emit_move_insn (counter,
- force_reg (SImode, plus_constant (SImode, counter, 1)));
- return false;
- }
- else
- {
- rtx count_list_ptr
- = gen_rtx_CONST (Pmode,
- gen_rtx_UNSPEC (Pmode,
- gen_rtvec (3, from, CONST0_RTX (Pmode),
- CONST0_RTX (Pmode)),
- UNSPEC_PROF));
- emit_move_insn (gen_rtx_REG (Pmode, 8), count_list_ptr);
- emit_move_insn (gen_rtx_REG (Pmode, 9), callee);
- return true;
- }
-}
-
/* Worker function for TARGET_RETURN_IN_MEMORY. */
static bool
return NULL;
}
+/* Return true if a load instruction (CONSUMER) uses the same address as a
+ store instruction (PRODUCER). This function is used to avoid st/ld
+ address hazard in ARC700 cores. */
+bool
+arc_store_addr_hazard_p (rtx_insn* producer, rtx_insn* consumer)
+{
+ rtx in_set, out_set;
+ rtx out_addr, in_addr;
+
+ if (!producer)
+ return false;
+
+ if (!consumer)
+ return false;
+
+ /* Peel the producer and the consumer for the address. */
+ out_set = single_set (producer);
+ if (out_set)
+ {
+ out_addr = SET_DEST (out_set);
+ if (!out_addr)
+ return false;
+ if (GET_CODE (out_addr) == ZERO_EXTEND
+ || GET_CODE (out_addr) == SIGN_EXTEND)
+ out_addr = XEXP (out_addr, 0);
+
+ if (!MEM_P (out_addr))
+ return false;
+
+ in_set = single_set (consumer);
+ if (in_set)
+ {
+ in_addr = SET_SRC (in_set);
+ if (!in_addr)
+ return false;
+ if (GET_CODE (in_addr) == ZERO_EXTEND
+ || GET_CODE (in_addr) == SIGN_EXTEND)
+ in_addr = XEXP (in_addr, 0);
+
+ if (!MEM_P (in_addr))
+ return false;
+ /* Get rid of the MEM and check if the addresses are
+ equivalent. */
+ in_addr = XEXP (in_addr, 0);
+ out_addr = XEXP (out_addr, 0);
+
+ return exp_equiv_p (in_addr, out_addr, 0, true);
+ }
+ }
+ return false;
+}
+
/* The same functionality as arc_hazard. It is called in machine
reorg before any other optimization. Hence, the NOP size is taken
into account when doing branch shortening. */
emit_insn_before (gen_nopv (), succ0);
}
}
+
+ if (TARGET_ARC700)
+ {
+ rtx_insn *succ1;
+
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ {
+ succ0 = next_real_insn (insn);
+ if (arc_store_addr_hazard_p (insn, succ0))
+ {
+ emit_insn_after (gen_nopv (), insn);
+ emit_insn_after (gen_nopv (), insn);
+ continue;
+ }
+
+ /* Avoid adding nops if the instruction between the ST and LD is
+ a call or jump. */
+ succ1 = next_real_insn (succ0);
+ if (succ0 && !JUMP_P (succ0) && !CALL_P (succ0)
+ && arc_store_addr_hazard_p (insn, succ1))
+ emit_insn_after (gen_nopv (), insn);
+ }
+ }
}
static int arc_reorg_in_progress = 0;
cfun->machine->arc_reorg_started = 1;
arc_reorg_in_progress = 1;
- /* Emit special sections for profiling. */
- if (crtl->profile)
- {
- section *save_text_section;
- rtx_insn *insn;
- int size = get_max_uid () >> 4;
- htab_t htab = htab_create (size, unspec_prof_hash, unspec_prof_htab_eq,
- NULL);
-
- save_text_section = in_section;
- for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
- if (NONJUMP_INSN_P (insn))
- walk_stores (PATTERN (insn), write_profile_sections, htab);
- if (htab_elements (htab))
- in_section = 0;
- switch_to_section (save_text_section);
- htab_delete (htab);
- }
-
/* Link up loop ends with their loop start. */
{
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
pc_target = SET_SRC (pattern);
+ /* Avoid FPU instructions. */
+ if ((GET_MODE (XEXP (XEXP (pc_target, 0), 0)) == CC_FPUmode)
+ || (GET_MODE (XEXP (XEXP (pc_target, 0), 0)) == CC_FPU_UNEQmode))
+ continue;
+
/* Now go back and search for the set cc insn. */
label = XEXP (pc_target, 1);
break;
}
}
- if (! link_insn)
+ if (!link_insn)
continue;
else
/* Check if this is a data dependency. */
arc_rewrite_small_data_p (const_rtx x)
{
if (GET_CODE (x) == CONST)
- x = XEXP (x, 0);
-
- if (GET_CODE (x) == PLUS)
- {
- if (GET_CODE (XEXP (x, 1)) == CONST_INT)
- x = XEXP (x, 0);
- }
-
- return (GET_CODE (x) == SYMBOL_REF
- && SYMBOL_REF_SMALL_P(x));
-}
-
-/* If possible, rewrite OP so that it refers to small data using
- explicit relocations. */
-
-rtx
-arc_rewrite_small_data (rtx op)
-{
- op = copy_insn (op);
- subrtx_ptr_iterator::array_type array;
- FOR_EACH_SUBRTX_PTR (iter, array, &op, ALL)
- {
- rtx *loc = *iter;
- if (arc_rewrite_small_data_p (*loc))
- {
- gcc_assert (SDATA_BASE_REGNUM == PIC_OFFSET_TABLE_REGNUM);
- *loc = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, *loc);
- if (loc != &op)
- {
- if (GET_CODE (op) == MEM && &XEXP (op, 0) == loc)
- ; /* OK. */
- else if (GET_CODE (op) == MEM
- && GET_CODE (XEXP (op, 0)) == PLUS
- && GET_CODE (XEXP (XEXP (op, 0), 0)) == MULT)
- *loc = force_reg (Pmode, *loc);
- else
- gcc_unreachable ();
- }
- iter.skip_subrtxes ();
- }
- else if (GET_CODE (*loc) == PLUS
- && rtx_equal_p (XEXP (*loc, 0), pic_offset_table_rtx))
- iter.skip_subrtxes ();
- }
- return op;
-}
-
-/* Return true if OP refers to small data symbols directly, not through
- a PLUS. */
-
-bool
-small_data_pattern (rtx op, machine_mode)
-{
- if (GET_CODE (op) == SEQUENCE)
- return false;
- subrtx_iterator::array_type array;
- FOR_EACH_SUBRTX (iter, array, op, ALL)
- {
- const_rtx x = *iter;
- if (GET_CODE (x) == PLUS
- && rtx_equal_p (XEXP (x, 0), pic_offset_table_rtx))
- iter.skip_subrtxes ();
- else if (arc_rewrite_small_data_p (x))
- return true;
- }
- return false;
-}
-
-/* Return true if OP is an acceptable memory operand for ARCompact
- 16-bit gp-relative load instructions.
- op shd look like : [r26, symref@sda]
- i.e. (mem (plus (reg 26) (symref with smalldata flag set))
- */
-/* volatile cache option still to be handled. */
-
-bool
-compact_sda_memory_operand (rtx op, machine_mode mode)
-{
- rtx addr;
- int size;
-
- /* Eliminate non-memory operations. */
- if (GET_CODE (op) != MEM)
- return false;
-
- if (mode == VOIDmode)
- mode = GET_MODE (op);
-
- size = GET_MODE_SIZE (mode);
-
- /* dword operations really put out 2 instructions, so eliminate them. */
- if (size > UNITS_PER_WORD)
- return false;
-
- /* Decode the address now. */
- addr = XEXP (op, 0);
-
- return LEGITIMATE_SMALL_DATA_ADDRESS_P (addr);
-}
-
-/* Implement ASM_OUTPUT_ALIGNED_DECL_LOCAL. */
-
-void
-arc_asm_output_aligned_decl_local (FILE * stream, tree decl, const char * name,
- unsigned HOST_WIDE_INT size,
- unsigned HOST_WIDE_INT align,
- unsigned HOST_WIDE_INT globalize_p)
-{
- int in_small_data = arc_in_small_data_p (decl);
-
- if (in_small_data)
- switch_to_section (get_named_section (NULL, ".sbss", 0));
- /* named_section (0,".sbss",0); */
- else
- switch_to_section (bss_section);
-
- if (globalize_p)
- (*targetm.asm_out.globalize_label) (stream, name);
-
- ASM_OUTPUT_ALIGN (stream, floor_log2 ((align) / BITS_PER_UNIT));
- ASM_OUTPUT_TYPE_DIRECTIVE (stream, name, "object");
- ASM_OUTPUT_SIZE_DIRECTIVE (stream, name, size);
- ASM_OUTPUT_LABEL (stream, name);
-
- if (size != 0)
- ASM_OUTPUT_SKIP (stream, size);
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-/* SIMD builtins support. */
-enum simd_insn_args_type {
- Va_Vb_Vc,
- Va_Vb_rlimm,
- Va_Vb_Ic,
- Va_Vb_u6,
- Va_Vb_u8,
- Va_rlimm_u8,
-
- Va_Vb,
-
- void_rlimm,
- void_u6,
-
- Da_u3_rlimm,
- Da_rlimm_rlimm,
-
- Va_Ib_u8,
- void_Va_Ib_u8,
-
- Va_Vb_Ic_u8,
- void_Va_u3_Ib_u8
-};
-
-struct builtin_description
-{
- enum simd_insn_args_type args_type;
- const enum insn_code icode;
- const char * const name;
- const enum arc_builtins code;
-};
-
-static const struct builtin_description arc_simd_builtin_desc_list[] =
-{
- /* VVV builtins go first. */
-#define SIMD_BUILTIN(type, code, string, builtin) \
- { type,CODE_FOR_##code, "__builtin_arc_" string, \
- ARC_SIMD_BUILTIN_##builtin },
-
- SIMD_BUILTIN (Va_Vb_Vc, vaddaw_insn, "vaddaw", VADDAW)
- SIMD_BUILTIN (Va_Vb_Vc, vaddw_insn, "vaddw", VADDW)
- SIMD_BUILTIN (Va_Vb_Vc, vavb_insn, "vavb", VAVB)
- SIMD_BUILTIN (Va_Vb_Vc, vavrb_insn, "vavrb", VAVRB)
- SIMD_BUILTIN (Va_Vb_Vc, vdifaw_insn, "vdifaw", VDIFAW)
- SIMD_BUILTIN (Va_Vb_Vc, vdifw_insn, "vdifw", VDIFW)
- SIMD_BUILTIN (Va_Vb_Vc, vmaxaw_insn, "vmaxaw", VMAXAW)
- SIMD_BUILTIN (Va_Vb_Vc, vmaxw_insn, "vmaxw", VMAXW)
- SIMD_BUILTIN (Va_Vb_Vc, vminaw_insn, "vminaw", VMINAW)
- SIMD_BUILTIN (Va_Vb_Vc, vminw_insn, "vminw", VMINW)
- SIMD_BUILTIN (Va_Vb_Vc, vmulaw_insn, "vmulaw", VMULAW)
- SIMD_BUILTIN (Va_Vb_Vc, vmulfaw_insn, "vmulfaw", VMULFAW)
- SIMD_BUILTIN (Va_Vb_Vc, vmulfw_insn, "vmulfw", VMULFW)
- SIMD_BUILTIN (Va_Vb_Vc, vmulw_insn, "vmulw", VMULW)
- SIMD_BUILTIN (Va_Vb_Vc, vsubaw_insn, "vsubaw", VSUBAW)
- SIMD_BUILTIN (Va_Vb_Vc, vsubw_insn, "vsubw", VSUBW)
- SIMD_BUILTIN (Va_Vb_Vc, vsummw_insn, "vsummw", VSUMMW)
- SIMD_BUILTIN (Va_Vb_Vc, vand_insn, "vand", VAND)
- SIMD_BUILTIN (Va_Vb_Vc, vandaw_insn, "vandaw", VANDAW)
- SIMD_BUILTIN (Va_Vb_Vc, vbic_insn, "vbic", VBIC)
- SIMD_BUILTIN (Va_Vb_Vc, vbicaw_insn, "vbicaw", VBICAW)
- SIMD_BUILTIN (Va_Vb_Vc, vor_insn, "vor", VOR)
- SIMD_BUILTIN (Va_Vb_Vc, vxor_insn, "vxor", VXOR)
- SIMD_BUILTIN (Va_Vb_Vc, vxoraw_insn, "vxoraw", VXORAW)
- SIMD_BUILTIN (Va_Vb_Vc, veqw_insn, "veqw", VEQW)
- SIMD_BUILTIN (Va_Vb_Vc, vlew_insn, "vlew", VLEW)
- SIMD_BUILTIN (Va_Vb_Vc, vltw_insn, "vltw", VLTW)
- SIMD_BUILTIN (Va_Vb_Vc, vnew_insn, "vnew", VNEW)
- SIMD_BUILTIN (Va_Vb_Vc, vmr1aw_insn, "vmr1aw", VMR1AW)
- SIMD_BUILTIN (Va_Vb_Vc, vmr1w_insn, "vmr1w", VMR1W)
- SIMD_BUILTIN (Va_Vb_Vc, vmr2aw_insn, "vmr2aw", VMR2AW)
- SIMD_BUILTIN (Va_Vb_Vc, vmr2w_insn, "vmr2w", VMR2W)
- SIMD_BUILTIN (Va_Vb_Vc, vmr3aw_insn, "vmr3aw", VMR3AW)
- SIMD_BUILTIN (Va_Vb_Vc, vmr3w_insn, "vmr3w", VMR3W)
- SIMD_BUILTIN (Va_Vb_Vc, vmr4aw_insn, "vmr4aw", VMR4AW)
- SIMD_BUILTIN (Va_Vb_Vc, vmr4w_insn, "vmr4w", VMR4W)
- SIMD_BUILTIN (Va_Vb_Vc, vmr5aw_insn, "vmr5aw", VMR5AW)
- SIMD_BUILTIN (Va_Vb_Vc, vmr5w_insn, "vmr5w", VMR5W)
- SIMD_BUILTIN (Va_Vb_Vc, vmr6aw_insn, "vmr6aw", VMR6AW)
- SIMD_BUILTIN (Va_Vb_Vc, vmr6w_insn, "vmr6w", VMR6W)
- SIMD_BUILTIN (Va_Vb_Vc, vmr7aw_insn, "vmr7aw", VMR7AW)
- SIMD_BUILTIN (Va_Vb_Vc, vmr7w_insn, "vmr7w", VMR7W)
- SIMD_BUILTIN (Va_Vb_Vc, vmrb_insn, "vmrb", VMRB)
- SIMD_BUILTIN (Va_Vb_Vc, vh264f_insn, "vh264f", VH264F)
- SIMD_BUILTIN (Va_Vb_Vc, vh264ft_insn, "vh264ft", VH264FT)
- SIMD_BUILTIN (Va_Vb_Vc, vh264fw_insn, "vh264fw", VH264FW)
- SIMD_BUILTIN (Va_Vb_Vc, vvc1f_insn, "vvc1f", VVC1F)
- SIMD_BUILTIN (Va_Vb_Vc, vvc1ft_insn, "vvc1ft", VVC1FT)
-
- SIMD_BUILTIN (Va_Vb_rlimm, vbaddw_insn, "vbaddw", VBADDW)
- SIMD_BUILTIN (Va_Vb_rlimm, vbmaxw_insn, "vbmaxw", VBMAXW)
- SIMD_BUILTIN (Va_Vb_rlimm, vbminw_insn, "vbminw", VBMINW)
- SIMD_BUILTIN (Va_Vb_rlimm, vbmulaw_insn, "vbmulaw", VBMULAW)
- SIMD_BUILTIN (Va_Vb_rlimm, vbmulfw_insn, "vbmulfw", VBMULFW)
- SIMD_BUILTIN (Va_Vb_rlimm, vbmulw_insn, "vbmulw", VBMULW)
- SIMD_BUILTIN (Va_Vb_rlimm, vbrsubw_insn, "vbrsubw", VBRSUBW)
- SIMD_BUILTIN (Va_Vb_rlimm, vbsubw_insn, "vbsubw", VBSUBW)
-
- /* Va, Vb, Ic instructions. */
- SIMD_BUILTIN (Va_Vb_Ic, vasrw_insn, "vasrw", VASRW)
- SIMD_BUILTIN (Va_Vb_Ic, vsr8_insn, "vsr8", VSR8)
- SIMD_BUILTIN (Va_Vb_Ic, vsr8aw_insn, "vsr8aw", VSR8AW)
-
- /* Va, Vb, u6 instructions. */
- SIMD_BUILTIN (Va_Vb_u6, vasrrwi_insn, "vasrrwi", VASRRWi)
- SIMD_BUILTIN (Va_Vb_u6, vasrsrwi_insn, "vasrsrwi", VASRSRWi)
- SIMD_BUILTIN (Va_Vb_u6, vasrwi_insn, "vasrwi", VASRWi)
- SIMD_BUILTIN (Va_Vb_u6, vasrpwbi_insn, "vasrpwbi", VASRPWBi)
- SIMD_BUILTIN (Va_Vb_u6, vasrrpwbi_insn,"vasrrpwbi", VASRRPWBi)
- SIMD_BUILTIN (Va_Vb_u6, vsr8awi_insn, "vsr8awi", VSR8AWi)
- SIMD_BUILTIN (Va_Vb_u6, vsr8i_insn, "vsr8i", VSR8i)
-
- /* Va, Vb, u8 (simm) instructions. */
- SIMD_BUILTIN (Va_Vb_u8, vmvaw_insn, "vmvaw", VMVAW)
- SIMD_BUILTIN (Va_Vb_u8, vmvw_insn, "vmvw", VMVW)
- SIMD_BUILTIN (Va_Vb_u8, vmvzw_insn, "vmvzw", VMVZW)
- SIMD_BUILTIN (Va_Vb_u8, vd6tapf_insn, "vd6tapf", VD6TAPF)
-
- /* Va, rlimm, u8 (simm) instructions. */
- SIMD_BUILTIN (Va_rlimm_u8, vmovaw_insn, "vmovaw", VMOVAW)
- SIMD_BUILTIN (Va_rlimm_u8, vmovw_insn, "vmovw", VMOVW)
- SIMD_BUILTIN (Va_rlimm_u8, vmovzw_insn, "vmovzw", VMOVZW)
-
- /* Va, Vb instructions. */
- SIMD_BUILTIN (Va_Vb, vabsaw_insn, "vabsaw", VABSAW)
- SIMD_BUILTIN (Va_Vb, vabsw_insn, "vabsw", VABSW)
- SIMD_BUILTIN (Va_Vb, vaddsuw_insn, "vaddsuw", VADDSUW)
- SIMD_BUILTIN (Va_Vb, vsignw_insn, "vsignw", VSIGNW)
- SIMD_BUILTIN (Va_Vb, vexch1_insn, "vexch1", VEXCH1)
- SIMD_BUILTIN (Va_Vb, vexch2_insn, "vexch2", VEXCH2)
- SIMD_BUILTIN (Va_Vb, vexch4_insn, "vexch4", VEXCH4)
- SIMD_BUILTIN (Va_Vb, vupbaw_insn, "vupbaw", VUPBAW)
- SIMD_BUILTIN (Va_Vb, vupbw_insn, "vupbw", VUPBW)
- SIMD_BUILTIN (Va_Vb, vupsbaw_insn, "vupsbaw", VUPSBAW)
- SIMD_BUILTIN (Va_Vb, vupsbw_insn, "vupsbw", VUPSBW)
-
- /* DIb, rlimm, rlimm instructions. */
- SIMD_BUILTIN (Da_rlimm_rlimm, vdirun_insn, "vdirun", VDIRUN)
- SIMD_BUILTIN (Da_rlimm_rlimm, vdorun_insn, "vdorun", VDORUN)
-
- /* DIb, limm, rlimm instructions. */
- SIMD_BUILTIN (Da_u3_rlimm, vdiwr_insn, "vdiwr", VDIWR)
- SIMD_BUILTIN (Da_u3_rlimm, vdowr_insn, "vdowr", VDOWR)
-
- /* rlimm instructions. */
- SIMD_BUILTIN (void_rlimm, vrec_insn, "vrec", VREC)
- SIMD_BUILTIN (void_rlimm, vrun_insn, "vrun", VRUN)
- SIMD_BUILTIN (void_rlimm, vrecrun_insn, "vrecrun", VRECRUN)
- SIMD_BUILTIN (void_rlimm, vendrec_insn, "vendrec", VENDREC)
-
- /* Va, [Ib,u8] instructions. */
- SIMD_BUILTIN (Va_Vb_Ic_u8, vld32wh_insn, "vld32wh", VLD32WH)
- SIMD_BUILTIN (Va_Vb_Ic_u8, vld32wl_insn, "vld32wl", VLD32WL)
- SIMD_BUILTIN (Va_Vb_Ic_u8, vld64_insn, "vld64", VLD64)
- SIMD_BUILTIN (Va_Vb_Ic_u8, vld32_insn, "vld32", VLD32)
-
- SIMD_BUILTIN (Va_Ib_u8, vld64w_insn, "vld64w", VLD64W)
- SIMD_BUILTIN (Va_Ib_u8, vld128_insn, "vld128", VLD128)
- SIMD_BUILTIN (void_Va_Ib_u8, vst128_insn, "vst128", VST128)
- SIMD_BUILTIN (void_Va_Ib_u8, vst64_insn, "vst64", VST64)
-
- /* Va, [Ib, u8] instructions. */
- SIMD_BUILTIN (void_Va_u3_Ib_u8, vst16_n_insn, "vst16_n", VST16_N)
- SIMD_BUILTIN (void_Va_u3_Ib_u8, vst32_n_insn, "vst32_n", VST32_N)
-
- SIMD_BUILTIN (void_u6, vinti_insn, "vinti", VINTI)
-};
-
-static void
-arc_init_simd_builtins (void)
-{
- int i;
- tree endlink = void_list_node;
- tree V8HI_type_node = build_vector_type_for_mode (intHI_type_node, V8HImode);
-
- tree v8hi_ftype_v8hi_v8hi
- = build_function_type (V8HI_type_node,
- tree_cons (NULL_TREE, V8HI_type_node,
- tree_cons (NULL_TREE, V8HI_type_node,
- endlink)));
- tree v8hi_ftype_v8hi_int
- = build_function_type (V8HI_type_node,
- tree_cons (NULL_TREE, V8HI_type_node,
- tree_cons (NULL_TREE, integer_type_node,
- endlink)));
-
- tree v8hi_ftype_v8hi_int_int
- = build_function_type (V8HI_type_node,
- tree_cons (NULL_TREE, V8HI_type_node,
- tree_cons (NULL_TREE, integer_type_node,
- tree_cons (NULL_TREE,
- integer_type_node,
- endlink))));
-
- tree void_ftype_v8hi_int_int
- = build_function_type (void_type_node,
- tree_cons (NULL_TREE, V8HI_type_node,
- tree_cons (NULL_TREE, integer_type_node,
- tree_cons (NULL_TREE,
- integer_type_node,
- endlink))));
-
- tree void_ftype_v8hi_int_int_int
- = (build_function_type
- (void_type_node,
- tree_cons (NULL_TREE, V8HI_type_node,
- tree_cons (NULL_TREE, integer_type_node,
- tree_cons (NULL_TREE, integer_type_node,
- tree_cons (NULL_TREE,
- integer_type_node,
- endlink))))));
-
- tree v8hi_ftype_int_int
- = build_function_type (V8HI_type_node,
- tree_cons (NULL_TREE, integer_type_node,
- tree_cons (NULL_TREE, integer_type_node,
- endlink)));
-
- tree void_ftype_int_int
- = build_function_type (void_type_node,
- tree_cons (NULL_TREE, integer_type_node,
- tree_cons (NULL_TREE, integer_type_node,
- endlink)));
-
- tree void_ftype_int
- = build_function_type (void_type_node,
- tree_cons (NULL_TREE, integer_type_node, endlink));
-
- tree v8hi_ftype_v8hi
- = build_function_type (V8HI_type_node, tree_cons (NULL_TREE, V8HI_type_node,
- endlink));
-
- /* These asserts have been introduced to ensure that the order of builtins
- does not get messed up, else the initialization goes wrong. */
- gcc_assert (arc_simd_builtin_desc_list [0].args_type == Va_Vb_Vc);
- for (i=0; arc_simd_builtin_desc_list [i].args_type == Va_Vb_Vc; i++)
- def_mbuiltin (TARGET_SIMD_SET, arc_simd_builtin_desc_list[i].name,
- v8hi_ftype_v8hi_v8hi, arc_simd_builtin_desc_list[i].code);
-
- gcc_assert (arc_simd_builtin_desc_list [i].args_type == Va_Vb_rlimm);
- for (; arc_simd_builtin_desc_list [i].args_type == Va_Vb_rlimm; i++)
- def_mbuiltin (TARGET_SIMD_SET, arc_simd_builtin_desc_list[i].name,
- v8hi_ftype_v8hi_int, arc_simd_builtin_desc_list[i].code);
-
- gcc_assert (arc_simd_builtin_desc_list [i].args_type == Va_Vb_Ic);
- for (; arc_simd_builtin_desc_list [i].args_type == Va_Vb_Ic; i++)
- def_mbuiltin (TARGET_SIMD_SET, arc_simd_builtin_desc_list[i].name,
- v8hi_ftype_v8hi_int, arc_simd_builtin_desc_list[i].code);
-
- gcc_assert (arc_simd_builtin_desc_list [i].args_type == Va_Vb_u6);
- for (; arc_simd_builtin_desc_list [i].args_type == Va_Vb_u6; i++)
- def_mbuiltin (TARGET_SIMD_SET, arc_simd_builtin_desc_list[i].name,
- v8hi_ftype_v8hi_int, arc_simd_builtin_desc_list[i].code);
-
- gcc_assert (arc_simd_builtin_desc_list [i].args_type == Va_Vb_u8);
- for (; arc_simd_builtin_desc_list [i].args_type == Va_Vb_u8; i++)
- def_mbuiltin (TARGET_SIMD_SET, arc_simd_builtin_desc_list[i].name,
- v8hi_ftype_v8hi_int, arc_simd_builtin_desc_list[i].code);
-
- gcc_assert (arc_simd_builtin_desc_list [i].args_type == Va_rlimm_u8);
- for (; arc_simd_builtin_desc_list [i].args_type == Va_rlimm_u8; i++)
- def_mbuiltin (TARGET_SIMD_SET, arc_simd_builtin_desc_list[i].name,
- v8hi_ftype_int_int, arc_simd_builtin_desc_list[i].code);
-
- gcc_assert (arc_simd_builtin_desc_list [i].args_type == Va_Vb);
- for (; arc_simd_builtin_desc_list [i].args_type == Va_Vb; i++)
- def_mbuiltin (TARGET_SIMD_SET, arc_simd_builtin_desc_list[i].name,
- v8hi_ftype_v8hi, arc_simd_builtin_desc_list[i].code);
-
- gcc_assert (arc_simd_builtin_desc_list [i].args_type == Da_rlimm_rlimm);
- for (; arc_simd_builtin_desc_list [i].args_type == Da_rlimm_rlimm; i++)
- def_mbuiltin (TARGET_SIMD_SET, arc_simd_builtin_desc_list [i].name,
- void_ftype_int_int, arc_simd_builtin_desc_list[i].code);
-
- gcc_assert (arc_simd_builtin_desc_list [i].args_type == Da_u3_rlimm);
- for (; arc_simd_builtin_desc_list [i].args_type == Da_u3_rlimm; i++)
- def_mbuiltin (TARGET_SIMD_SET, arc_simd_builtin_desc_list[i].name,
- void_ftype_int_int, arc_simd_builtin_desc_list[i].code);
-
- gcc_assert (arc_simd_builtin_desc_list [i].args_type == void_rlimm);
- for (; arc_simd_builtin_desc_list [i].args_type == void_rlimm; i++)
- def_mbuiltin (TARGET_SIMD_SET, arc_simd_builtin_desc_list[i].name,
- void_ftype_int, arc_simd_builtin_desc_list[i].code);
-
- gcc_assert (arc_simd_builtin_desc_list [i].args_type == Va_Vb_Ic_u8);
- for (; arc_simd_builtin_desc_list [i].args_type == Va_Vb_Ic_u8; i++)
- def_mbuiltin (TARGET_SIMD_SET, arc_simd_builtin_desc_list[i].name,
- v8hi_ftype_v8hi_int_int, arc_simd_builtin_desc_list[i].code);
-
- gcc_assert (arc_simd_builtin_desc_list [i].args_type == Va_Ib_u8);
- for (; arc_simd_builtin_desc_list [i].args_type == Va_Ib_u8; i++)
- def_mbuiltin (TARGET_SIMD_SET, arc_simd_builtin_desc_list[i].name,
- v8hi_ftype_int_int, arc_simd_builtin_desc_list[i].code);
-
- gcc_assert (arc_simd_builtin_desc_list [i].args_type == void_Va_Ib_u8);
- for (; arc_simd_builtin_desc_list [i].args_type == void_Va_Ib_u8; i++)
- def_mbuiltin (TARGET_SIMD_SET, arc_simd_builtin_desc_list [i].name,
- void_ftype_v8hi_int_int, arc_simd_builtin_desc_list[i].code);
-
- gcc_assert (arc_simd_builtin_desc_list [i].args_type == void_Va_u3_Ib_u8);
- for (; arc_simd_builtin_desc_list [i].args_type == void_Va_u3_Ib_u8; i++)
- def_mbuiltin (TARGET_SIMD_SET, arc_simd_builtin_desc_list[i].name,
- void_ftype_v8hi_int_int_int,
- arc_simd_builtin_desc_list[i].code);
-
- gcc_assert (arc_simd_builtin_desc_list [i].args_type == void_u6);
- for (; arc_simd_builtin_desc_list [i].args_type == void_u6; i++)
- def_mbuiltin (TARGET_SIMD_SET, arc_simd_builtin_desc_list[i].name,
- void_ftype_int, arc_simd_builtin_desc_list[i].code);
-
- gcc_assert(i == ARRAY_SIZE (arc_simd_builtin_desc_list));
-}
-
-/* Helper function of arc_expand_builtin; has the same parameters,
- except that EXP is now known to be a call to a simd builtin. */
-
-static rtx
-arc_expand_simd_builtin (tree exp,
- rtx target,
- rtx subtarget ATTRIBUTE_UNUSED,
- machine_mode mode ATTRIBUTE_UNUSED,
- int ignore ATTRIBUTE_UNUSED)
-{
- tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
- tree arg0;
- tree arg1;
- tree arg2;
- tree arg3;
- rtx op0;
- rtx op1;
- rtx op2;
- rtx op3;
- rtx op4;
- rtx pat;
- unsigned int i;
- int fcode = DECL_FUNCTION_CODE (fndecl);
- int icode;
- machine_mode mode0;
- machine_mode mode1;
- machine_mode mode2;
- machine_mode mode3;
- machine_mode mode4;
- const struct builtin_description * d;
-
- for (i = 0, d = arc_simd_builtin_desc_list;
- i < ARRAY_SIZE (arc_simd_builtin_desc_list); i++, d++)
- if (d->code == (const enum arc_builtins) fcode)
- break;
-
- /* We must get an entry here. */
- gcc_assert (i < ARRAY_SIZE (arc_simd_builtin_desc_list));
-
- switch (d->args_type)
- {
- case Va_Vb_rlimm:
- icode = d->icode;
- arg0 = CALL_EXPR_ARG (exp, 0);
- arg1 = CALL_EXPR_ARG (exp, 1);
- op0 = expand_expr (arg0, NULL_RTX, V8HImode, EXPAND_NORMAL);
- op1 = expand_expr (arg1, NULL_RTX, SImode, EXPAND_NORMAL);
-
- target = gen_reg_rtx (V8HImode);
- mode0 = insn_data[icode].operand[1].mode;
- mode1 = insn_data[icode].operand[2].mode;
-
- if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
- op0 = copy_to_mode_reg (mode0, op0);
-
- if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
- op1 = copy_to_mode_reg (mode1, op1);
-
- pat = GEN_FCN (icode) (target, op0, op1);
- if (! pat)
- return 0;
-
- emit_insn (pat);
- return target;
-
- case Va_Vb_u6:
- case Va_Vb_u8:
- icode = d->icode;
- arg0 = CALL_EXPR_ARG (exp, 0);
- arg1 = CALL_EXPR_ARG (exp, 1);
- op0 = expand_expr (arg0, NULL_RTX, V8HImode, EXPAND_NORMAL);
- op1 = expand_expr (arg1, NULL_RTX, SImode, EXPAND_NORMAL);
-
- target = gen_reg_rtx (V8HImode);
- mode0 = insn_data[icode].operand[1].mode;
- mode1 = insn_data[icode].operand[2].mode;
-
- if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
- op0 = copy_to_mode_reg (mode0, op0);
-
- if (! (*insn_data[icode].operand[2].predicate) (op1, mode1)
- || (d->args_type == Va_Vb_u6 && !UNSIGNED_INT6 (INTVAL (op1)))
- || (d->args_type == Va_Vb_u8 && !UNSIGNED_INT8 (INTVAL (op1))))
- error ("operand 2 of %s instruction should be an unsigned %d-bit value",
- d->name,
- (d->args_type == Va_Vb_u6)? 6: 8);
-
- pat = GEN_FCN (icode) (target, op0, op1);
- if (! pat)
- return 0;
-
- emit_insn (pat);
- return target;
-
- case Va_rlimm_u8:
- icode = d->icode;
- arg0 = CALL_EXPR_ARG (exp, 0);
- arg1 = CALL_EXPR_ARG (exp, 1);
- op0 = expand_expr (arg0, NULL_RTX, SImode, EXPAND_NORMAL);
- op1 = expand_expr (arg1, NULL_RTX, SImode, EXPAND_NORMAL);
-
- target = gen_reg_rtx (V8HImode);
- mode0 = insn_data[icode].operand[1].mode;
- mode1 = insn_data[icode].operand[2].mode;
-
- if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
- op0 = copy_to_mode_reg (mode0, op0);
-
- if ( (!(*insn_data[icode].operand[2].predicate) (op1, mode1))
- || !(UNSIGNED_INT8 (INTVAL (op1))))
- error ("operand 2 of %s instruction should be an unsigned 8-bit value",
- d->name);
-
- pat = GEN_FCN (icode) (target, op0, op1);
- if (! pat)
- return 0;
-
- emit_insn (pat);
- return target;
-
- case Va_Vb_Ic:
- icode = d->icode;
- arg0 = CALL_EXPR_ARG (exp, 0);
- arg1 = CALL_EXPR_ARG (exp, 1);
- op0 = expand_expr (arg0, NULL_RTX, V8HImode, EXPAND_NORMAL);
- op1 = expand_expr (arg1, NULL_RTX, SImode, EXPAND_NORMAL);
- op2 = gen_rtx_REG (V8HImode, ARC_FIRST_SIMD_VR_REG);
-
- target = gen_reg_rtx (V8HImode);
- mode0 = insn_data[icode].operand[1].mode;
- mode1 = insn_data[icode].operand[2].mode;
-
- if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
- op0 = copy_to_mode_reg (mode0, op0);
-
- if ( (!(*insn_data[icode].operand[2].predicate) (op1, mode1))
- || !(UNSIGNED_INT3 (INTVAL (op1))))
- error ("operand 2 of %s instruction should be an unsigned 3-bit value (I0-I7)",
- d->name);
-
- pat = GEN_FCN (icode) (target, op0, op1, op2);
- if (! pat)
- return 0;
-
- emit_insn (pat);
- return target;
-
- case Va_Vb_Vc:
- icode = d->icode;
- arg0 = CALL_EXPR_ARG (exp, 0);
- arg1 = CALL_EXPR_ARG (exp, 1);
- op0 = expand_expr (arg0, NULL_RTX, V8HImode, EXPAND_NORMAL);
- op1 = expand_expr (arg1, NULL_RTX, V8HImode, EXPAND_NORMAL);
-
- target = gen_reg_rtx (V8HImode);
- mode0 = insn_data[icode].operand[1].mode;
- mode1 = insn_data[icode].operand[2].mode;
-
- if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
- op0 = copy_to_mode_reg (mode0, op0);
-
- if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
- op1 = copy_to_mode_reg (mode1, op1);
-
- pat = GEN_FCN (icode) (target, op0, op1);
- if (! pat)
- return 0;
-
- emit_insn (pat);
- return target;
-
- case Va_Vb:
- icode = d->icode;
- arg0 = CALL_EXPR_ARG (exp, 0);
- op0 = expand_expr (arg0, NULL_RTX, V8HImode, EXPAND_NORMAL);
-
- target = gen_reg_rtx (V8HImode);
- mode0 = insn_data[icode].operand[1].mode;
-
- if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
- op0 = copy_to_mode_reg (mode0, op0);
-
- pat = GEN_FCN (icode) (target, op0);
- if (! pat)
- return 0;
-
- emit_insn (pat);
- return target;
-
- case Da_rlimm_rlimm:
- icode = d->icode;
- arg0 = CALL_EXPR_ARG (exp, 0);
- arg1 = CALL_EXPR_ARG (exp, 1);
- op0 = expand_expr (arg0, NULL_RTX, SImode, EXPAND_NORMAL);
- op1 = expand_expr (arg1, NULL_RTX, SImode, EXPAND_NORMAL);
-
-
- if (icode == CODE_FOR_vdirun_insn)
- target = gen_rtx_REG (SImode, 131);
- else if (icode == CODE_FOR_vdorun_insn)
- target = gen_rtx_REG (SImode, 139);
- else
- gcc_unreachable ();
-
- mode0 = insn_data[icode].operand[1].mode;
- mode1 = insn_data[icode].operand[2].mode;
-
- if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
- op0 = copy_to_mode_reg (mode0, op0);
-
- if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
- op1 = copy_to_mode_reg (mode1, op1);
-
-
- pat = GEN_FCN (icode) (target, op0, op1);
- if (! pat)
- return 0;
-
- emit_insn (pat);
- return NULL_RTX;
-
- case Da_u3_rlimm:
- icode = d->icode;
- arg0 = CALL_EXPR_ARG (exp, 0);
- arg1 = CALL_EXPR_ARG (exp, 1);
- op0 = expand_expr (arg0, NULL_RTX, SImode, EXPAND_NORMAL);
- op1 = expand_expr (arg1, NULL_RTX, SImode, EXPAND_NORMAL);
-
-
- if (! (GET_CODE (op0) == CONST_INT)
- || !(UNSIGNED_INT3 (INTVAL (op0))))
- error ("operand 1 of %s instruction should be an unsigned 3-bit value (DR0-DR7)",
- d->name);
-
- mode1 = insn_data[icode].operand[1].mode;
-
- if (icode == CODE_FOR_vdiwr_insn)
- target = gen_rtx_REG (SImode,
- ARC_FIRST_SIMD_DMA_CONFIG_IN_REG + INTVAL (op0));
- else if (icode == CODE_FOR_vdowr_insn)
- target = gen_rtx_REG (SImode,
- ARC_FIRST_SIMD_DMA_CONFIG_OUT_REG + INTVAL (op0));
- else
- gcc_unreachable ();
-
- if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
- op1 = copy_to_mode_reg (mode1, op1);
-
- pat = GEN_FCN (icode) (target, op1);
- if (! pat)
- return 0;
-
- emit_insn (pat);
- return NULL_RTX;
-
- case void_u6:
- icode = d->icode;
- arg0 = CALL_EXPR_ARG (exp, 0);
-
- fold (arg0);
-
- op0 = expand_expr (arg0, NULL_RTX, SImode, EXPAND_NORMAL);
- mode0 = insn_data[icode].operand[0].mode;
-
- /* op0 should be u6. */
- if (! (*insn_data[icode].operand[0].predicate) (op0, mode0)
- || !(UNSIGNED_INT6 (INTVAL (op0))))
- error ("operand of %s instruction should be an unsigned 6-bit value",
- d->name);
-
- pat = GEN_FCN (icode) (op0);
- if (! pat)
- return 0;
-
- emit_insn (pat);
- return NULL_RTX;
-
- case void_rlimm:
- icode = d->icode;
- arg0 = CALL_EXPR_ARG (exp, 0);
-
- fold (arg0);
-
- op0 = expand_expr (arg0, NULL_RTX, SImode, EXPAND_NORMAL);
- mode0 = insn_data[icode].operand[0].mode;
-
- if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
- op0 = copy_to_mode_reg (mode0, op0);
-
- pat = GEN_FCN (icode) (op0);
- if (! pat)
- return 0;
-
- emit_insn (pat);
- return NULL_RTX;
-
- case Va_Vb_Ic_u8:
- {
- rtx src_vreg;
- icode = d->icode;
- arg0 = CALL_EXPR_ARG (exp, 0); /* source vreg */
- arg1 = CALL_EXPR_ARG (exp, 1); /* [I]0-7 */
- arg2 = CALL_EXPR_ARG (exp, 2); /* u8 */
-
- src_vreg = expand_expr (arg0, NULL_RTX, V8HImode, EXPAND_NORMAL);
- op0 = expand_expr (arg1, NULL_RTX, SImode, EXPAND_NORMAL); /* [I]0-7 */
- op1 = expand_expr (arg2, NULL_RTX, SImode, EXPAND_NORMAL); /* u8 */
- op2 = gen_rtx_REG (V8HImode, ARC_FIRST_SIMD_VR_REG); /* VR0 */
-
- /* target <- src vreg */
- emit_insn (gen_move_insn (target, src_vreg));
-
- /* target <- vec_concat: target, mem(Ib, u8) */
- mode0 = insn_data[icode].operand[3].mode;
- mode1 = insn_data[icode].operand[1].mode;
-
- if ( (!(*insn_data[icode].operand[3].predicate) (op0, mode0))
- || !(UNSIGNED_INT3 (INTVAL (op0))))
- error ("operand 1 of %s instruction should be an unsigned 3-bit value (I0-I7)",
- d->name);
-
- if ( (!(*insn_data[icode].operand[1].predicate) (op1, mode1))
- || !(UNSIGNED_INT8 (INTVAL (op1))))
- error ("operand 2 of %s instruction should be an unsigned 8-bit value",
- d->name);
-
- pat = GEN_FCN (icode) (target, op1, op2, op0);
- if (! pat)
- return 0;
-
- emit_insn (pat);
- return target;
- }
-
- case void_Va_Ib_u8:
- icode = d->icode;
- arg0 = CALL_EXPR_ARG (exp, 0); /* src vreg */
- arg1 = CALL_EXPR_ARG (exp, 1); /* [I]0-7 */
- arg2 = CALL_EXPR_ARG (exp, 2); /* u8 */
-
- op0 = gen_rtx_REG (V8HImode, ARC_FIRST_SIMD_VR_REG); /* VR0 */
- op1 = expand_expr (arg1, NULL_RTX, SImode, EXPAND_NORMAL); /* I[0-7] */
- op2 = expand_expr (arg2, NULL_RTX, SImode, EXPAND_NORMAL); /* u8 */
- op3 = expand_expr (arg0, NULL_RTX, V8HImode, EXPAND_NORMAL); /* Vdest */
-
- mode0 = insn_data[icode].operand[0].mode;
- mode1 = insn_data[icode].operand[1].mode;
- mode2 = insn_data[icode].operand[2].mode;
- mode3 = insn_data[icode].operand[3].mode;
-
- if ( (!(*insn_data[icode].operand[1].predicate) (op1, mode1))
- || !(UNSIGNED_INT3 (INTVAL (op1))))
- error ("operand 2 of %s instruction should be an unsigned 3-bit value (I0-I7)",
- d->name);
+ x = XEXP (x, 0);
- if ( (!(*insn_data[icode].operand[2].predicate) (op2, mode2))
- || !(UNSIGNED_INT8 (INTVAL (op2))))
- error ("operand 3 of %s instruction should be an unsigned 8-bit value",
- d->name);
+ if (GET_CODE (x) == PLUS)
+ {
+ if (GET_CODE (XEXP (x, 1)) == CONST_INT)
+ x = XEXP (x, 0);
+ }
- if (!(*insn_data[icode].operand[3].predicate) (op3, mode3))
- op3 = copy_to_mode_reg (mode3, op3);
+ if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_SMALL_P (x))
+ {
+ gcc_assert (SYMBOL_REF_TLS_MODEL (x) == 0);
+ return true;
+ }
+ return false;
+}
- pat = GEN_FCN (icode) (op0, op1, op2, op3);
- if (! pat)
- return 0;
+/* If possible, rewrite OP so that it refers to small data using
+ explicit relocations. */
- emit_insn (pat);
- return NULL_RTX;
+rtx
+arc_rewrite_small_data (rtx op)
+{
+ op = copy_insn (op);
+ subrtx_ptr_iterator::array_type array;
+ FOR_EACH_SUBRTX_PTR (iter, array, &op, ALL)
+ {
+ rtx *loc = *iter;
+ if (arc_rewrite_small_data_p (*loc))
+ {
+ gcc_assert (SDATA_BASE_REGNUM == PIC_OFFSET_TABLE_REGNUM);
+ *loc = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, *loc);
+ if (loc != &op)
+ {
+ if (GET_CODE (op) == MEM && &XEXP (op, 0) == loc)
+ ; /* OK. */
+ else if (GET_CODE (op) == MEM
+ && GET_CODE (XEXP (op, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (op, 0), 0)) == MULT)
+ *loc = force_reg (Pmode, *loc);
+ else
+ gcc_unreachable ();
+ }
+ iter.skip_subrtxes ();
+ }
+ else if (GET_CODE (*loc) == PLUS
+ && rtx_equal_p (XEXP (*loc, 0), pic_offset_table_rtx))
+ iter.skip_subrtxes ();
+ }
+ return op;
+}
- case Va_Ib_u8:
- icode = d->icode;
- arg0 = CALL_EXPR_ARG (exp, 0); /* dest vreg */
- arg1 = CALL_EXPR_ARG (exp, 1); /* [I]0-7 */
+/* Return true if OP refers to small data symbols directly, not through
+ a PLUS. */
- op0 = gen_rtx_REG (V8HImode, ARC_FIRST_SIMD_VR_REG); /* VR0 */
- op1 = expand_expr (arg0, NULL_RTX, SImode, EXPAND_NORMAL); /* I[0-7] */
- op2 = expand_expr (arg1, NULL_RTX, SImode, EXPAND_NORMAL); /* u8 */
+bool
+small_data_pattern (rtx op, machine_mode)
+{
+ if (GET_CODE (op) == SEQUENCE)
+ return false;
+ subrtx_iterator::array_type array;
+ FOR_EACH_SUBRTX (iter, array, op, ALL)
+ {
+ const_rtx x = *iter;
+ if (GET_CODE (x) == PLUS
+ && rtx_equal_p (XEXP (x, 0), pic_offset_table_rtx))
+ iter.skip_subrtxes ();
+ else if (arc_rewrite_small_data_p (x))
+ return true;
+ }
+ return false;
+}
- /* target <- src vreg */
- target = gen_reg_rtx (V8HImode);
+/* Return true if OP is an acceptable memory operand for ARCompact
+ 16-bit gp-relative load instructions.
+ op shd look like : [r26, symref@sda]
+ i.e. (mem (plus (reg 26) (symref with smalldata flag set))
+ */
+/* volatile cache option still to be handled. */
- /* target <- vec_concat: target, mem(Ib, u8) */
- mode0 = insn_data[icode].operand[1].mode;
- mode1 = insn_data[icode].operand[2].mode;
- mode2 = insn_data[icode].operand[3].mode;
+bool
+compact_sda_memory_operand (rtx op, machine_mode mode)
+{
+ rtx addr;
+ int size;
- if ( (!(*insn_data[icode].operand[2].predicate) (op1, mode1))
- || !(UNSIGNED_INT3 (INTVAL (op1))))
- error ("operand 1 of %s instruction should be an unsigned 3-bit value (I0-I7)",
- d->name);
+ /* Eliminate non-memory operations. */
+ if (GET_CODE (op) != MEM)
+ return false;
- if ( (!(*insn_data[icode].operand[3].predicate) (op2, mode2))
- || !(UNSIGNED_INT8 (INTVAL (op2))))
- error ("operand 2 of %s instruction should be an unsigned 8-bit value",
- d->name);
+ if (mode == VOIDmode)
+ mode = GET_MODE (op);
- pat = GEN_FCN (icode) (target, op0, op1, op2);
- if (! pat)
- return 0;
+ size = GET_MODE_SIZE (mode);
- emit_insn (pat);
- return target;
+ /* dword operations really put out 2 instructions, so eliminate them. */
+ if (size > UNITS_PER_WORD)
+ return false;
- case void_Va_u3_Ib_u8:
- icode = d->icode;
- arg0 = CALL_EXPR_ARG (exp, 0); /* source vreg */
- arg1 = CALL_EXPR_ARG (exp, 1); /* u3 */
- arg2 = CALL_EXPR_ARG (exp, 2); /* [I]0-7 */
- arg3 = CALL_EXPR_ARG (exp, 3); /* u8 */
-
- op0 = expand_expr (arg3, NULL_RTX, SImode, EXPAND_NORMAL); /* u8 */
- op1 = gen_rtx_REG (V8HImode, ARC_FIRST_SIMD_VR_REG); /* VR */
- op2 = expand_expr (arg2, NULL_RTX, SImode, EXPAND_NORMAL); /* [I]0-7 */
- op3 = expand_expr (arg0, NULL_RTX, V8HImode, EXPAND_NORMAL);/* vreg to be stored */
- op4 = expand_expr (arg1, NULL_RTX, SImode, EXPAND_NORMAL); /* vreg 0-7 subreg no. */
-
- mode0 = insn_data[icode].operand[0].mode;
- mode2 = insn_data[icode].operand[2].mode;
- mode3 = insn_data[icode].operand[3].mode;
- mode4 = insn_data[icode].operand[4].mode;
+ /* Decode the address now. */
+ addr = XEXP (op, 0);
- /* Do some correctness checks for the operands. */
- if ( (!(*insn_data[icode].operand[0].predicate) (op0, mode0))
- || !(UNSIGNED_INT8 (INTVAL (op0))))
- error ("operand 4 of %s instruction should be an unsigned 8-bit value (0-255)",
- d->name);
+ return LEGITIMATE_SMALL_DATA_ADDRESS_P (addr);
+}
- if ( (!(*insn_data[icode].operand[2].predicate) (op2, mode2))
- || !(UNSIGNED_INT3 (INTVAL (op2))))
- error ("operand 3 of %s instruction should be an unsigned 3-bit value (I0-I7)",
- d->name);
+/* Implement ASM_OUTPUT_ALIGNED_DECL_LOCAL. */
- if (!(*insn_data[icode].operand[3].predicate) (op3, mode3))
- op3 = copy_to_mode_reg (mode3, op3);
+void
+arc_asm_output_aligned_decl_local (FILE * stream, tree decl, const char * name,
+ unsigned HOST_WIDE_INT size,
+ unsigned HOST_WIDE_INT align,
+ unsigned HOST_WIDE_INT globalize_p)
+{
+ int in_small_data = arc_in_small_data_p (decl);
- if ( (!(*insn_data[icode].operand[4].predicate) (op4, mode4))
- || !(UNSIGNED_INT3 (INTVAL (op4))))
- error ("operand 2 of %s instruction should be an unsigned 3-bit value (subreg 0-7)",
- d->name);
- else if (icode == CODE_FOR_vst32_n_insn
- && ((INTVAL(op4) % 2 ) != 0))
- error ("operand 2 of %s instruction should be an even 3-bit value (subreg 0,2,4,6)",
- d->name);
+ if (in_small_data)
+ switch_to_section (get_named_section (NULL, ".sbss", 0));
+ /* named_section (0,".sbss",0); */
+ else
+ switch_to_section (bss_section);
- pat = GEN_FCN (icode) (op0, op1, op2, op3, op4);
- if (! pat)
- return 0;
+ if (globalize_p)
+ (*targetm.asm_out.globalize_label) (stream, name);
- emit_insn (pat);
- return NULL_RTX;
+ ASM_OUTPUT_ALIGN (stream, floor_log2 ((align) / BITS_PER_UNIT));
+ ASM_OUTPUT_TYPE_DIRECTIVE (stream, name, "object");
+ ASM_OUTPUT_SIZE_DIRECTIVE (stream, name, size);
+ ASM_OUTPUT_LABEL (stream, name);
- default:
- gcc_unreachable ();
- }
- return NULL_RTX;
+ if (size != 0)
+ ASM_OUTPUT_SKIP (stream, size);
}
static bool
return 8;
/* Force an attempt to 'mov Dy,Dx' to spill. */
- if (TARGET_ARC700 && TARGET_DPFP
+ if ((TARGET_ARC700 || TARGET_EM) && TARGET_DPFP
&& from_class == DOUBLE_REGS && to_class == DOUBLE_REGS)
return 100;
int
arc_output_addsi (rtx *operands, bool cond_p, bool output_p)
{
- char format[32];
+ char format[35];
int match = operands_match_p (operands[0], operands[1]);
int match2 = operands_match_p (operands[0], operands[2]);
case AND:
if (satisfies_constraint_C1p (operands[2]))
pat = "bmsk%? %0,%1,%Z2";
+ else if (satisfies_constraint_C2p (operands[2]))
+ {
+ operands[2] = GEN_INT ((~INTVAL (operands[2])));
+ pat = "bmskn%? %0,%1,%Z2";
+ }
else if (satisfies_constraint_Ccp (operands[2]))
pat = "bclr%? %0,%1,%M2";
else if (satisfies_constraint_CnL (operands[2]))
return addr;
}
-/* Like move_by_pieces, but take account of load latency,
- and actual offset ranges.
- Return true on success. */
+/* Like move_by_pieces, but take account of load latency, and actual
+ offset ranges. Return true on success. */
bool
arc_expand_movmem (rtx *operands)
size = INTVAL (operands[2]);
/* move_by_pieces_ninsns is static, so we can't use it. */
if (align >= 4)
- n_pieces = (size + 2) / 4U + (size & 1);
+ {
+ if (TARGET_LL64)
+ n_pieces = (size + 4) / 8U + ((size >> 1) & 1) + (size & 1);
+ else
+ n_pieces = (size + 2) / 4U + (size & 1);
+ }
else if (align == 2)
n_pieces = (size + 1) / 2U;
else
n_pieces = size;
if (n_pieces >= (unsigned int) (optimize_size ? 3 : 15))
return false;
- if (piece > 4)
+ /* Force 32 bit aligned and larger datum to use 64 bit transfers, if
+ possible. */
+ if (TARGET_LL64 && (piece >= 4) && (size >= 8))
+ piece = 8;
+ else if (piece > 4)
piece = 4;
dst_addr = force_offsettable (XEXP (operands[0], 0), size, 0);
src_addr = force_offsettable (XEXP (operands[1], 0), size, 0);
rtx tmp;
machine_mode mode;
- if (piece > size)
- piece = size & -size;
+ while (piece > size)
+ piece >>= 1;
mode = smallest_mode_for_size (piece * BITS_PER_UNIT, MODE_INT);
/* If we don't re-use temporaries, the scheduler gets carried away,
and the register pressure gets unnecessarily high. */
{
/* We used to do this only for MODE_INT Modes, but addresses to floating
point variables may well be in the small data section. */
- if (1)
- {
- if (!TARGET_NO_SDATA_SET && small_data_pattern (operands[0], Pmode))
- operands[0] = arc_rewrite_small_data (operands[0]);
- else if (mode == SImode && flag_pic && SYMBOLIC_CONST (operands[1]))
- {
- emit_pic_move (operands, SImode);
-
- /* Disable any REG_EQUALs associated with the symref
- otherwise the optimization pass undoes the work done
- here and references the variable directly. */
- }
- else if (GET_CODE (operands[0]) != MEM
- && !TARGET_NO_SDATA_SET
- && small_data_pattern (operands[1], Pmode))
- {
- /* This is to take care of address calculations involving sdata
- variables. */
- operands[1] = arc_rewrite_small_data (operands[1]);
-
- emit_insn (gen_rtx_SET (operands[0],operands[1]));
- /* ??? This note is useless, since it only restates the set itself.
- We should rather use the original SYMBOL_REF. However, there is
- the problem that we are lying to the compiler about these
- SYMBOL_REFs to start with. symbol@sda should be encoded specially
- so that we can tell it apart from an actual symbol. */
- set_unique_reg_note (get_last_insn (), REG_EQUAL, operands[1]);
-
- /* Take care of the REG_EQUAL note that will be attached to mark the
- output reg equal to the initial symbol_ref after this code is
- executed. */
- emit_move_insn (operands[0], operands[0]);
- return true;
- }
+ if (!TARGET_NO_SDATA_SET && small_data_pattern (operands[0], Pmode))
+ operands[0] = arc_rewrite_small_data (operands[0]);
+
+ if (mode == SImode && SYMBOLIC_CONST (operands[1]))
+ {
+ prepare_pic_move (operands, SImode);
+
+ /* Disable any REG_EQUALs associated with the symref
+ otherwise the optimization pass undoes the work done
+ here and references the variable directly. */
+ }
+
+ if (GET_CODE (operands[0]) != MEM
+ && !TARGET_NO_SDATA_SET
+ && small_data_pattern (operands[1], Pmode))
+ {
+ /* This is to take care of address calculations involving sdata
+ variables. */
+ operands[1] = arc_rewrite_small_data (operands[1]);
+
+ emit_insn (gen_rtx_SET (operands[0],operands[1]));
+ /* ??? This note is useless, since it only restates the set itself.
+ We should rather use the original SYMBOL_REF. However, there is
+ the problem that we are lying to the compiler about these
+ SYMBOL_REFs to start with. symbol@sda should be encoded specially
+ so that we can tell it apart from an actual symbol. */
+ set_unique_reg_note (get_last_insn (), REG_EQUAL, operands[1]);
+
+ /* Take care of the REG_EQUAL note that will be attached to mark the
+ output reg equal to the initial symbol_ref after this code is
+ executed. */
+ emit_move_insn (operands[0], operands[0]);
+ return true;
}
if (MEM_P (operands[0])
|| (TARGET_MEDIUM_CALLS && arc_ccfsm_cond_exec_p ()))
{
if (flag_pic)
- sprintf (buf, "add r12,pcl,@%s-(.&-4)\n\tjl%%!%%* [r12]", fname);
+ sprintf (buf, "add r12,pcl,@%s@pcl\n\tjl%%!%%* [r12]", fname);
else
sprintf (buf, "jl%%! @%s", fname);
}
jump = pred;
else if (GET_CODE (PATTERN (pred)) == SEQUENCE
&& JUMP_P (XVECEXP (PATTERN (pred), 0, 0)))
- jump = as_a <rtx_insn *> XVECEXP (PATTERN (pred), 0, 0);
+ jump = as_a <rtx_insn *> (XVECEXP (PATTERN (pred), 0, 0));
else
return false;
static rtx
arc_legitimize_address (rtx orig_x, rtx oldx, machine_mode mode)
{
+ if (GET_CODE (orig_x) == SYMBOL_REF)
+ {
+ enum tls_model model = SYMBOL_REF_TLS_MODEL (orig_x);
+ if (model != 0)
+ return arc_legitimize_tls_address (orig_x, model);
+ }
+
rtx new_x = arc_legitimize_address_0 (orig_x, oldx, mode);
if (new_x)
static rtx
arc_delegitimize_address_0 (rtx x)
{
- rtx u, gp;
+ rtx u, gp, p;
if (GET_CODE (x) == CONST && GET_CODE (u = XEXP (x, 0)) == UNSPEC)
{
- if (XINT (u, 1) == ARC_UNSPEC_GOT)
+ if (XINT (u, 1) == ARC_UNSPEC_GOT
+ || XINT (u, 1) == ARC_UNSPEC_GOTOFFPC)
return XVECEXP (u, 0, 0);
}
+ else if (GET_CODE (x) == CONST && GET_CODE (p = XEXP (x, 0)) == PLUS
+ && GET_CODE (u = XEXP (p, 0)) == UNSPEC
+ && (XINT (u, 1) == ARC_UNSPEC_GOT
+ || XINT (u, 1) == ARC_UNSPEC_GOTOFFPC))
+ return gen_rtx_CONST
+ (GET_MODE (x),
+ gen_rtx_PLUS (GET_MODE (p), XVECEXP (u, 0, 0), XEXP (p, 1)));
else if (GET_CODE (x) == PLUS
&& ((REG_P (gp = XEXP (x, 0))
&& REGNO (gp) == PIC_OFFSET_TABLE_REGNUM)
Operand 0: destination register
Operand 1: source register */
-static rtx
+static bool
arc_process_double_reg_moves (rtx *operands)
{
rtx dest = operands[0];
rtx src = operands[1];
- rtx val;
enum usesDxState { none, srcDx, destDx, maxDx };
enum usesDxState state = none;
}
if (state == none)
- return NULL_RTX;
-
- start_sequence ();
+ return false;
if (state == srcDx)
{
{
/* When we have 'mov D, r' or 'mov D, D' then get the target
register pair for use with LR insn. */
- rtx destHigh = simplify_gen_subreg(SImode, dest, DFmode, 4);
- rtx destLow = simplify_gen_subreg(SImode, dest, DFmode, 0);
+ rtx destHigh = simplify_gen_subreg (SImode, dest, DFmode,
+ TARGET_BIG_ENDIAN ? 0 : 4);
+ rtx destLow = simplify_gen_subreg (SImode, dest, DFmode,
+ TARGET_BIG_ENDIAN ? 4 : 0);
/* Produce the two LR insns to get the high and low parts. */
emit_insn (gen_rtx_SET (destHigh,
- gen_rtx_UNSPEC_VOLATILE (Pmode, gen_rtvec (1, src),
- VUNSPEC_LR_HIGH)));
+ gen_rtx_UNSPEC_VOLATILE (Pmode,
+ gen_rtvec (1, src),
+ VUNSPEC_ARC_LR_HIGH)));
emit_insn (gen_rtx_SET (destLow,
- gen_rtx_UNSPEC_VOLATILE (Pmode, gen_rtvec (1, src),
- VUNSPEC_LR)));
+ gen_rtx_UNSPEC_VOLATILE (Pmode,
+ gen_rtvec (1, src),
+ VUNSPEC_ARC_LR)));
}
}
else if (state == destDx)
{
/* When we have 'mov r, D' or 'mov D, D' and we have access to the
LR insn get the target register pair. */
- rtx srcHigh = simplify_gen_subreg(SImode, src, DFmode, 4);
- rtx srcLow = simplify_gen_subreg(SImode, src, DFmode, 0);
-
- emit_insn (gen_rtx_UNSPEC_VOLATILE (Pmode,
- gen_rtvec (3, dest, srcHigh, srcLow),
- VUNSPEC_DEXCL_NORES));
+ rtx srcHigh = simplify_gen_subreg (SImode, src, DFmode,
+ TARGET_BIG_ENDIAN ? 0 : 4);
+ rtx srcLow = simplify_gen_subreg (SImode, src, DFmode,
+ TARGET_BIG_ENDIAN ? 4 : 0);
+ emit_insn (gen_dexcl_2op (dest, srcHigh, srcLow));
}
else
gcc_unreachable ();
- val = get_insns ();
- end_sequence ();
- return val;
+ return true;
}
/* operands 0..1 are the operands of a 64 bit move instruction.
split it into two moves with operands 2/3 and 4/5. */
-rtx
+void
arc_split_move (rtx *operands)
{
machine_mode mode = GET_MODE (operands[0]);
int i;
int swap = 0;
rtx xop[4];
- rtx val;
if (TARGET_DPFP)
{
- val = arc_process_double_reg_moves (operands);
- if (val)
- return val;
+ if (arc_process_double_reg_moves (operands))
+ return;
}
+ if (TARGET_LL64
+ && ((memory_operand (operands[0], mode)
+ && even_register_operand (operands[1], mode))
+ || (memory_operand (operands[1], mode)
+ && even_register_operand (operands[0], mode))))
+ {
+ emit_move_insn (operands[0], operands[1]);
+ return;
+ }
+
+ if (TARGET_PLUS_QMACW
+ && GET_CODE (operands[1]) == CONST_VECTOR)
+ {
+ HOST_WIDE_INT intval0, intval1;
+ if (GET_MODE (operands[1]) == V2SImode)
+ {
+ intval0 = INTVAL (XVECEXP (operands[1], 0, 0));
+ intval1 = INTVAL (XVECEXP (operands[1], 0, 1));
+ }
+ else
+ {
+ intval1 = INTVAL (XVECEXP (operands[1], 0, 3)) << 16;
+ intval1 |= INTVAL (XVECEXP (operands[1], 0, 2)) & 0xFFFF;
+ intval0 = INTVAL (XVECEXP (operands[1], 0, 1)) << 16;
+ intval0 |= INTVAL (XVECEXP (operands[1], 0, 0)) & 0xFFFF;
+ }
+ xop[0] = gen_rtx_REG (SImode, REGNO (operands[0]));
+ xop[3] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
+ xop[2] = GEN_INT (trunc_int_for_mode (intval0, SImode));
+ xop[1] = GEN_INT (trunc_int_for_mode (intval1, SImode));
+ emit_move_insn (xop[0], xop[2]);
+ emit_move_insn (xop[3], xop[1]);
+ return;
+ }
+
for (i = 0; i < 2; i++)
{
if (MEM_P (operands[i]) && auto_inc_p (XEXP (operands[i], 0)))
swap = 2;
gcc_assert (!reg_overlap_mentioned_p (xop[2], xop[1]));
}
- operands[2+swap] = xop[0];
- operands[3+swap] = xop[1];
- operands[4-swap] = xop[2];
- operands[5-swap] = xop[3];
- start_sequence ();
- emit_insn (gen_rtx_SET (operands[2], operands[3]));
- emit_insn (gen_rtx_SET (operands[4], operands[5]));
- val = get_insns ();
- end_sequence ();
+ emit_move_insn (xop[0 + swap], xop[1 + swap]);
+ emit_move_insn (xop[2 - swap], xop[3 - swap]);
- return val;
}
/* Select between the instruction output templates s_tmpl (for short INSNs)
long.) */
int
-arc_label_align (rtx label)
+arc_label_align (rtx_insn *label)
{
int loop_align = LOOP_ALIGN (LABEL);
bool
arc_epilogue_uses (int regno)
{
+ if (regno == arc_tp_regno)
+ return true;
if (reload_completed)
{
if (ARC_INTERRUPT_P (cfun->machine->fn_type))
return regno == arc_return_address_regs[arc_compute_function_type (cfun)];
}
+/* Helper for EH_USES macro. */
+
+bool
+arc_eh_uses (int regno)
+{
+ if (regno == arc_tp_regno)
+ return true;
+ return false;
+}
+
#ifndef TARGET_NO_LRA
#define TARGET_NO_LRA !TARGET_LRA
#endif
{
int very_unlikely = REG_BR_PROB_BASE / 100 - 1;
- insn = emit_jump_insn (insn);
- add_int_reg_note (insn, REG_BR_PROB, very_unlikely);
+ rtx_insn *jump = emit_jump_insn (insn);
+ add_int_reg_note (jump, REG_BR_PROB, very_unlikely);
}
/* Expand code to perform a 8 or 16-bit compare and swap by doing
return true;
}
+/* Return a parallel of registers to represent where to find the
+ register pieces if required, otherwise NULL_RTX. */
+
+static rtx
+arc_dwarf_register_span (rtx rtl)
+{
+ machine_mode mode = GET_MODE (rtl);
+ unsigned regno;
+ rtx p;
+
+ if (GET_MODE_SIZE (mode) != 8)
+ return NULL_RTX;
+
+ p = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (2));
+ regno = REGNO (rtl);
+ XVECEXP (p, 0, 0) = gen_rtx_REG (SImode, regno);
+ XVECEXP (p, 0, 1) = gen_rtx_REG (SImode, regno + 1);
+
+ return p;
+}
+
+/* Return true if OP is an acceptable memory operand for ARCompact
+ 16-bit load instructions of MODE.
+
+ AV2SHORT: TRUE if address needs to fit into the new ARCv2 short
+ non scaled instructions.
+
+ SCALED: TRUE if address can be scaled. */
+
+bool
+compact_memory_operand_p (rtx op, machine_mode mode,
+ bool av2short, bool scaled)
+{
+ rtx addr, plus0, plus1;
+ int size, off;
+
+ /* Eliminate non-memory operations. */
+ if (GET_CODE (op) != MEM)
+ return 0;
+
+ /* .di instructions have no 16-bit form. */
+ if (MEM_VOLATILE_P (op) && !TARGET_VOLATILE_CACHE_SET)
+ return false;
+
+ if (mode == VOIDmode)
+ mode = GET_MODE (op);
+
+ size = GET_MODE_SIZE (mode);
+
+ /* dword operations really put out 2 instructions, so eliminate
+ them. */
+ if (size > UNITS_PER_WORD)
+ return false;
+
+ /* Decode the address now. */
+ addr = XEXP (op, 0);
+ switch (GET_CODE (addr))
+ {
+ case REG:
+ return (REGNO (addr) >= FIRST_PSEUDO_REGISTER
+ || COMPACT_GP_REG_P (REGNO (addr))
+ || (SP_REG_P (REGNO (addr)) && (size != 2)));
+ case PLUS:
+ plus0 = XEXP (addr, 0);
+ plus1 = XEXP (addr, 1);
+
+ if ((GET_CODE (plus0) == REG)
+ && ((REGNO (plus0) >= FIRST_PSEUDO_REGISTER)
+ || COMPACT_GP_REG_P (REGNO (plus0)))
+ && ((GET_CODE (plus1) == REG)
+ && ((REGNO (plus1) >= FIRST_PSEUDO_REGISTER)
+ || COMPACT_GP_REG_P (REGNO (plus1)))))
+ {
+ return !av2short;
+ }
+
+ if ((GET_CODE (plus0) == REG)
+ && ((REGNO (plus0) >= FIRST_PSEUDO_REGISTER)
+ || (COMPACT_GP_REG_P (REGNO (plus0)) && !av2short)
+ || (IN_RANGE (REGNO (plus0), 0, 31) && av2short))
+ && (GET_CODE (plus1) == CONST_INT))
+ {
+ bool valid = false;
+
+ off = INTVAL (plus1);
+
+ /* Negative offset is not supported in 16-bit load/store insns. */
+ if (off < 0)
+ return 0;
+
+ /* Only u5 immediates allowed in code density instructions. */
+ if (av2short)
+ {
+ switch (size)
+ {
+ case 1:
+ return false;
+ case 2:
+ /* This is an ldh_s.x instruction, check the u6
+ immediate. */
+ if (COMPACT_GP_REG_P (REGNO (plus0)))
+ valid = true;
+ break;
+ case 4:
+ /* Only u5 immediates allowed in 32bit access code
+ density instructions. */
+ if (REGNO (plus0) <= 31)
+ return ((off < 32) && (off % 4 == 0));
+ break;
+ default:
+ return false;
+ }
+ }
+ else
+ if (COMPACT_GP_REG_P (REGNO (plus0)))
+ valid = true;
+
+ if (valid)
+ {
+
+ switch (size)
+ {
+ case 1:
+ return (off < 32);
+ case 2:
+ /* The 6-bit constant get shifted to fit the real
+ 5-bits field. Check also for the alignment. */
+ return ((off < 64) && (off % 2 == 0));
+ case 4:
+ return ((off < 128) && (off % 4 == 0));
+ default:
+ return false;
+ }
+ }
+ }
+
+ if (REG_P (plus0) && CONST_INT_P (plus1)
+ && ((REGNO (plus0) >= FIRST_PSEUDO_REGISTER)
+ || SP_REG_P (REGNO (plus0)))
+ && !av2short)
+ {
+ off = INTVAL (plus1);
+ return ((size != 2) && (off >= 0 && off < 128) && (off % 4 == 0));
+ }
+
+ if ((GET_CODE (plus0) == MULT)
+ && (GET_CODE (XEXP (plus0, 0)) == REG)
+ && ((REGNO (XEXP (plus0, 0)) >= FIRST_PSEUDO_REGISTER)
+ || COMPACT_GP_REG_P (REGNO (XEXP (plus0, 0))))
+ && (GET_CODE (plus1) == REG)
+ && ((REGNO (plus1) >= FIRST_PSEUDO_REGISTER)
+ || COMPACT_GP_REG_P (REGNO (plus1))))
+ return scaled;
+ default:
+ break ;
+ /* TODO: 'gp' and 'pcl' are to supported as base address operand
+ for 16-bit load instructions. */
+ }
+ return false;
+}
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-arc.h"