This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] [ARC] GAS: add instruction relaxation.


This patch adds instruction relaxation support for ARC-GAS. The assembly-time
relaxation implementation has been made with an extendible design
in mind.  This was done by using a table driven design.
The work on assembly-time relaxation was mainly carried on by Janek van
Oirschot as part of his intership at Synopsys.  I have cleaned up and
reorganized the code a bit.  I also added some tests for relaxation.

Comments are well appreciated,
Claudiu

gas/
2016-01-26  Claudiu Zissulescu  <claziss@synopsys.com>
	    Janek van Oirschot  <jvanoirs@synopsys.com>

        * config/tc-arc.h (TC_FRAG_TYPE, TC_PCREL_ADJUST, MAX_INSN_ARGS)
        (MAX_INSN_FLGS, MAX_FLAG_NAME_LENGHT, TC_GENERIC_RELAX_TABLE):
        Define.
        (arc_flags, arc_relax_type): New structure.
        * config/tc-arc.c (FRAG_MAX_GROWTH, RELAX_TABLE_ENTRY)
	(RELAX_TABLE_ENTRY_MAX): New define.
        (relaxation_state, md_relax_table, arc_relaxable_insns)
	(arc_num_relaxable_ins): New variable.
	(rlx_operand_type, arc_rlx_types): New enums.
	(arc_relaxable_ins): New structure.
        (OPTION_RELAX): New option.
        (arc_insn): New relax member.
        (arc_flags): Remove.
        (relax_insn_p): New function.
        (apply_fixups): Likewise.
        (relaxable_operand): Likewise.
        (may_relax_expr): Likewise.
        (relaxable_flag): Likewise.
        (arc_pcrel_adjust): Likewise.
        (md_estimate_size_before_relax): Implement.
        (md_convert_frag): Likewise.
        (md_parse_option): Handle new mrelax option.
        (md_show_usage): Likewise.
        (assemble_insn): Set relax member.
        (emit_insn0): New function.
        (emit_insn1): Likewise.
        (emit_insn): Handle relaxation case.

gas/testsuite
2016-01-26  Claudiu Zissulescu  <claziss@synopsys.com>

        * gas/arc/relax-avoid1.d: New file.
        * gas/arc/relax-avoid1.s: Likewise.
        * gas/arc/relax-avoid2.d: Likewise.
        * gas/arc/relax-avoid2.s: Likewise.
        * gas/arc/relax-avoid3.d: Likewise.
        * gas/arc/relax-avoid3.s: Likewise.
	* gas/arc/relax-b.d: Likewise.
        * gas/arc/relax-b.s: Likewise.

include/opcode/
2016-01-26  Claudiu Zissulescu  <claziss@synopsys.com>
	    Janek van Oirschot  <jvanoirs@synopsys.com>

        * arc.h (arc_opcode arc_relax_opcodes, arc_num_relax_opcodes):
        Declare.

opcodes/
2016-01-26  Claudiu Zissulescu  <claziss@synopsys.com>
	    Janek van Oirschot  <jvanoirs@synopsys.com>

        * arc-opc.c (arc_relax_opcodes, arc_num_relax_opcodes): New
        variable.
---
 gas/config/tc-arc.c                  | 630 +++++++++++++++++++++++++++++++----
 gas/config/tc-arc.h                  |  56 ++++
 gas/testsuite/gas/arc/relax-avoid1.d |  13 +
 gas/testsuite/gas/arc/relax-avoid1.s |  11 +
 gas/testsuite/gas/arc/relax-avoid2.d |  14 +
 gas/testsuite/gas/arc/relax-avoid2.s |   4 +
 gas/testsuite/gas/arc/relax-avoid3.d |  14 +
 gas/testsuite/gas/arc/relax-avoid3.s |   5 +
 gas/testsuite/gas/arc/relax-b.d      |  19 ++
 gas/testsuite/gas/arc/relax-b.s      |  11 +
 include/opcode/arc.h                 |   8 +
 opcodes/arc-opc.c                    | 126 +++++++
 12 files changed, 844 insertions(+), 67 deletions(-)
 create mode 100644 gas/testsuite/gas/arc/relax-avoid1.d
 create mode 100644 gas/testsuite/gas/arc/relax-avoid1.s
 create mode 100644 gas/testsuite/gas/arc/relax-avoid2.d
 create mode 100644 gas/testsuite/gas/arc/relax-avoid2.s
 create mode 100644 gas/testsuite/gas/arc/relax-avoid3.d
 create mode 100644 gas/testsuite/gas/arc/relax-avoid3.s
 create mode 100644 gas/testsuite/gas/arc/relax-b.d
 create mode 100644 gas/testsuite/gas/arc/relax-b.s

diff --git a/gas/config/tc-arc.c b/gas/config/tc-arc.c
index 40ba0ad..c2115a6 100644
--- a/gas/config/tc-arc.c
+++ b/gas/config/tc-arc.c
@@ -31,9 +31,9 @@
 
 /* Defines section.  */
 
-#define MAX_FLAG_NAME_LENGHT 3
 #define MAX_INSN_FIXUPS      2
 #define MAX_CONSTR_STR       20
+#define FRAG_MAX_GROWTH      8
 
 #ifdef DEBUG
 # define pr_debug(fmt, args...) fprintf (stderr, fmt, ##args)
@@ -49,6 +49,45 @@
 /* Equal to MAX_PRECISION in atof-ieee.c.  */
 #define MAX_LITTLENUMS 6
 
+/* Enum used to enumerate the relaxable ins operands.  */
+enum rlx_operand_type
+  {
+    EMPTY = 0,
+    REGISTER,
+    REGISTER_S, /* Register for short instruction(s).  */
+    REGISTER_NO_GP, /* Is a register but not gp register specifically.  */
+    REGISTER_DUP, /* Duplication of previous operand of type register.  */
+    IMMEDIATE,
+    BRACKET
+  };
+
+enum arc_rlx_types
+  {
+    ARC_RLX_NONE = 0,
+    ARC_RLX_BL_S,
+    ARC_RLX_BL,
+    ARC_RLX_B_S,
+    ARC_RLX_B,
+    ARC_RLX_ADD_U3,
+    ARC_RLX_ADD_U6,
+    ARC_RLX_ADD_LIMM,
+    ARC_RLX_LD_U7,
+    ARC_RLX_LD_S9,
+    ARC_RLX_LD_LIMM,
+    ARC_RLX_MOV_U8,
+    ARC_RLX_MOV_S12,
+    ARC_RLX_MOV_LIMM,
+    ARC_RLX_SUB_U3,
+    ARC_RLX_SUB_U6,
+    ARC_RLX_SUB_LIMM,
+    ARC_RLX_MPY_U6,
+    ARC_RLX_MPY_LIMM,
+    ARC_RLX_MOV_RU6,
+    ARC_RLX_MOV_RLIMM,
+    ARC_RLX_ADD_RRU6,
+    ARC_RLX_ADD_RRLIMM,
+  };
+
 /* Macros section.  */
 
 #define regno(x)		((x) & 0x3F)
