[ARC] Rework code for profiling.
[gcc.git] / gcc / config / arc / arc.c
index d3a6f27332a288a4b9cf7f3eb7e61a9e7103f29d..9a72786e00f538e3fbb016019520a14c656edccd 100644 (file)
@@ -1,5 +1,5 @@
 /* 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.
@@ -31,6 +31,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
+#include "memmodel.h"
 #include "backend.h"
 #include "target.h"
 #include "rtl.h"
@@ -64,7 +65,8 @@ along with GCC; see the file COPYING3.  If not see
 #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.  */
@@ -175,164 +177,6 @@ struct GTY (()) arc_ccfsm
    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
@@ -375,7 +219,6 @@ static rtx arc_expand_builtin (tree, rtx, rtx, machine_mode, int);
 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);
@@ -385,7 +228,6 @@ static bool arc_in_small_data_p (const_tree);
 
 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 &,
@@ -401,21 +243,58 @@ static bool arc_use_by_pieces_infrastructure_p (unsigned HOST_WIDE_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;
@@ -456,6 +335,9 @@ static void arc_finalize_pic (void);
 #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
 
@@ -501,6 +383,12 @@ static void arc_finalize_pic (void);
 #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
 
@@ -576,6 +464,14 @@ static void arc_finalize_pic (void);
 #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.  */
@@ -780,42 +676,9 @@ make_pass_arc_predicate_delay_insns (gcc::context *ctxt)
 
 /* 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)
@@ -846,18 +709,10 @@ arc_init (void)
        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");
 
@@ -870,15 +725,10 @@ arc_init (void)
   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)
@@ -889,9 +739,6 @@ arc_init (void)
       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.  */
@@ -936,11 +783,106 @@ static void
 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;
 
@@ -1075,6 +1017,33 @@ get_arc_condition_code (rtx comparison)
        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*/
@@ -1158,19 +1127,46 @@ arc_select_cc_mode (enum rtx_code op, rtx x, rtx y)
        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;
 }
 
@@ -1289,7 +1285,12 @@ arc_init_reg_tables (void)
            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:
@@ -1297,7 +1298,8 @@ arc_init_reg_tables (void)
             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;
@@ -1354,6 +1356,14 @@ arc_conditional_register_usage (void)
       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;
@@ -1431,11 +1441,22 @@ arc_conditional_register_usage (void)
        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;
@@ -1452,12 +1473,12 @@ arc_conditional_register_usage (void)
        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);
 
@@ -1525,6 +1546,19 @@ arc_conditional_register_usage (void)
 
   /* 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
@@ -1694,6 +1728,30 @@ gen_compare_reg (rtx comparison, machine_mode omode)
                                                 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);
@@ -1787,10 +1845,11 @@ arc_setup_incoming_varargs (cumulative_args_t args_so_far,
   /* 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.  */
 
@@ -1830,6 +1889,8 @@ arc_address_cost (rtx addr, machine_mode, addr_space_t, bool speed)
     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);
 
@@ -2331,9 +2392,26 @@ arc_save_restore (rtx base_reg,
 
       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;
 
@@ -2349,7 +2427,7 @@ arc_save_restore (rtx base_reg,
                  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 =
@@ -2368,6 +2446,11 @@ arc_save_restore (rtx base_reg,
              else
                frame_move_inc (mem, reg, base_reg, addr);
              offset += UNITS_PER_WORD;
+             if (mode == DImode)
+               {
+                 offset += UNITS_PER_WORD;
+                 ++regno;
+               }
            } /* if */
        } /* for */
     }/* if */
@@ -2688,6 +2771,15 @@ arc_return_slot_offset ()
 
 /* 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
@@ -2713,9 +2805,7 @@ arc_finalize_pic (void)
   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);
@@ -2957,6 +3047,8 @@ static int output_scaled = 0;
     '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
@@ -3007,6 +3099,24 @@ arc_print_operand (FILE *file, rtx x, int code)
 
       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
@@ -3177,19 +3287,17 @@ arc_print_operand (FILE *file, rtx x, int code)
       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;
@@ -3391,9 +3499,19 @@ arc_print_operand (FILE *file, rtx x, int code)
          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
        {
@@ -3458,6 +3576,18 @@ arc_print_operand_address (FILE *file , rtx addr)
       {
        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);
 
@@ -3480,97 +3610,6 @@ arc_print_operand_address (FILE *file , rtx addr)
     }
 }
 
-/* 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.
@@ -3999,9 +4038,8 @@ arc_ccfsm_post_advance (rtx_insn *insn, struct arc_ccfsm *state)
           && 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))
@@ -4282,6 +4320,24 @@ arc_encode_section_info (tree decl, rtx rtl, int first)
 
       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
@@ -4376,17 +4432,16 @@ arc_rtx_costs (rtx x, machine_mode mode, int outer_code,
 
     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;
       }
 
@@ -4529,6 +4584,45 @@ arc_rtx_costs (rtx x, machine_mode mode, int outer_code,
     }
 }
 
+/* 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.  */
 
@@ -4537,17 +4631,8 @@ arc_legitimate_pc_offset_p (rtx addr)
 {
   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.
@@ -4576,9 +4661,12 @@ arc_legitimate_pic_addr_p (rtx addr)
       || 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
@@ -4636,6 +4724,10 @@ arc_raw_symbolic_reference_mentioned_p (rtx op, bool skip_local)
 
   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);
     }
@@ -4662,57 +4754,141 @@ arc_raw_symbolic_reference_mentioned_p (rtx op, bool skip_local)
   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;
