More signed overflow fixes
[deliverable/binutils-gdb.git] / opcodes / arc-ext.c
index 52f455639e0a787557676f89a8c86bf96d18736a..bc676687914ab2f4833167458e67aa57d44114c5 100644 (file)
@@ -1,5 +1,5 @@
 /* ARC target-dependent stuff.  Extension structure access functions
-   Copyright (C) 1995-2016 Free Software Foundation, Inc.
+   Copyright (C) 1995-2019 Free Software Foundation, Inc.
 
    This file is part of libopcodes.
 
@@ -27,7 +27,6 @@
 #include "elf/arc.h"
 #include "libiberty.h"
 
-
 /* This module provides support for extensions to the ARC processor
    architecture.  */
 
 
 /* These types define the information stored in the table.  */
 
-struct ExtInstruction
-{
-  char                  major;
-  char                  minor;
-  char                  flags;
-  char*                         name;
-  struct ExtInstruction* next;
-};
-
 struct ExtAuxRegister
 {
-  long                  address;
-  char*                         name;
-  struct ExtAuxRegister* next;
+  unsigned               address;
+  char *                 name;
+  struct ExtAuxRegister * next;
 };
 
 struct ExtCoreRegister
 {
   short                    number;
   enum ExtReadWrite rw;
-  char*                    name;
+  char *           name;
 };
 
 struct arcExtMap
@@ -80,7 +70,7 @@ struct arcExtMap
   struct ExtAuxRegister* auxRegisters;
   struct ExtInstruction* instructions[INST_HASH_SIZE];
   struct ExtCoreRegister coreRegisters[NUM_EXT_CORE];
-  char*                         condCodes[NUM_EXT_COND];
+  char *                condCodes[NUM_EXT_COND];
 };
 
 
@@ -141,6 +131,9 @@ create_map (unsigned char *block,
            insn->minor = minor;
            insn->flags = p[4];
            insn->next  = *bucket;
+           insn->suffix = 0;
+           insn->syntax = 0;
+           insn->modsyn = 0;
            *bucket = insn;
            break;
          }
@@ -177,6 +170,7 @@ create_map (unsigned char *block,
            arc_extension_map.
              coreRegisters[number - FIRST_EXTENSION_CORE_REGISTER].name
              = xstrdup (name);
+           break;
          }
 
        case EXT_COND_CODE:
@@ -197,8 +191,8 @@ create_map (unsigned char *block,
            char *aux_name = xstrdup ((char *) (p + 6));
 
            newAuxRegister->name = aux_name;
-           newAuxRegister->address = (p[2] << 24) | (p[3] << 16)
-             | (p[4] << 8) | p[5];
+           newAuxRegister->address = (((unsigned) p[2] << 24) | (p[3] << 16)
+                                      | (p[4] << 8) | p[5]);
            newAuxRegister->next = arc_extension_map.auxRegisters;
            arc_extension_map.auxRegisters = newAuxRegister;
            break;
@@ -285,10 +279,8 @@ ExtReadWrite_image (enum ExtReadWrite val)
 
 /* Get the name of an extension instruction.  */
 
-const char *
-arcExtMap_instName (int opcode,
-                   int insn,
-                   int *flags)
+const extInstruction_t *
+arcExtMap_insn (int opcode, unsigned long long insn)
 {
   /* Here the following tasks need to be done.  First of all, the
      opcode stored in the Extension Map is the real opcode.  However,
@@ -306,7 +298,7 @@ arcExtMap_instName (int opcode,
      then un-mangle using iiiiiI else iiiiii.  */
 
   unsigned char minor;
-  struct ExtInstruction *temp;
+  extInstruction_t *temp;
 
   /* 16-bit instructions.  */
   if (0x08 <= opcode && opcode <= 0x0b)
@@ -367,8 +359,7 @@ arcExtMap_instName (int opcode,
     {
       if ((temp->major == opcode) && (temp->minor == minor))
        {
-         *flags = temp->flags;
-         return temp->name;
+         return temp;
        }
       temp = temp->next;
     }
@@ -382,7 +373,7 @@ const char *
 arcExtMap_coreRegName (int regnum)
 {
   if (regnum < FIRST_EXTENSION_CORE_REGISTER
-      || regnum > LAST_EXTENSION_CONDITION_CODE)
+      || regnum > LAST_EXTENSION_CORE_REGISTER)
     return NULL;
   return arc_extension_map.
     coreRegisters[regnum - FIRST_EXTENSION_CORE_REGISTER].name;
@@ -394,7 +385,7 @@ enum ExtReadWrite
 arcExtMap_coreReadWrite (int regnum)
 {
   if (regnum < FIRST_EXTENSION_CORE_REGISTER
-      || regnum > LAST_EXTENSION_CONDITION_CODE)
+      || regnum > LAST_EXTENSION_CORE_REGISTER)
     return REG_INVALID;
   return arc_extension_map.
     coreRegisters[regnum - FIRST_EXTENSION_CORE_REGISTER].rw;
@@ -415,7 +406,7 @@ arcExtMap_condCodeName (int code)
 /* Get the name of an extension auxiliary register.  */
 
 const char *
-arcExtMap_auxRegName (long address)
+arcExtMap_auxRegName (unsigned address)
 {
   /* Walk the list of auxiliary register names and find the name.  */
   struct ExtAuxRegister *r;
@@ -447,7 +438,7 @@ build_ARC_extmap (bfd *text_bfd)
          sizeof (".gnu.linkonce.arcextmap.") - 1)
        || !strcmp (sect->name,".arcextmap"))
       {
-       bfd_size_type  count  = bfd_get_section_size (sect);
+       bfd_size_type  count  = bfd_section_size (sect);
        unsigned char* buffer = xmalloc (count);
 
        if (buffer)
@@ -459,6 +450,8 @@ build_ARC_extmap (bfd *text_bfd)
       }
 }
 
+/* Debug function used to dump the ARC information fount in arcextmap
+   sections.  */
 
 void
 dump_ARC_extmap (void)
@@ -470,7 +463,7 @@ dump_ARC_extmap (void)
 
     while (r)
     {
-       printf ("AUX : %s %ld\n", r->name, r->address);
+       printf ("AUX : %s %u\n", r->name, r->address);
        r = r->next;
     }
 
@@ -480,8 +473,32 @@ dump_ARC_extmap (void)
 
        for (insn = arc_extension_map.instructions[i];
             insn != NULL; insn = insn->next)
-           printf ("INST: %d %d %x %s\n", insn->major, insn->minor,
-                   insn->flags, insn->name);
+         {
+           printf ("INST: 0x%02x 0x%02x ", insn->major, insn->minor);
+           switch (insn->flags & ARC_SYNTAX_MASK)
+             {
+             case ARC_SYNTAX_2OP:
+               printf ("SYNTAX_2OP");
+               break;
+             case ARC_SYNTAX_3OP:
+               printf ("SYNTAX_3OP");
+               break;
+             case ARC_SYNTAX_1OP:
+               printf ("SYNTAX_1OP");
+               break;
+             case ARC_SYNTAX_NOP:
+               printf ("SYNTAX_NOP");
+               break;
+             default:
+               printf ("SYNTAX_UNK");
+               break;
+             }
+
+           if (insn->flags & 0x10)
+             printf ("|MODIFIER");
+
+           printf (" %s\n", insn->name);
+         }
     }
 
     for (i = 0; i < NUM_EXT_CORE; i++)
@@ -489,11 +506,311 @@ dump_ARC_extmap (void)
        struct ExtCoreRegister reg = arc_extension_map.coreRegisters[i];
 
        if (reg.name)