@@ -83,6 +122,9 @@ extern int target_big_endian;
 const char *arc_target_format = DEFAULT_TARGET_FORMAT;
 static int byte_order = DEFAULT_BYTE_ORDER;
 
+/* By default relaxation is disabled.  */
+static int relaxation_state = 0;
+
 extern int arc_get_mach (char *);
 
 /* Forward declaration.  */
@@ -121,6 +163,7 @@ enum options
 
   OPTION_MCPU,
   OPTION_CD,
+  OPTION_RELAX,
 
   /* The following options are deprecated and provided here only for
      compatibility reasons.  */
@@ -162,6 +205,7 @@ struct option md_longopts[] =
   { "mEM",		no_argument,	   NULL, OPTION_ARCEM },
   { "mHS",		no_argument,	   NULL, OPTION_ARCHS },
   { "mcode-density",	no_argument,	   NULL, OPTION_CD },
+  { "mrelax",           no_argument,       NULL, OPTION_RELAX },
 
   /* The following options are deprecated and provided here only for
      compatibility reasons.  */
@@ -242,6 +286,8 @@ struct arc_insn
 			     short.  */
   bfd_boolean has_limm;   /* Boolean value: TRUE if limm field is
 			     valid.  */
+  bfd_boolean relax;	  /* Boolean value: TRUE if needs
+			     relaxation.  */
 };
 
 /* Structure to hold any last two instructions.  */
@@ -298,15 +344,6 @@ static const struct cpu_type
   { 0, 0, 0, 0, 0 }
 };
 
-struct arc_flags
-{
-  /* Name of the parsed flag.  */
-  char name[MAX_FLAG_NAME_LENGHT+1];
-
-  /* The code of the parsed flag.  Valid when is not zero.  */
-  unsigned char code;
-};
-
 /* Used by the arc_reloc_op table.  Order is important.  */
 #define O_gotoff  O_md1     /* @gotoff relocation.  */
 #define O_gotpc   O_md2     /* @gotpc relocation.  */
@@ -371,6 +408,131 @@ static const struct arc_reloc_op_tag
 static const int arc_num_reloc_op
 = sizeof (arc_reloc_op) / sizeof (*arc_reloc_op);
 
+/* Structure for relaxable instruction that have to be swapped with a
+   smaller alternative instruction.  */
+struct arc_relaxable_ins
+{
+  /* Mnemonic that should be checked.  */
+  const char *mnemonic_r;
+
+  /* Operands that should be checked.
+     Indexes of operands from operand array.  */
+  enum rlx_operand_type operands[6];
+
+  /* Flags that should be checked. */
+  unsigned flag_classes[5];
+
+  /* Mnemonic (smaller) alternative to be used later for relaxation.  */
+  const char *mnemonic_alt;
+
+  /* Index of operand that generic relaxation has to check.  */
+  unsigned opcheckidx;
+
+  /* Base subtype index used.  */
+  enum arc_rlx_types subtype;
+};
+
+#define RELAX_TABLE_ENTRY(BITS, ISSIGNED, SIZE, NEXT)			\
+  { (ISSIGNED) ? ((1 << ((BITS) - 1)) - 1) : ((1 << (BITS)) - 1),	\
+      (ISSIGNED) ? -(1 << ((BITS) - 1)) : 0,				\
+      (SIZE),								\
+      (NEXT) }								\
+
+#define RELAX_TABLE_ENTRY_MAX(ISSIGNED, SIZE, NEXT)	\
+  { (ISSIGNED) ? 0x7FFFFFFF : 0xFFFFFFFF,		\
+      (ISSIGNED) ? -(0x7FFFFFFF) : 0,                   \
+      (SIZE),                                           \
+      (NEXT) }                                          \
+
+
+/* ARC relaxation table.  */
+const relax_typeS md_relax_table[] =
+ {
+    /* Fake entry. */
+    {0, 0, 0, 0},
+
+    /* BL_S s13 ->
+       BL s25.  */
+    RELAX_TABLE_ENTRY(13, 1, 2, ARC_RLX_BL),
+    RELAX_TABLE_ENTRY(25, 1, 4, ARC_RLX_NONE),
+
+    /* B_S s10 ->
+       B s25.  */
+    RELAX_TABLE_ENTRY(10, 1, 2, ARC_RLX_B),
+    RELAX_TABLE_ENTRY(25, 1, 4, ARC_RLX_NONE),
+
+    /* ADD_S c,b, u3 ->
+       ADD<.f> a,b,u6 ->
+       ADD<.f> a,b,limm.  */
+    RELAX_TABLE_ENTRY(3, 0, 2, ARC_RLX_ADD_U6),
+    RELAX_TABLE_ENTRY(6, 0, 4, ARC_RLX_ADD_LIMM),
+    RELAX_TABLE_ENTRY_MAX(0, 8, ARC_RLX_NONE),
+
+    /* LD_S a, [b, u7] ->
+       LD<zz><.x><.aa><.di> a, [b, s9] ->
+       LD<zz><.x><.aa><.di> a, [b, limm] */
+    RELAX_TABLE_ENTRY(7, 0, 2, ARC_RLX_LD_S9),
+    RELAX_TABLE_ENTRY(9, 1, 4, ARC_RLX_LD_LIMM),
+    RELAX_TABLE_ENTRY_MAX(1, 8, ARC_RLX_NONE),
+
+    /* MOV_S b, u8 ->
+       MOV<.f> b, s12 ->
+       MOV<.f> b, limm.  */
+    RELAX_TABLE_ENTRY(8, 0, 2, ARC_RLX_MOV_S12),
+    RELAX_TABLE_ENTRY(8, 0, 4, ARC_RLX_MOV_LIMM),
+    RELAX_TABLE_ENTRY_MAX(0, 8, ARC_RLX_NONE),
+
+    /* SUB_S c, b, u3 ->
+       SUB<.f> a, b, u6 ->
+       SUB<.f> a, b, limm.  */
+    RELAX_TABLE_ENTRY(3, 0, 2, ARC_RLX_SUB_U6),
+    RELAX_TABLE_ENTRY(6, 0, 4, ARC_RLX_SUB_LIMM),
+    RELAX_TABLE_ENTRY_MAX(0, 8, ARC_RLX_NONE),
+
+    /* MPY<.f> a, b, u6 ->
+       MPY<.f> a, b, limm.  */
+    RELAX_TABLE_ENTRY(6, 0, 4, ARC_RLX_MPY_LIMM),
+    RELAX_TABLE_ENTRY_MAX(0, 8, ARC_RLX_NONE),
+
+    /* MOV<.f><.cc> b, u6 ->
+       MOV<.f><.cc> b, limm.  */
+    RELAX_TABLE_ENTRY(6, 0, 4, ARC_RLX_MOV_RLIMM),
+    RELAX_TABLE_ENTRY_MAX(0, 8, ARC_RLX_NONE),
+
+    /* ADD<.f><.cc> b, b, u6 ->
+       ADD<.f><.cc> b, b, limm.  */
+    RELAX_TABLE_ENTRY(6, 0, 4, ARC_RLX_ADD_RRLIMM),
+    RELAX_TABLE_ENTRY_MAX(0, 8, ARC_RLX_NONE),
+  };
+
+/* Order of this table's entries matters!  */
+const struct arc_relaxable_ins arc_relaxable_insns[] =
+  {
+    { "bl", { IMMEDIATE }, { 0 }, "bl_s", 0, ARC_RLX_BL_S },
+    { "b", { IMMEDIATE }, { 0 }, "b_s", 0, ARC_RLX_B_S },
+    { "add", { REGISTER, REGISTER_DUP, IMMEDIATE }, { 5, 1, 0 }, "add",
+      2, ARC_RLX_ADD_RRU6},
+    { "add", { REGISTER_S, REGISTER_S, IMMEDIATE }, { 0 }, "add_s", 2,
+      ARC_RLX_ADD_U3 },
+    { "add", { REGISTER, REGISTER, IMMEDIATE }, { 5, 0 }, "add", 2,
+      ARC_RLX_ADD_U6 },
+    { "ld", { REGISTER_S, BRACKET, REGISTER_S, IMMEDIATE, BRACKET },
+      { 0 }, "ld_s", 3, ARC_RLX_LD_U7 },
+    { "ld", { REGISTER, BRACKET, REGISTER_NO_GP, IMMEDIATE, BRACKET },
+      { 11, 4, 14, 17, 0 }, "ld", 3, ARC_RLX_LD_S9 },
+    { "mov", { REGISTER_S, IMMEDIATE }, { 0 }, "mov_s", 1, ARC_RLX_MOV_U8 },
+    { "mov", { REGISTER, IMMEDIATE }, { 5, 0 }, "mov", 1, ARC_RLX_MOV_S12 },
+    { "mov", { REGISTER, IMMEDIATE }, { 5, 1, 0 },"mov", 1, ARC_RLX_MOV_RU6 },
+    { "sub", { REGISTER_S, REGISTER_S, IMMEDIATE }, { 0 }, "sub_s", 2,
+      ARC_RLX_SUB_U3 },
+    { "sub", { REGISTER, REGISTER, IMMEDIATE }, { 5, 0 }, "sub", 2,
+      ARC_RLX_SUB_U6 },
+    { "mpy", { REGISTER, REGISTER, IMMEDIATE }, { 5, 0 }, "mpy", 2,
+      ARC_RLX_MPY_U6 },
+  };
+
+const unsigned arc_num_relaxable_ins = ARRAY_SIZE (arc_relaxable_insns);
+
 /* Flags to set in the elf header.  */
 static flagword arc_eflag = 0x00;
 