@@ -4725,6 +4901,7 @@ arc_legitimize_pic_address (rtx orig, rtx 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);
@@ -4734,45 +4911,23 @@ arc_legitimize_pic_address (rtx orig, rtx oldx)
        {
          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);
            }
        }
     }
@@ -4888,26 +5043,51 @@ arc_output_pic_addr_const (FILE * file, rtx x, int code)
 
 
     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");
@@ -4921,15 +5101,18 @@ arc_output_pic_addr_const (FILE * file, rtx x, int code)
 
 /* 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);
+    }
 }
 
 
@@ -4983,8 +5166,6 @@ arc_arg_partial_bytes (cumulative_args_t cum_v, machine_mode mode,
   return ret;
 }
 
-
-
 /* This function is used to control a function argument is passed in a
    register, and which register.
 
@@ -5022,8 +5203,10 @@ arc_arg_partial_bytes (cumulative_args_t cum_v, machine_mode mode,
    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;
@@ -5069,8 +5252,10 @@ arc_function_arg (cumulative_args_t cum_v, machine_mode mode,
    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
@@ -5129,9 +5314,12 @@ arc_legitimate_pic_operand_p (rtx x)
    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))
@@ -5141,7 +5329,9 @@ arc_legitimate_constant_p (machine_mode, rtx 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);
        }
@@ -5152,8 +5342,11 @@ arc_legitimate_constant_p (machine_mode, rtx x)
          {
          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:
@@ -5167,9 +5360,14 @@ arc_legitimate_constant_p (machine_mode, rtx x)
       /* 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;
@@ -5192,12 +5390,29 @@ arc_legitimate_address_p (machine_mode mode, rtx x, bool strict)
      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
@@ -5241,91 +5456,256 @@ arc_cannot_force_const_mem (machine_mode mode, rtx x)
   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
@@ -5336,314 +5716,396 @@ static rtx arc_expand_simd_builtin (tree, rtx, rtx, machine_mode, int);
 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
@@ -5679,6 +6141,7 @@ check_if_valid_sleep_operand (rtx *operands, int opno)
     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");
@@ -5804,47 +6267,6 @@ arc_is_shortcall_p (rtx sym_ref)
 
 }
 
-/* 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
@@ -5953,6 +6375,58 @@ arc_invalid_within_doloop (const rtx_insn *insn)
   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.  */
@@ -5971,6 +6445,29 @@ workaround_arc_anomaly (void)
          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;
@@ -5991,25 +6488,6 @@ arc_reorg (void)
   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))
@@ -6309,6 +6787,11 @@ arc_reorg (void)
 
          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);
@@ -6331,7 +6814,7 @@ arc_reorg (void)
                      break;
                    }
                }
-             if (! link_insn)
+             if (!link_insn)
                continue;
              else
                /* Check if this is a data dependency.  */
@@ -6580,935 +7063,136 @@ static bool
 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
@@ -7545,7 +7229,7 @@ arc_register_move_cost (machine_mode,
     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;
 
@@ -7560,7 +7244,7 @@ arc_register_move_cost (machine_mode,
 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]);
@@ -7675,6 +7359,11 @@ arc_output_commutative_cond_exec (rtx *operands, bool output_p)
       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]))
@@ -7729,9 +7418,8 @@ force_offsettable (rtx addr, HOST_WIDE_INT size, bool reuse)
   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)
@@ -7752,14 +7440,23 @@ 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);
@@ -7770,8 +7467,8 @@ arc_expand_movmem (rtx *operands)
       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.  */
@@ -7803,40 +7500,39 @@ prepare_move_operands (rtx *operands, machine_mode mode)
 {
   /* 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])
@@ -7921,7 +7617,7 @@ arc_output_libcall (const char *fname)
      || (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);
     }
@@ -8064,7 +7760,7 @@ arc_loop_hazard (rtx_insn *pred, rtx_insn *succ)
     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;
 
@@ -8834,6 +8530,13 @@ arc_legitimize_address_0 (rtx x, rtx oldx ATTRIBUTE_UNUSED,
 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)
@@ -8844,13 +8547,21 @@ arc_legitimize_address (rtx orig_x, rtx oldx, machine_mode mode)
 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)
@@ -9206,12 +8917,11 @@ split_subsi (rtx *operands)
    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;
@@ -9226,9 +8936,7 @@ arc_process_double_reg_moves (rtx *operands)
     }
 
   if (state == none)
-    return NULL_RTX;
-
-  start_sequence ();
+    return false;
 
   if (state == srcDx)
     {
@@ -9246,57 +8954,91 @@ arc_process_double_reg_moves (rtx *operands)
        {
          /* 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)))
@@ -9344,18 +9086,10 @@ arc_split_move (rtx *operands)
       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)
@@ -9478,7 +9212,7 @@ arc_scheduling_not_expected (void)
    long.)  */
 
 int
-arc_label_align (rtx label)
+arc_label_align (rtx_insn *label)
 {
   int loop_align = LOOP_ALIGN (LABEL);
 
@@ -9571,6 +9305,8 @@ arc_can_follow_jump (const rtx_insn *follower, const rtx_insn *followee)
 bool
 arc_epilogue_uses (int regno)
 {
+  if (regno == arc_tp_regno)
+    return true;
   if (reload_completed)
     {
       if (ARC_INTERRUPT_P (cfun->machine->fn_type))
@@ -9586,6 +9322,16 @@ arc_epilogue_uses (int regno)
     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
@@ -9736,8 +9482,8 @@ emit_unlikely_jump (rtx insn)
 {
   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
@@ -10070,6 +9816,167 @@ arc_no_speculation_in_delay_slots_p ()
   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"