-           printf ("CORE: %s %d %s\n", reg.name, reg.number,
-                   ExtReadWrite_image (reg.rw));
+         printf ("CORE: 0x%04x %s %s\n", reg.number,
+                 ExtReadWrite_image (reg.rw),
+                 reg.name);
     }
 
     for (i = 0; i < NUM_EXT_COND; i++)
        if (arc_extension_map.condCodes[i])
            printf ("COND: %s\n", arc_extension_map.condCodes[i]);
 }
+
+/* For a given extension instruction generate the equivalent arc
+   opcode structure.  */
+
+struct arc_opcode *
+arcExtMap_genOpcode (const extInstruction_t *einsn,
+                    unsigned arc_target,
+                    const char **errmsg)
+{
+  struct arc_opcode *q, *arc_ext_opcodes = NULL;
+  const unsigned char *lflags_f;
+  const unsigned char *lflags_ccf;
+  int count;
+
+  /* Check for the class to see how many instructions we generate.  */
+  switch (einsn->flags & ARC_SYNTAX_MASK)
+    {
+    case ARC_SYNTAX_3OP:
+      count = (einsn->modsyn & ARC_OP1_MUST_BE_IMM) ? 10 : 20;
+      break;
+    case ARC_SYNTAX_2OP:
+      count = (einsn->flags & 0x10) ? 7 : 6;
+      break;
+    case ARC_SYNTAX_1OP:
+      count = 3;
+      break;
+    case ARC_SYNTAX_NOP:
+      count = 1;
+      break;
+    default:
+      count = 0;
+      break;
+    }
+
+  /* Allocate memory.  */
+  arc_ext_opcodes = (struct arc_opcode *)
+    xmalloc ((count + 1) * sizeof (*arc_ext_opcodes));
+
+  if (arc_ext_opcodes == NULL)
+    {
+      *errmsg = "Virtual memory exhausted";
+      return NULL;
+    }
+
+  /* Generate the patterns.  */
+  q = arc_ext_opcodes;
+
+  if (einsn->suffix)
+    {
+      lflags_f   = flags_none;
+      lflags_ccf = flags_none;
+    }
+  else
+    {
+      lflags_f   = flags_f;
+      lflags_ccf = flags_ccf;
+    }
+
+  if (einsn->suffix & ARC_SUFFIX_COND)
+    lflags_ccf = flags_cc;
+  if (einsn->suffix & ARC_SUFFIX_FLAG)
+    {
+      lflags_f   = flags_f;
+      lflags_ccf = flags_f;
+    }
+  if (einsn->suffix & (ARC_SUFFIX_FLAG | ARC_SUFFIX_COND))
+    lflags_ccf = flags_ccf;
+
+  if (einsn->flags & ARC_SYNTAX_2OP
+      && !(einsn->flags & 0x10))
+    {
+      /* Regular 2OP instruction.  */
+      if (einsn->suffix & ARC_SUFFIX_COND)
+       *errmsg = "Suffix SUFFIX_COND ignored";
+
+      INSERT_XOP (q, einsn->name,
+                 INSN2OP_BC (einsn->major, einsn->minor), MINSN2OP_BC,
+                 arc_target, arg_32bit_rbrc, lflags_f);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN2OP_0C (einsn->major, einsn->minor), MINSN2OP_0C,
+                 arc_target, arg_32bit_zarc, lflags_f);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN2OP_BU (einsn->major, einsn->minor), MINSN2OP_BU,
+                 arc_target, arg_32bit_rbu6, lflags_f);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN2OP_0U (einsn->major, einsn->minor), MINSN2OP_0U,
+                 arc_target, arg_32bit_zau6, lflags_f);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN2OP_BL (einsn->major, einsn->minor), MINSN2OP_BL,
+                 arc_target, arg_32bit_rblimm, lflags_f);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN2OP_0L (einsn->major, einsn->minor), MINSN2OP_0L,
+                 arc_target, arg_32bit_zalimm, lflags_f);
+    }
+  else if (einsn->flags & (0x10 | ARC_SYNTAX_2OP))
+    {
+      /* This is actually a 3OP pattern.  The first operand is
+        immplied and is set to zero.  */
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_0BC (einsn->major, einsn->minor),  MINSN3OP_0BC,
+                 arc_target, arg_32bit_rbrc, lflags_f);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_0BU (einsn->major, einsn->minor),  MINSN3OP_0BU,
+                 arc_target, arg_32bit_rbu6, lflags_f);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_0BL (einsn->major, einsn->minor),  MINSN3OP_0BL,
+                 arc_target, arg_32bit_rblimm, lflags_f);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_C0LC (einsn->major, einsn->minor), MINSN3OP_C0LC,
+                 arc_target, arg_32bit_limmrc, lflags_ccf);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_C0LU (einsn->major, einsn->minor), MINSN3OP_C0LU,
+                 arc_target, arg_32bit_limmu6, lflags_ccf);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_0LS (einsn->major, einsn->minor),  MINSN3OP_0LS,
+                 arc_target, arg_32bit_limms12, lflags_f);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_C0LL (einsn->major, einsn->minor), MINSN3OP_C0LL,
+                 arc_target, arg_32bit_limmlimm, lflags_ccf);
+    }
+  else if (einsn->flags & ARC_SYNTAX_3OP
+          && !(einsn->modsyn & ARC_OP1_MUST_BE_IMM))
+    {
+      /* Regular 3OP instruction.  */
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_ABC (einsn->major, einsn->minor),  MINSN3OP_ABC,
+                 arc_target, arg_32bit_rarbrc, lflags_f);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_0BC (einsn->major, einsn->minor),  MINSN3OP_0BC,
+                 arc_target, arg_32bit_zarbrc, lflags_f);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_CBBC (einsn->major, einsn->minor), MINSN3OP_CBBC,
+                 arc_target, arg_32bit_rbrbrc, lflags_ccf);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_ABU (einsn->major, einsn->minor),  MINSN3OP_ABU,
+                 arc_target, arg_32bit_rarbu6, lflags_f);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_0BU (einsn->major, einsn->minor),  MINSN3OP_0BU,
+                 arc_target, arg_32bit_zarbu6, lflags_f);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_CBBU (einsn->major, einsn->minor), MINSN3OP_CBBU,
+                 arc_target, arg_32bit_rbrbu6, lflags_ccf);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_BBS (einsn->major, einsn->minor),  MINSN3OP_BBS,
+                 arc_target, arg_32bit_rbrbs12, lflags_f);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_ALC (einsn->major, einsn->minor),  MINSN3OP_ALC,
+                 arc_target, arg_32bit_ralimmrc, lflags_f);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_ABL (einsn->major, einsn->minor),  MINSN3OP_ABL,
+                 arc_target, arg_32bit_rarblimm, lflags_f);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_0LC (einsn->major, einsn->minor),  MINSN3OP_0LC,
+                 arc_target, arg_32bit_zalimmrc, lflags_f);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_0BL (einsn->major, einsn->minor),  MINSN3OP_0BL,
+                 arc_target, arg_32bit_zarblimm, lflags_f);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_C0LC (einsn->major, einsn->minor), MINSN3OP_C0LC,
+                 arc_target, arg_32bit_zalimmrc, lflags_ccf);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_CBBL (einsn->major, einsn->minor), MINSN3OP_CBBL,
+                 arc_target, arg_32bit_rbrblimm, lflags_ccf);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_ALU (einsn->major, einsn->minor),  MINSN3OP_ALU,
+                 arc_target, arg_32bit_ralimmu6, lflags_f);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_0LU (einsn->major, einsn->minor),  MINSN3OP_0LU,
+                 arc_target, arg_32bit_zalimmu6, lflags_f);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_C0LU (einsn->major, einsn->minor), MINSN3OP_C0LU,
+                 arc_target, arg_32bit_zalimmu6, lflags_ccf);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_0LS (einsn->major, einsn->minor),  MINSN3OP_0LS,
+                 arc_target, arg_32bit_zalimms12, lflags_f);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_ALL (einsn->major, einsn->minor),  MINSN3OP_ALL,
+                 arc_target, arg_32bit_ralimmlimm, lflags_f);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_0LL (einsn->major, einsn->minor),  MINSN3OP_0LL,
+                 arc_target, arg_32bit_zalimmlimm, lflags_f);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_C0LL (einsn->major, einsn->minor), MINSN3OP_C0LL,
+                 arc_target, arg_32bit_zalimmlimm, lflags_ccf);
+    }
+  else if (einsn->flags & ARC_SYNTAX_3OP)
+    {
+      /* 3OP instruction which accepts only zero as first
+        argument.  */
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_0BC (einsn->major, einsn->minor),  MINSN3OP_0BC,
+                 arc_target, arg_32bit_zarbrc, lflags_f);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_0BU (einsn->major, einsn->minor),  MINSN3OP_0BU,
+                 arc_target, arg_32bit_zarbu6, lflags_f);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_0LC (einsn->major, einsn->minor),  MINSN3OP_0LC,
+                 arc_target, arg_32bit_zalimmrc, lflags_f);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_0BL (einsn->major, einsn->minor),  MINSN3OP_0BL,
+                 arc_target, arg_32bit_zarblimm, lflags_f);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_C0LC (einsn->major, einsn->minor), MINSN3OP_C0LC,
+                 arc_target, arg_32bit_zalimmrc, lflags_ccf);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_0LU (einsn->major, einsn->minor),  MINSN3OP_0LU,
+                 arc_target, arg_32bit_zalimmu6, lflags_f);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_C0LU (einsn->major, einsn->minor), MINSN3OP_C0LU,
+                 arc_target, arg_32bit_zalimmu6, lflags_ccf);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_0LS (einsn->major, einsn->minor),  MINSN3OP_0LS,
+                 arc_target, arg_32bit_zalimms12, lflags_f);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_0LL (einsn->major, einsn->minor),  MINSN3OP_0LL,
+                 arc_target, arg_32bit_zalimmlimm, lflags_f);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN3OP_C0LL (einsn->major, einsn->minor), MINSN3OP_C0LL,
+                 arc_target, arg_32bit_zalimmlimm, lflags_ccf);
+    }
+  else if (einsn->flags & ARC_SYNTAX_1OP)
+    {
+      if (einsn->suffix & ARC_SUFFIX_COND)
+       *errmsg = "Suffix SUFFIX_COND ignored";
+
+      INSERT_XOP (q, einsn->name,
+                 INSN2OP (einsn->major, 0x3F) | FIELDB (einsn->minor),
+                 MINSN2OP_0C, arc_target, arg_32bit_rc, lflags_f);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN2OP (einsn->major, 0x3F) | FIELDB (einsn->minor)
+                 | (0x01 << 22), MINSN2OP_0U, arc_target, arg_32bit_u6,
+                 lflags_f);
+
+      INSERT_XOP (q, einsn->name,
+                 INSN2OP (einsn->major, 0x3F) | FIELDB (einsn->minor)
+                 | FIELDC (62), MINSN2OP_0L, arc_target, arg_32bit_limm,
+                 lflags_f);
+
+    }
+  else if (einsn->flags & ARC_SYNTAX_NOP)
+    {
+      if (einsn->suffix & ARC_SUFFIX_COND)
+       *errmsg = "Suffix SUFFIX_COND ignored";
+
+      INSERT_XOP (q, einsn->name,
+                 INSN2OP (einsn->major, 0x3F) | FIELDB (einsn->minor)
+                 | (0x01 << 22), MINSN2OP_0L, arc_target, arg_none, lflags_f);
+    }
+  else
+    {
+      *errmsg = "Unknown syntax";
+      return NULL;
+    }
+
+  /* End marker.  */
+  memset (q, 0, sizeof (*arc_ext_opcodes));
+
+  return arc_ext_opcodes;
+}
This page took 0.030658 seconds and 4 git commands to generate.