@@ -406,6 +568,12 @@ static const struct arc_opcode *find_special_case_pseudo (const char *,
 							  expressionS *,
 							  int *,
 							  struct arc_flags *);
+static bfd_boolean relax_insn_p (const struct arc_opcode *opcode,
+				 const expressionS *tok,
+				 int ntok,
+				 const struct arc_flags *pflags,
+				 int nflg);
+static void emit_insn0 (struct arc_insn *insn, char *where, bfd_boolean relax);
 
 /* Functions implementation.  */
 
@@ -1470,16 +1638,33 @@ md_apply_fix (fixS *fixP,
    fr_var starts with a value.  */
 
 int
-md_estimate_size_before_relax (fragS *fragP ATTRIBUTE_UNUSED,
-			       segT segment ATTRIBUTE_UNUSED)
+md_estimate_size_before_relax (fragS *fragP,
+			       segT segment)
 {
-  int growth = 4;
+  int growth;
+
+  /* If the symbol is not located within the same section AND it's not
+     an absolute section, use the maximum.  OR if the symbol is a
+     constant AND the insn is by nature not pc-rel, use the maximum.
+     OR if the symbol is being equated against another symbol, use the
+     maximum.  OR if the symbol is weak use the maximum.  */
+  if ((S_GET_SEGMENT (fragP->fr_symbol) != segment
+       && S_GET_SEGMENT (fragP->fr_symbol) != absolute_section)
+      || (symbol_constant_p (fragP->fr_symbol)
+	  && !fragP->tc_frag_data.pcrel)
+      || symbol_equated_p (fragP->fr_symbol)
+      || S_IS_WEAK (fragP->fr_symbol))
+    {
+      while (md_relax_table[fragP->fr_subtype].rlx_more != ARC_RLX_NONE)
+	++fragP->fr_subtype;
+    }
+
+  growth = md_relax_table[fragP->fr_subtype].rlx_length;
+  fragP->fr_var = growth;
 
-  fragP->fr_var = 4;
   pr_debug ("%s:%d: md_estimate_size_before_relax: %d\n",
 	   fragP->fr_file, fragP->fr_line, growth);
 
-  as_fatal (_("md_estimate_size_before_relax\n"));
   return growth;
 }
 
@@ -1552,6 +1737,70 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED,
   return reloc;
 }
 
+/* Apply the fixups in order.  */
+
+static void
+apply_fixups (struct arc_insn *insn,
+	      fragS *fragP,
+	      int fix)
+{
+  int i;
+
+  for (i = 0; i < insn->nfixups; i++)
+    {
+      struct arc_fixup *fixup = &insn->fixups[i];
+      int size, pcrel, offset = 0;
+
+      /*FIXME! the reloc size is wrong in the BFD file.  When it will
+	be fixed please delete me.  */
+      size = (insn->short_insn && !fixup->islong) ? 2 : 4;
+
+      if (fixup->islong)
+	offset = (insn->short_insn) ? 2 : 4;
+
+      /* Some fixups are only used internally, thus no howto.  */
+      if ((int) fixup->reloc == 0)
+	{
+	  as_fatal (_("Unhandled reloc type"));
+	}
+      if ((int) fixup->reloc < 0)
+	{
+	  /*FIXME! the reloc size is wrong in the BFD file.  When it
+	    will be fixed please enable me.
+	    size = (insn->short_insn && !fixup->islong) ? 2 : 4; */
+	  pcrel = fixup->pcrel;
+	}
+      else
+	{
+	  reloc_howto_type *reloc_howto =
+	    bfd_reloc_type_lookup (stdoutput,
+				   (bfd_reloc_code_real_type) fixup->reloc);
+	  gas_assert (reloc_howto);
+	  /*FIXME! the reloc size is wrong in the BFD file.  When it
+	    will be fixed please enable me.
+	    size = bfd_get_reloc_size (reloc_howto); */
+	  pcrel = reloc_howto->pc_relative;
+	}
+
+      pr_debug ("%s:%d: apply_fixups: new %s fixup (PCrel:%s) of size %d @ \
+offset %d + %d\n",
+		fragP->fr_file, fragP->fr_line,
+		(fixup->reloc < 0) ? "Internal" :
+		bfd_get_reloc_code_name (fixup->reloc),
+		pcrel ? "Y" : "N",
+		size, fix, offset);
+      fix_new_exp (fragP, fix + offset,
+		   size, &fixup->exp, pcrel, fixup->reloc);
+
+      /* Check for ZOLs, and update symbol info if any.  */
+      if (LP_INSN (insn->insn))
+	{
+	  gas_assert (fixup->exp.X_add_symbol);
+	  ARC_SET_FLAG (fixup->exp.X_add_symbol, ARC_FLAG_ZOL);
+	}
+    }
+}
+
 /* Perform post-processing of machine-dependent frags after relaxation.
    Called after relaxation is finished.
    In:	Address of frag.
@@ -1563,12 +1812,40 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED,
 void
 md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
 		 segT segment ATTRIBUTE_UNUSED,
-		 fragS *fragP ATTRIBUTE_UNUSED)
+		 fragS *fragP)
 {
+  const relax_typeS *table_entry;
+  char *dest;
+  const struct arc_opcode *opcode;
+  struct arc_insn insn;
+  int size, fix;
+  struct arc_relax_type *relax_arg = &fragP->tc_frag_data;
+
+  fix = (fragP->fr_fix < 0 ? 0 : fragP->fr_fix);
+  dest = fragP->fr_literal + fix;
+  table_entry = TC_GENERIC_RELAX_TABLE + fragP->fr_subtype;
+
   pr_debug ("%s:%d: md_convert_frag, subtype: %d, fix: %d, var: %d\n",
 	    fragP->fr_file, fragP->fr_line,
-	    fragP->fr_subtype, fragP->fr_fix, fragP->fr_var);
-  abort ();
+	    fragP->fr_subtype, fix, fragP->fr_var);
+
+  if (fragP->fr_subtype <= 0
+      && fragP->fr_subtype >= arc_num_relax_opcodes)
+    as_fatal (_("no relaxation found for this instruction."));
+
+  opcode = &arc_relax_opcodes[fragP->fr_subtype];
+
+  assemble_insn (opcode, relax_arg->tok, relax_arg->ntok, relax_arg->pflags,
+	relax_arg->nflg, &insn);
+
+  apply_fixups (&insn, fragP, fix);
+
+  size = insn.short_insn ? (insn.has_limm ? 6 : 2) : (insn.has_limm ? 8 : 4);
+  gas_assert (table_entry->rlx_length == size);
+  emit_insn0 (&insn, dest, TRUE);
+
+  fragP->fr_fix += table_entry->rlx_length;
+  fragP->fr_var = 0;
 }
 
 /* We have no need to default values of symbols.  We could catch
@@ -1665,6 +1942,7 @@ arc_parse_name (const char *name,
    -mcpu=<cpu name>		 Assemble for selected processor
    -EB/-mbig-endian		 Big-endian
    -EL/-mlittle-endian		 Little-endian
+   -mrelax                       Enable relaxation
 
    The following CPU names are recognized:
    arc700, av2em, av2hs.  */
@@ -1741,6 +2019,10 @@ md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
 	arc_features |= ARC_CD;
       break;
 
+    case OPTION_RELAX:
+      relaxation_state = 1;
+      break;
+
     case OPTION_USER_MODE:
     case OPTION_LD_EXT_MASK:
     case OPTION_SWAP:
@@ -1790,6 +2072,9 @@ md_show_usage (FILE *stream)
   -EB                     assemble code for a big-endian cpu\n"));
   fprintf (stream, _("\
   -EL                     assemble code for a little-endian cpu\n"));
+  fprintf (stream, _("\
+  -mrelax                  Enable relaxation\n"));
+
 }
 
 static void
@@ -2859,6 +3144,8 @@ assemble_insn (const struct arc_opcode *opcode,
 	  << flg_operand->shift;
     }
 
+  insn->relax = relax_insn_p (opcode, tok, ntok, pflags, nflg);
+
   /* Short instruction?  */
   insn->short_insn = ARC_SHORT (opcode->mask) ? TRUE : FALSE;
 
@@ -2880,10 +3167,9 @@ assemble_insn (const struct arc_opcode *opcode,
 /* Actually output an instruction with its fixup.  */
 
 static void
-emit_insn (struct arc_insn *insn)
+emit_insn0 (struct arc_insn *insn, char *where, bfd_boolean relax)
 {
-  char *f;
-  int i;
+  char *f = where;
 
   pr_debug ("Emit insn : 0x%x\n", insn->insn);
   pr_debug ("\tShort   : 0x%d\n", insn->short_insn);
@@ -2894,14 +3180,16 @@ emit_insn (struct arc_insn *insn)
     {
       if (insn->has_limm)
 	{
-	  f = frag_more (6);
+	  if (!relax)
+	    f = frag_more (6);
 	  md_number_to_chars (f, insn->insn, 2);
 	  md_number_to_chars_midend (f + 2, insn->limm, 4);
 	  dwarf2_emit_insn (6);
 	}
       else
 	{
-	  f = frag_more (2);
+	  if (!relax)
+	    f = frag_more (2);
 	  md_number_to_chars (f, insn->insn, 2);
 	  dwarf2_emit_insn (2);
 	}
@@ -2910,68 +3198,73 @@ emit_insn (struct arc_insn *insn)
     {
       if (insn->has_limm)
 	{
-	  f = frag_more (8);
+	  if (!relax)
+	    f = frag_more (8);
 	  md_number_to_chars_midend (f, insn->insn, 4);
 	  md_number_to_chars_midend (f + 4, insn->limm, 4);
 	  dwarf2_emit_insn (8);
 	}
       else
 	{
-	  f = frag_more (4);
+	  if (!relax)
+	    f = frag_more (4);
 	  md_number_to_chars_midend (f, insn->insn, 4);
 	  dwarf2_emit_insn (4);
 	}
     }
 
-  /* Apply the fixups in order.  */
-  for (i = 0; i < insn->nfixups; i++)
+  if (!relax)
+    apply_fixups (insn, frag_now, (f - frag_now->fr_literal));
+}
+
+static void
+emit_insn1 (struct arc_insn *insn)
+{
+  /* How frag_var's args are currently configured:
+     - rs_machine_dependent, to dictate it's a relaxation frag.
+     - FRAG_MAX_GROWTH, maximum size of instruction
+     - 0, variable size that might grow...unused by generic relaxation.
+     - frag_now->fr_subtype, fr_subtype starting value, set previously.
+     - s, opand expression.
+     - 0, offset but it's unused.
+     - 0, opcode but it's unused.  */
+  symbolS *s = make_expr_symbol (&insn->fixups[0].exp);
+  frag_now->tc_frag_data.pcrel = insn->fixups[0].pcrel;
+
+  if (frag_room () < FRAG_MAX_GROWTH)
     {
-      struct arc_fixup *fixup = &insn->fixups[i];
-      int size, pcrel, offset = 0;
+      /* Handle differently when frag literal memory is exhausted.
+	 This is used because when there's not enough memory left in
+	 the current frag, a new frag is created and the information
+	 we put into frag_now->tc_frag_data is disregarded.  */
 
-      /*FIXME! the reloc size is wrong in the BFD file.  When it will
-	be fixed please delete me.  */
-      size = (insn->short_insn && !fixup->islong) ? 2 : 4;
+      struct arc_relax_type relax_info_copy;
+      relax_substateT subtype = frag_now->fr_subtype;
 
-      if (fixup->islong)
-	offset = (insn->short_insn) ? 2 : 4;
+      memcpy (&relax_info_copy, &frag_now->tc_frag_data,
+	      sizeof (struct arc_relax_type));
 
-      /* Some fixups are only used internally, thus no howto.  */
-      if ((int) fixup->reloc < 0)
-	{
-	  /*FIXME! the reloc size is wrong in the BFD file.  When it
-	    will be fixed please enable me.
-	    size = (insn->short_insn && !fixup->islong) ? 2 : 4; */
-	  pcrel = fixup->pcrel;
-	}
-      else
-	{
-	  reloc_howto_type *reloc_howto =
-	    bfd_reloc_type_lookup (stdoutput,
-				   (bfd_reloc_code_real_type) fixup->reloc);
-	  gas_assert (reloc_howto);
-	  /*FIXME! the reloc size is wrong in the BFD file.  When it
-	    will be fixed please enable me.
-	    size = bfd_get_reloc_size (reloc_howto); */
-	  pcrel = reloc_howto->pc_relative;
-	}
+      frag_wane (frag_now);
+      frag_grow (FRAG_MAX_GROWTH);
 
-      pr_debug ("%s:%d: emit_insn: new %s fixup (PCrel:%s) of size %d @ offset %d\n",
-		frag_now->fr_file, frag_now->fr_line,
-		(fixup->reloc < 0) ? "Internal" :
-		bfd_get_reloc_code_name (fixup->reloc),
-		pcrel ? "Y" : "N",
-		size, offset);
-      fix_new_exp (frag_now, f - frag_now->fr_literal + offset,
-		   size, &fixup->exp, pcrel, fixup->reloc);
+      memcpy (&frag_now->tc_frag_data, &relax_info_copy,
+	      sizeof (struct arc_relax_type));
 
-      /* Check for ZOLs, and update symbol info if any.  */
-      if (LP_INSN (insn->insn))
-	{
-	  gas_assert (fixup->exp.X_add_symbol);
-	  ARC_SET_FLAG (fixup->exp.X_add_symbol, ARC_FLAG_ZOL);
-	}
+      frag_var (rs_machine_dependent, FRAG_MAX_GROWTH, 0,
+		subtype, s, 0, 0);
     }
+  else
+    frag_var (rs_machine_dependent, FRAG_MAX_GROWTH, 0,
+	      frag_now->fr_subtype, s, 0, 0);
+}
+
+static void
+emit_insn (struct arc_insn *insn)
+{
+  if (insn->relax)
+    emit_insn1 (insn);
+  else
+    emit_insn0 (insn, NULL, FALSE);
 }
 
 /* Insert an operand value into an instruction.  */
@@ -3201,3 +3494,206 @@ arc_frob_label (symbolS * sym)
 
   dwarf2_emit_label (sym);
 }
+
+/* Checks if operands are in line with relaxable insn.  */
+
+static bfd_boolean
+relaxable_operand (const struct arc_relaxable_ins *ins,
+		   const expressionS *tok,
+		   int ntok)
+{
+  const enum rlx_operand_type *operand = &ins->operands[0];
+  int i = 0;
+
+  while (*operand != EMPTY)
+    {
+      const expressionS *epr = &tok[i];
+
+      if (i != 0 && i >= ntok)
+	return FALSE;
+
+      switch (*operand)
+	{
+	case IMMEDIATE:
+	  if (!(epr->X_op == O_multiply
+		|| epr->X_op == O_divide
+		|| epr->X_op == O_modulus
+		|| epr->X_op == O_add
+		|| epr->X_op == O_subtract
+		|| epr->X_op == O_symbol))
+	    return FALSE;
+	  break;
+
+	case REGISTER_DUP:
+	  if ((i <= 0)
+	      || (epr->X_add_number != tok[i - 1].X_add_number))
+	    return FALSE;
+	  /* Fall through.  */
+	case REGISTER:
+	  if (epr->X_op != O_register)
+	    return FALSE;
+	  break;
+
+	case REGISTER_S:
+	  if (epr->X_op != O_register)
+	    return FALSE;
+
+	  switch (epr->X_add_number)
+	    {
+	    case 0:case 1:case 2:case 3:
+	    case 12:case 13:case 14:case 15:
+	      break;
+	    default:
+	      return FALSE;
+	    }
+	  break;
+
+	case REGISTER_NO_GP:
+	  if ((epr->X_op != O_register)
+	      || (epr->X_add_number == 26)) /* 26 is the gp register.  */
+	    return FALSE;
+	  break;
+
+	case BRACKET:
+	  if (epr->X_op != O_bracket)
+	    return FALSE;
+	  break;
+
+	default:
+	  /* Don't understand, bail out.  */
+	  return FALSE;
+	  break;
+	}
+
+      ++i;
+      operand = &ins->operands[i];
+    }
+
+  return (i == ntok ? TRUE : FALSE);
+}
+
+/* Checks if flags are in line with relaxable insn.  */
+
+static bfd_boolean
+relaxable_flag (const struct arc_relaxable_ins *ins,
+		const struct arc_flags *pflags,
+		int nflgs)
+{
+  unsigned flag_class,
+    flag,
+    flag_class_idx = 0,
+    flag_idx = 0;
+
+  const struct arc_flag_operand *flag_opand;
+  int i, counttrue = 0;
+
+  /* Iterate through flags classes.  */
+  while ((flag_class = ins->flag_classes[flag_class_idx]) != 0)
+    {
+      /* Iterate through flags in flag class.  */
+      while ((flag = arc_flag_classes[flag_class].flags[flag_idx])
+	     != 0)
+	{
+	  flag_opand = &arc_flag_operands[flag];
+	  /* Iterate through flags in ins to compare.  */
+	  for (i = 0; i < nflgs; ++i)
+	    {
+	      if (strcmp (flag_opand->name, pflags[i].name) == 0)
+		++counttrue;
+	    }
+
+	  ++flag_idx;
+	}
+
+      ++flag_class_idx;
+      flag_idx = 0;
+    }
+
+  /* If counttrue == nflgs, then all flags have been found.  */
+  return (counttrue == nflgs ? TRUE : FALSE);
+}
+
+/* All the symbol types that are allowed to be used for
+   relaxation.  */
+
+static bfd_boolean
+may_relax_expr (expressionS tok)
+{
+  /* Check if we have unrelaxable relocs.  */
+  switch (tok.X_md)
+    {
+    default:
+      break;
+    case O_plt:
+      return FALSE;
+    }
+
+  switch (tok.X_op)
+    {
+    case O_symbol:
+    case O_multiply:
+    case O_divide:
+    case O_modulus:
+    case O_add:
+    case O_subtract:
+      break;
+
+    default:
+      return FALSE;
+    }
+  return TRUE;
+}
+
+/* Return TRUE if this OPDCODE is a candidate for relaxation.  */
+
+static bfd_boolean
+relax_insn_p (const struct arc_opcode *opcode,
+	      const expressionS *tok,
+	      int ntok,
+	      const struct arc_flags *pflags,
+	      int nflg)
+{
+  unsigned i;
+  bfd_boolean rv = FALSE;
+
+  /* Check the relaxation table.  */
+  for (i = 0; i < arc_num_relaxable_ins && relaxation_state; ++i)
+    {
+      const struct arc_relaxable_ins *arc_rlx_ins = &arc_relaxable_insns[i];
+
+      if ((strcmp (opcode->name, arc_rlx_ins->mnemonic_r) == 0)
+	  && may_relax_expr (tok[arc_rlx_ins->opcheckidx])
+	  && relaxable_operand (arc_rlx_ins, tok, ntok)
+	  && relaxable_flag (arc_rlx_ins, pflags, nflg))
+	{
+	  rv = TRUE;
+	  frag_now->fr_subtype = arc_relaxable_insns[i].subtype;
+	  memcpy (&frag_now->tc_frag_data.tok, tok,
+		sizeof (expressionS) * ntok);
+	  memcpy (&frag_now->tc_frag_data.pflags, pflags,
+		sizeof (struct arc_flags) * nflg);
+	  frag_now->tc_frag_data.nflg = nflg;
+	  frag_now->tc_frag_data.ntok = ntok;
+	  break;
+	}
+    }
+
+  return rv;
+}
+
+/* Used because generic relaxation assumes a pc-rel value whilst we
+   also relax instructions that use an absolute value resolved out of
+   relative values (if that makes any sense).  An example: 'add r1,
+   r2, @.L2 - .'  The symbols . and @.L2 are relative to the section
+   but if they're in the same section we can subtract the section
+   offset relocation which ends up in a resolved value.  So if @.L2 is
+   .text + 0x50 and . is .text + 0x10, we can say that .text + 0x50 -
+   .text + 0x40 = 0x10.  */
+int
+arc_pcrel_adjust (fragS *fragP)
+{
+  if (!fragP->tc_frag_data.pcrel)
+    return fragP->fr_address + fragP->fr_fix;
+
+  return 0;
+}
diff --git a/gas/config/tc-arc.h b/gas/config/tc-arc.h
index ca5b152..acd007b 100644
--- a/gas/config/tc-arc.h
+++ b/gas/config/tc-arc.h
@@ -177,6 +177,14 @@ extern long md_pcrel_from_section (struct fix *, segT);
 /* This hook is required to parse register names as operands.  */
 #define md_parse_name(name, exp, m, c) arc_parse_name (name, exp)
 
+/* Used within frags to pass some information to some relaxation
+   machine dependent values.  */
+#define TC_FRAG_TYPE struct arc_relax_type
+
+/* Adjust non PC-rel values at relaxation time.  */
+#define TC_PCREL_ADJUST(F) arc_pcrel_adjust (F)
+
+extern int arc_pcrel_adjust (fragS *);
 extern bfd_boolean arc_parse_name (const char *, struct expressionS *);
 extern int tc_arc_fix_adjustable (struct fix *);
 extern void arc_handle_align (fragS *);
@@ -193,3 +201,51 @@ extern void arc_frob_label (symbolS *);
 #define NOP_OPCODE_S   0x000078E0
 #define NOP_OPCODE_L   0x264A7000 /* mov 0,0.  */
 
+#define MAX_FLAG_NAME_LENGHT 3
+
+struct arc_flags
+{
+  /* Name of the parsed flag.  */
+  char name[MAX_FLAG_NAME_LENGHT + 1];
+
+  /* The code of the parsed flag.  Valid when is not zero.  */
+  unsigned char code;
+};
+
+#ifndef MAX_INSN_ARGS
+#define MAX_INSN_ARGS	     6
+#endif
+
+#ifndef MAX_INSN_FLGS
+#define MAX_INSN_FLGS	     3
+#endif
+
+extern const relax_typeS md_relax_table[];
+#define TC_GENERIC_RELAX_TABLE md_relax_table
+
+/* Used to construct instructions at md_convert_frag stage of
+   relaxation.  */
+struct arc_relax_type
+{
+  /* Dictates whether the pc-relativity should be kept in mind when
+     relax_frag is called or whether the pc-relativity should be
+     solved outside of relaxation.  For clarification: BL(_S) and
+     B(_S) use pcrel == 1 and ADD with a solvable expression as 3rd
+     operand use pcrel == 0.  */
+  unsigned char pcrel;
+
+  /* Expressions that dictate the operands.  Used for re-assembling in
+     md_convert_frag.  */
+  expressionS tok[MAX_INSN_ARGS];
+
+  /* Number of tok (i.e. number of operands).  Used for re-assembling
+     in md_convert_frag.  */
+  int ntok;
+
+  /* Flags of instruction.  Used for re-assembling in
+     md_convert_frag.  */
+  struct arc_flags pflags[MAX_INSN_FLGS];
+
+  /* Number of flags.  Used for re-assembling in md_convert_frag.  */
+  int nflg;
+};
diff --git a/gas/testsuite/gas/arc/relax-avoid1.d b/gas/testsuite/gas/arc/relax-avoid1.d
new file mode 100644
index 0000000..3d6d74e
--- /dev/null
+++ b/gas/testsuite/gas/arc/relax-avoid1.d
@@ -0,0 +1,13 @@
+#as: -mcpu=archs -mrelax
+#objdump: -dr
+
+.*: +file format .*arc.*
+
+
+Disassembly of section .text:
+
+00000000 <.text>:
+   0:	78e0                	nop_s
+   2:	240a 0f80 0000 0000 	mov	r4,0
+			6: R_ARC_32_ME	.LC2
+   a:	78e0                	nop_s
diff --git a/gas/testsuite/gas/arc/relax-avoid1.s b/gas/testsuite/gas/arc/relax-avoid1.s
new file mode 100644
index 0000000..82fbe63
--- /dev/null
+++ b/gas/testsuite/gas/arc/relax-avoid1.s
@@ -0,0 +1,11 @@
+	.section	.rodata
+	.align 4
+.LC2:
+	.word	0x01
+	.word	0x02
+	.word	0x03
+
+	.section	.text
+	.align 4
+	nop_s
+	mov r4,@.LC2
diff --git a/gas/testsuite/gas/arc/relax-avoid2.d b/gas/testsuite/gas/arc/relax-avoid2.d
new file mode 100644
index 0000000..fd602b4
--- /dev/null
+++ b/gas/testsuite/gas/arc/relax-avoid2.d
@@ -0,0 +1,14 @@
+#as: -mcpu=archs -mrelax
+#objdump: -dr
+
+.*: +file format .*arc.*
+
+
+Disassembly of section .text:
+
+00000000 <test>:
+   0:	2000 0000           	add	r0,r0,r0
+
+00000004 <main>:
+   4:	0802 0000           	bl	0 <test>
+			4: R_ARC_S25W_PCREL_PLT	test
diff --git a/gas/testsuite/gas/arc/relax-avoid2.s b/gas/testsuite/gas/arc/relax-avoid2.s
new file mode 100644
index 0000000..703064d
--- /dev/null
+++ b/gas/testsuite/gas/arc/relax-avoid2.s
@@ -0,0 +1,4 @@
+test:
+	add	r0,r0,r0
+main:
+	bl @test@plt
diff --git a/gas/testsuite/gas/arc/relax-avoid3.d b/gas/testsuite/gas/arc/relax-avoid3.d
new file mode 100644
index 0000000..7b177fb
--- /dev/null
+++ b/gas/testsuite/gas/arc/relax-avoid3.d
@@ -0,0 +1,14 @@
+#as: -mcpu=archs -mrelax
+#objdump: -dr
+
+.*: +file format .*arc.*
+
+
+Disassembly of section .text:
+
+00000000 <test>:
+   0:	2000 0000           	add	r0,r0,r0
+
+00000004 <main>:
+   4:	0001 0000           	b	0 <test>
+			4: R_ARC_S25H_PCREL	test
diff --git a/gas/testsuite/gas/arc/relax-avoid3.s b/gas/testsuite/gas/arc/relax-avoid3.s
new file mode 100644
index 0000000..dc913a4
--- /dev/null
+++ b/gas/testsuite/gas/arc/relax-avoid3.s
@@ -0,0 +1,5 @@
+test:
+	add	r0,r0,r0
+	.weak	test
+main:
+	b	test
diff --git a/gas/testsuite/gas/arc/relax-b.d b/gas/testsuite/gas/arc/relax-b.d
new file mode 100644
index 0000000..fd8dc47
--- /dev/null
+++ b/gas/testsuite/gas/arc/relax-b.d
@@ -0,0 +1,19 @@
+#as: -mcpu=archs -mrelax
+#objdump: -dr
+
+.*: +file format .*arc.*
+
+
+Disassembly of section .text:
+
+00000000 <foo-0x4>:
+   0:	78e0                	nop_s
+   2:	78e0                	nop_s
+
+00000004 <foo>:
+   4:	2000 0000           	add	r0,r0,r0
+
+00000008 <bar>:
+   8:	ffff                	bl_s	4 <foo>
+   a:	2100 0041           	add	r1,r1,r1
+   e:	f1fc                	b_s	4 <foo>
diff --git a/gas/testsuite/gas/arc/relax-b.s b/gas/testsuite/gas/arc/relax-b.s
new file mode 100644
index 0000000..3698b14
--- /dev/null
+++ b/gas/testsuite/gas/arc/relax-b.s
@@ -0,0 +1,11 @@
+	.text
+	nop_s
+	.align 4
+foo:
+	add	r0,r0,r0
+
+	.align 4
+bar:
+	bl	@foo
+	add	r1,r1,r1
+	b	@foo
diff --git a/include/opcode/arc.h b/include/opcode/arc.h
index a69a561..6f5bc98 100644
--- a/include/opcode/arc.h
+++ b/include/opcode/arc.h
@@ -24,8 +24,13 @@
 #ifndef OPCODE_ARC_H
 #define OPCODE_ARC_H
 
+#ifndef MAX_INSN_ARGS
 #define MAX_INSN_ARGS	     6
+#endif
+
+#ifndef MAX_INSN_FLGS
 #define MAX_INSN_FLGS	     3
+#endif
 
 /* Instruction Class.  */
 typedef enum
@@ -410,4 +415,7 @@ struct arc_aux_reg
 extern const struct arc_aux_reg arc_aux_regs[];
 extern const unsigned arc_num_aux_regs;
 
+extern const struct arc_opcode arc_relax_opcodes[];
+extern const unsigned arc_num_relax_opcodes;
+
 #endif /* OPCODE_ARC_H */
diff --git a/opcodes/arc-opc.c b/opcodes/arc-opc.c
index 2d6e887..9c6a86d 100644
--- a/opcodes/arc-opc.c
+++ b/opcodes/arc-opc.c
@@ -1359,3 +1359,129 @@ const struct arc_aux_reg arc_aux_regs[] =
 };
 
 const unsigned arc_num_aux_regs = ARRAY_SIZE (arc_aux_regs);
+
+/* NOTE: The order of this array MUST be consistent with 'enum
+   arc_rlx_types' located in tc-arc.h!  */
+const struct arc_opcode arc_relax_opcodes[] =
+  {
+    { NULL, 0x0, 0x0, 0x0, ARITH, NONE, { UNUSED }, { 0 } },
+
+    /* bl_s s13 11111sssssssssss.  */
+    { "bl_s", 0x0000F800, 0x0000F800, ARC_OPCODE_ARC600 | ARC_OPCODE_ARC700
+      | ARC_OPCODE_ARCv2EM | ARC_OPCODE_ARCv2HS, BRANCH, NONE,
+      { SIMM13_A32_5_S }, { 0 }},
+
+    /* bl<.d> s25 00001sssssssss10SSSSSSSSSSNRtttt.  */
+    { "bl", 0x08020000, 0xF8030000, ARC_OPCODE_ARC600 | ARC_OPCODE_ARC700
+      | ARC_OPCODE_ARCv2EM | ARC_OPCODE_ARCv2HS, BRANCH, NONE,
+      { SIMM25_A32_5 }, { C_D }},
+
+    /* b_s s10 1111000sssssssss.  */
+    { "b_s", 0x0000F000, 0x0000FE00, ARC_OPCODE_ARC600 | ARC_OPCODE_ARC700
+      | ARC_OPCODE_ARCv2EM | ARC_OPCODE_ARCv2HS, BRANCH, NONE,
+      { SIMM10_A16_7_S }, { 0 }},
+
+    /* b<.d> s25 00000ssssssssss1SSSSSSSSSSNRtttt.  */
+    { "b", 0x00010000, 0xF8010000, ARC_OPCODE_ARC600 | ARC_OPCODE_ARC700
+      | ARC_OPCODE_ARCv2EM | ARC_OPCODE_ARCv2HS, BRANCH, NONE,
+      { SIMM25_A16_5 }, { C_D }},
+
+    /* add_s c,b,u3 01101bbbccc00uuu.  Wants UIMM3_13_S_PCREL.  */
+    { "add_s", 0x00006800, 0x0000F818, ARC_OPCODE_ARC600 | ARC_OPCODE_ARC700
+      | ARC_OPCODE_ARCv2EM | ARC_OPCODE_ARCv2HS, ARITH, NONE,
+      { RC_S, RB_S, UIMM3_13_S }, { 0 }},
+
+    /* add<.f> a,b,u6 00100bbb01000000FBBBuuuuuuAAAAAA.  Wants
+       UIMM6_20_PCREL.  */
+    { "add", 0x20400000, 0xF8FF0000, ARC_OPCODE_ARC600 | ARC_OPCODE_ARC700
+      | ARC_OPCODE_ARCv2EM | ARC_OPCODE_ARCv2HS, ARITH, NONE,
+      { RA, RB, UIMM6_20 }, { C_F }},
+
+    /* add<.f> a,b,limm 00100bbb00000000FBBB111110AAAAAA.  */
+    { "add", 0x20000F80, 0xF8FF0FC0, ARC_OPCODE_ARC600 | ARC_OPCODE_ARC700
+      | ARC_OPCODE_ARCv2EM | ARC_OPCODE_ARCv2HS, ARITH, NONE,
+      { RA, RB, LIMM }, { C_F }},
+
+    /* ld_s c,b,u7 10000bbbcccuuuuu.  Wants UIMM7_A32_11_S_PCREL.  */
+    { "ld_s", 0x00008000, 0x0000F800, ARC_OPCODE_ARC600 | ARC_OPCODE_ARC700
+      | ARC_OPCODE_ARCv2EM | ARC_OPCODE_ARCv2HS, MEMORY, NONE,
+      { RC_S, BRAKET, RB_S, UIMM7_A32_11_S, BRAKETdup }, { 0 }},
+
+    /* ld<.di><.aa><.x><zz> a,b,s9
+       00010bbbssssssssSBBBDaaZZXAAAAAA. Wants SIMM9_8_PCREL.  */
+    { "ld", 0x10000000, 0xF8000000, ARC_OPCODE_ARC600 | ARC_OPCODE_ARC700
+      | ARC_OPCODE_ARCv2EM | ARC_OPCODE_ARCv2HS, MEMORY, NONE,
+      { RA, BRAKET, RB, SIMM9_8, BRAKETdup },
+      { C_ZZ23, C_DI20, C_AA21, C_X25 }},
+
+    /* ld<.di><.aa><.x><zz> a,b,limm 00100bbbaa110ZZXDBBB111110AAAAAA.  */
+    { "ld", 0x20300F80, 0xF8380FC0, ARC_OPCODE_ARC600 | ARC_OPCODE_ARC700
+      | ARC_OPCODE_ARCv2EM | ARC_OPCODE_ARCv2HS, MEMORY, NONE,
+      { RA, BRAKET, RB, LIMM, BRAKETdup },
+      { C_ZZ13, C_DI16, C_AA8, C_X15 }},
+
+    /* mov_s b,u8 11011bbbuuuuuuuu.  Wants UIMM8_8_S_PCREL.  */
+    { "mov_s", 0x0000D800, 0x0000F800, ARC_OPCODE_ARC600 | ARC_OPCODE_ARC700
+      | ARC_OPCODE_ARCv2EM | ARC_OPCODE_ARCv2HS, MEMORY, NONE,
+      { RB_S, UIMM8_8_S }, { 0 }},
+
+    /* mov<.f> b,s12 00100bbb10001010FBBBssssssSSSSSS. Wants
+       SIMM12_20_PCREL.  */
+    { "mov", 0x208A0000, 0xF8FF0000, ARC_OPCODE_ARC600 | ARC_OPCODE_ARC700
+      | ARC_OPCODE_ARCv2EM | ARC_OPCODE_ARCv2HS, MEMORY, NONE,
+      { RB, SIMM12_20 }, { C_F }},
+
+    /* mov<.f> b,limm 00100bbb00001010FBBB111110RRRRRR.  */
+    { "mov", 0x200A0F80, 0xF8FF0FC0, ARC_OPCODE_ARC600 | ARC_OPCODE_ARC700
+      | ARC_OPCODE_ARCv2EM | ARC_OPCODE_ARCv2HS, MEMORY, NONE,
+      { RB, LIMM }, { C_F }},
+
+    /* sub_s c,b,u3 01101bbbccc01uuu.  UIMM3_13_S_PCREL. */
+    { "sub_s", 0x00006808, 0x0000F818, ARC_OPCODE_ARC600 | ARC_OPCODE_ARC700
+      | ARC_OPCODE_ARCv2EM | ARC_OPCODE_ARCv2HS, ARITH, NONE,
+      { RC_S, RB_S, UIMM3_13_S }, { 0 }},
+
+    /* sub<.f> a,b,u6 00100bbb01000010FBBBuuuuuuAAAAAA.
+       UIMM6_20_PCREL.  */
+    { "sub", 0x20420000, 0xF8FF0000, ARC_OPCODE_ARC600 | ARC_OPCODE_ARC700
+      | ARC_OPCODE_ARCv2EM | ARC_OPCODE_ARCv2HS, ARITH, NONE,
+      { RA, RB, UIMM6_20 }, { C_F }},
+
+    /* sub<.f> a,b,limm 00100bbb00000010FBBB111110AAAAAA.  */
+    { "sub", 0x20020F80, 0xF8FF0FC0, ARC_OPCODE_ARC600 | ARC_OPCODE_ARC700
+      | ARC_OPCODE_ARCv2EM | ARC_OPCODE_ARCv2HS, ARITH, NONE,
+      { RA, RB, LIMM }, { C_F }},
+
+    /* mpy<.f> a,b,u6 00100bbb01011010FBBBuuuuuuAAAAAA.
+       UIMM6_20_PCREL.  */
+    { "mpy", 0x205A0000, 0xF8FF0000, ARC_OPCODE_ARC700 | ARC_OPCODE_ARCv2EM
+      | ARC_OPCODE_ARCv2HS, ARITH, MPY6E, { RA, RB, UIMM6_20 }, { C_F }},
+
+    /* mpy<.f> a,b,limm 00100bbb00011010FBBB111110AAAAAA.  */
+    { "mpy", 0x201A0F80, 0xF8FF0FC0, ARC_OPCODE_ARC700 | ARC_OPCODE_ARCv2EM
+      | ARC_OPCODE_ARCv2HS, ARITH, MPY6E, { RA, RB, LIMM }, { C_F }},
+
+    /* mov<.f><.cc> b,u6 00100bbb11001010FBBBuuuuuu1QQQQQ.
+       UIMM6_20_PCREL.  */
+    { "mov", 0x20CA0020, 0xF8FF0020, ARC_OPCODE_ARC600 | ARC_OPCODE_ARC700
+      | ARC_OPCODE_ARCv2EM | ARC_OPCODE_ARCv2HS, MEMORY, NONE,
+      { RB, UIMM6_20 }, { C_F, C_CC }},
+
+    /* mov<.f><.cc> b,limm 00100bbb11001010FBBB1111100QQQQQ.  */
+    { "mov", 0x20CA0F80, 0xF8FF0FE0, ARC_OPCODE_ARC600 | ARC_OPCODE_ARC700
+      | ARC_OPCODE_ARCv2EM | ARC_OPCODE_ARCv2HS, MEMORY, NONE,
+      { RB, LIMM }, { C_F, C_CC }},
+
+    /* add<.f><.cc> b,b,u6 00100bbb11000000FBBBuuuuuu1QQQQQ.
+       UIMM6_20_PCREL.  */
+    { "add", 0x20C00020, 0xF8FF0020, ARC_OPCODE_ARC600 | ARC_OPCODE_ARC700
+      | ARC_OPCODE_ARCv2EM | ARC_OPCODE_ARCv2HS, ARITH, NONE,
+      { RB, RBdup, UIMM6_20 }, { C_F, C_CC }},
+
+    /* add<.f><.cc> b,b,limm 00100bbb11000000FBBB1111100QQQQQ.  */
+    { "add", 0x20C00F80, 0xF8FF0FE0, ARC_OPCODE_ARC600 | ARC_OPCODE_ARC700
+      | ARC_OPCODE_ARCv2EM | ARC_OPCODE_ARCv2HS, ARITH, NONE,
+      { RB, RBdup, LIMM }, { C_F, C_CC }}
+  };
+
+const unsigned arc_num_relax_opcodes = ARRAY_SIZE (arc_relax_opcodes);
-- 
1.9.1


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