[4/5] arc: Add disassembler helper

Message ID 20170214100130.29194-4-Anton.Kolesov@synopsys.com
State New, archived
Headers

Commit Message

Anton Kolesov Feb. 14, 2017, 10:01 a.m. UTC
  Add disassembler helper for GDB, that uses opcodes structure arc_instruction
and adds convenience functions to handle instruction operands.  This interface
solves at least those problems with arc_instruction:

  * Some instructions, like "push_s", have implicit operands which are not
    directly present in arc_instruction.
  * Operands of particular meaning, like branch/jump targets, have various
    locations and meaning depending on type of branch/target.
  * Access to operand value is abstracted into a separate function, so callee
    code shouldn't bother if operand value is an immediate value or in a
    register.

Testcases included in this commit are fairly limited - they test exclusively
branch instructions, something that will be used in software single stepping.
Most of the other parts of this disassembler helper are tested during prologue
analysis testing.

gdb/ChangeLog:

yyyy-mm-dd  Anton Kolesov  <anton.kolesov@synopsys.com>

	* configure.tgt: Add arc-insn.o.
	* arc-tdep.c (arc_delayed_print_insn): Make non-static.
	  (dump_arc_instruction_command): New function.
	* arc-tdep.h (arc_delayed_print_insn): Add function declaration.
	* arch/arc-insn.c: New file.
	* arch/arc-insn.h: Likewise.

gdb/doc/ChangeLog:

yyyy-mm-dd  Anton Kolesov  <anton.kolesov@synopsys.com>

	* gdb.texinfo (Synopsys ARC): Add "maint print arc arc-instruction".

gdb/testsuite/ChangeLog:

yyyy-mm-dd  Anton Kolesov  <anton.kolesov@synopsys.com>

      * gdb.arch/arc-decode-insn.S: New file.
      * gdb.arch/arc-decode-insn.exp: Likewise.
---
 gdb/arc-tdep.c                             |   28 +-
 gdb/arc-tdep.h                             |    6 +
 gdb/arch/arc-insn.c                        |  275 ++++++++
 gdb/arch/arc-insn.h                        |   64 ++
 gdb/configure.tgt                          |    4 +-
 gdb/doc/gdb.texinfo                        |    4 +
 gdb/testsuite/gdb.arch/arc-decode-insn.S   | 1002 ++++++++++++++++++++++++++++
 gdb/testsuite/gdb.arch/arc-decode-insn.exp |  136 ++++
 8 files changed, 1516 insertions(+), 3 deletions(-)
 create mode 100644 gdb/arch/arc-insn.c
 create mode 100644 gdb/arch/arc-insn.h
 create mode 100644 gdb/testsuite/gdb.arch/arc-decode-insn.S
 create mode 100644 gdb/testsuite/gdb.arch/arc-decode-insn.exp
  

Comments

Eli Zaretskii Feb. 14, 2017, 3:50 p.m. UTC | #1
> From: Anton Kolesov <Anton.Kolesov@synopsys.com>
> Cc: Anton Kolesov <Anton.Kolesov@synopsys.com>,	Francois Bedard <Francois.Bedard@synopsys.com>
> Date: Tue, 14 Feb 2017 13:01:29 +0300
> 
> Add disassembler helper for GDB, that uses opcodes structure arc_instruction
> and adds convenience functions to handle instruction operands.  This interface
> solves at least those problems with arc_instruction:
> 
>   * Some instructions, like "push_s", have implicit operands which are not
>     directly present in arc_instruction.
>   * Operands of particular meaning, like branch/jump targets, have various
>     locations and meaning depending on type of branch/target.
>   * Access to operand value is abstracted into a separate function, so callee
>     code shouldn't bother if operand value is an immediate value or in a
>     register.
> 
> Testcases included in this commit are fairly limited - they test exclusively
> branch instructions, something that will be used in software single stepping.
> Most of the other parts of this disassembler helper are tested during prologue
> analysis testing.
> 
> gdb/ChangeLog:
> 
> yyyy-mm-dd  Anton Kolesov  <anton.kolesov@synopsys.com>
> 
> 	* configure.tgt: Add arc-insn.o.
> 	* arc-tdep.c (arc_delayed_print_insn): Make non-static.
> 	  (dump_arc_instruction_command): New function.
> 	* arc-tdep.h (arc_delayed_print_insn): Add function declaration.
> 	* arch/arc-insn.c: New file.
> 	* arch/arc-insn.h: Likewise.
> 
> gdb/doc/ChangeLog:
> 
> yyyy-mm-dd  Anton Kolesov  <anton.kolesov@synopsys.com>
> 
> 	* gdb.texinfo (Synopsys ARC): Add "maint print arc arc-instruction".
> 
> gdb/testsuite/ChangeLog:
> 
> yyyy-mm-dd  Anton Kolesov  <anton.kolesov@synopsys.com>
> 
>       * gdb.arch/arc-decode-insn.S: New file.
>       * gdb.arch/arc-decode-insn.exp: Likewise.

OK for the documentation part.

Thanks.
  
Pedro Alves Feb. 17, 2017, 1 p.m. UTC | #2
On 02/14/2017 10:01 AM, Anton Kolesov wrote:

> diff --git a/gdb/arch/arc-insn.c b/gdb/arch/arc-insn.c
> new file mode 100644
> index 0000000..2dc99a7
> --- /dev/null
> +++ b/gdb/arch/arc-insn.c
> @@ -0,0 +1,275 @@
> +/* ARC disassembler helper.
> +
> +   Copyright 2017 Free Software Foundation, Inc.
> +   Contributed by Synopsys Inc.

Please see:
 https://sourceware.org/gdb/wiki/ContributionChecklist#Attribution

(multiple instances)

> +
> +/* GDB header files.  */
> +#include "defs.h"

Hmm, the original idea of the gdb/arch/ dir was to hold files that could be
used by gdbserver too.  Note how the current files all include common-defs.h 
instead of defs.h.

This file seems to depend on gdb and opcodes, so ... not sure what to
suggest here.  Do you see using this code or parts of it in
gdbserver too in the future?

> +# This tests provides certain degree of testing for arch/arc-insn.c functions,

"These tests"

> +# however it is not a comprehensive testsuite that would go through all
> +# possible ARC instructions - instead this particular test is focused on branch
> +# instructions and whether branch targets are evaluated properly.  Most of the
> +# non-branch aspects of instruction decoder are used during prologue analysis,
> +# so are indirictly tested there.
> +
> +# To maintain separation of test data and test logic, all of the information
> +# about instructions, like if it has delay slot, condition code, branch target
> +# address, is all specified in the test assembly file as a symbols, while this
> +# test case reads those symbols to learn which values are right, then compares
> +# values coming from arc-insn.c with those found in symbols.  More information
> +# about requirements to actual test cases can be found in corresponding
> +# assembly file of this test case (arc-decode-insn.S).
> +
> +if {![istarget "arc*-*-*"]} then {
> +    verbose "Skipping ARC decoder test."
> +    return
> +}
> +
> +standard_testfile .S
> +
> +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable "" ] != "" } {
> +    untested arc-decode-insn.exp
> +    return -1
> +}
> +
> +gdb_exit
> +gdb_start
> +gdb_reinitialize_dir $srcdir/$subdir
> +gdb_load ${binfile}

Use prepare_for_testing instead of all the above.

> +
> +if ![runto_main] {
> +    fail "Can't run to main"
> +    return 0
> +}
> +
> +# Helper function that reads properties of instruction from the ELF file via
> +# its symbols and then confirms that decoder output aligns to the expected
> +# values.
> +proc test_branch_insn { test_name } {
> +
> +    # Make messages for failed cases more clear, by using hex in them.
> +    set pc [get_hexadecimal_valueof &${test_name}_start -1]
> +
> +    # Calculate instruction length, based on ${test_name}_end symbol.
> +    set end_pc [get_hexadecimal_valueof &${test_name}_end -1]
> +    set length [expr $end_pc - $pc]
> +
> +    set target_address [get_hexadecimal_valueof &${test_name}_target -1]
> +
> +    # Figure out if there is a delay slot, using symbol
> +    # ${test_name}_has_delay_slot.  Note that it should be read via &,
> +    # otherwise it would try to print value at the address specified in
> +    # ${test_name}_has_delay_slot, while a symbol value itself is required.
> +    if { 0 == [get_integer_valueof &${test_name}_has_delay_slot 0] } {
> +	set has_delay_slot 0
> +    } else {
> +	set has_delay_slot 1
> +    }
> +
> +    set cc [get_hexadecimal_valueof &${test_name}_cc 0]
> +
> +    gdb_test_sequence "mt print arc arc-instruction $pc" "" "
> +	length_with_limm=$length
> +	cc=$cc
> +	is_control_flow=1
> +	has_delay_slot=$has_delay_slot
> +	branch_target=$target_address"

The sequence should be a list, with each element being a line.

I think you probably have duplicate test messages.  Please check
with:
https://sourceware.org/gdb/wiki/GDBTestcaseCookbook#Make_sure_test_messages_are_unique

Thanks,
Pedro Alves
  
Pedro Alves Feb. 17, 2017, 1:01 p.m. UTC | #3
Note, new commands need doc/NEWS entry too, as per contribution checklist:
  https://sourceware.org/gdb/wiki/ContributionChecklist#Documentation

Thanks,
Pedro Alves
  

Patch

diff --git a/gdb/arc-tdep.c b/gdb/arc-tdep.c
index 5495f2e..a18f16a 100644
--- a/gdb/arc-tdep.c
+++ b/gdb/arc-tdep.c
@@ -33,6 +33,7 @@ 
 /* ARC header files.  */
 #include "opcode/arc.h"
 #include "arc-tdep.h"
+#include "arch/arc-insn.h"
 
 /* Standard headers.  */
 #include <algorithm>
@@ -701,7 +702,7 @@  arc_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
    that will not print, or `stream` should be different from standard
    gdb_stdlog.  */
 
-static int
+int
 arc_delayed_print_insn (bfd_vma addr, struct disassemble_info *info)
 {
   int (*print_insn) (bfd_vma, struct disassemble_info *);
@@ -1330,6 +1331,26 @@  maintenance_print_arc_command (char *args, int from_tty)
   cmd_show_list (maintenance_print_arc_list, from_tty, "");
 }
 
+/* This command accepts single argument - address of instruction to
+   disassemble.  */
+
+static void
+dump_arc_instruction_command (char *args, int from_tty)
+{
+  struct value *val;
+  if (args != NULL && strlen (args) > 0)
+    val = evaluate_expression (parse_expression (args).get ());
+  else
+    val = access_value_history (0);
+  record_latest_value (val);
+
+  CORE_ADDR address = value_as_address (val);
+  struct arc_instruction insn;
+  struct disassemble_info di = arc_disassemble_info (target_gdbarch ());
+  arc_insn_decode (address, &di, arc_delayed_print_insn, &insn);
+  arc_insn_dump (insn);
+}
+
 /* Suppress warning from -Wmissing-prototypes.  */
 extern initialize_file_ftype _initialize_arc_tdep;
 
@@ -1350,6 +1371,11 @@  _initialize_arc_tdep (void)
 		  &maintenance_print_arc_list, "maintenance print arc ", 0,
 		  &maintenanceprintlist);
 
+  add_cmd ("arc-instruction", class_maintenance,
+	   dump_arc_instruction_command,
+	   _("Dump arc_instruction structure for specified address."),
+	   &maintenance_print_arc_list);
+
   /* Debug internals for ARC GDB.  */
   add_setshow_zinteger_cmd ("arc", class_maintenance,
 			    &arc_debug,
diff --git a/gdb/arc-tdep.h b/gdb/arc-tdep.h
index 326f486..db7647d 100644
--- a/gdb/arc-tdep.h
+++ b/gdb/arc-tdep.h
@@ -123,4 +123,10 @@  arc_mach_is_arcv2 (struct gdbarch *gdbarch)
   return gdbarch_bfd_arch_info (gdbarch)->mach == bfd_mach_arc_arcv2;
 }
 
+/* Function to access ARC disassembler.  Underlying opcodes disassembler will
+   print an instruction into stream specified in the INFO, so if it is
+   undesired, then this stream should be set to some invisible stream, but it
+   can't be set to an actual NULL value - that would cause a crash.  */
+int arc_delayed_print_insn (bfd_vma addr, struct disassemble_info *info);
+
 #endif /* ARC_TDEP_H */
diff --git a/gdb/arch/arc-insn.c b/gdb/arch/arc-insn.c
new file mode 100644
index 0000000..2dc99a7
--- /dev/null
+++ b/gdb/arch/arc-insn.c
@@ -0,0 +1,275 @@ 
+/* ARC disassembler helper.
+
+   Copyright 2017 Free Software Foundation, Inc.
+   Contributed by Synopsys Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* GDB header files.  */
+#include "defs.h"
+#include "disasm.h"
+
+/* ARC header files.  */
+#include "opcode/arc.h"
+#include "arc-tdep.h"
+#include "arch/arc-insn.h"
+
+void
+arc_insn_dump (const struct arc_instruction &insn)
+{
+  struct gdbarch *gdbarch = target_gdbarch ();
+
+  arc_print ("Dumping arc_instruction at %s\n",
+	     paddress (gdbarch, insn.address));
+  arc_print ("\tlength=%u\n", insn.length);
+
+  if (!insn.valid)
+    {
+      arc_print ("\tThis is not a valid ARC instruction.\n");
+      return;
+    }
+
+  arc_print ("\tlength_with_limm=%u\n", insn.length + (insn.limm_p ? 4 : 0));
+  arc_print ("\tcc=0x%x\n", insn.condition_code);
+  arc_print ("\tinsn_class=%u\n", insn.insn_class);
+  arc_print ("\tis_control_flow=%i\n", insn.is_control_flow);
+  arc_print ("\thas_delay_slot=%i\n", insn.has_delay_slot);
+
+  CORE_ADDR next_pc = arc_insn_get_linear_next_pc (insn);
+  arc_print ("\tlinear_next_pc=%s\n", paddress (gdbarch, next_pc));
+
+  if (insn.is_control_flow)
+    {
+      CORE_ADDR t = arc_insn_get_branch_target (insn);
+      arc_print ("\tbranch_target=%s\n", paddress (gdbarch, t));
+    }
+
+  arc_print ("\tlimm_p=%i\n", insn.limm_p);
+  if (insn.limm_p)
+    arc_print ("\tlimm_value=0x%08x\n", insn.limm_value);
+
+  if (insn.insn_class == STORE || insn.insn_class == LOAD
+      || insn.insn_class == PUSH || insn.insn_class == POP)
+    {
+      arc_print ("\twriteback_mode=%u\n", insn.writeback_mode);
+      arc_print ("\tdata_size_mode=%u\n", insn.data_size_mode);
+      arc_print ("\tmemory_base_register=%s\n",
+		 gdbarch_register_name (gdbarch,
+					arc_insn_get_memory_base_reg (insn)));
+      /* get_memory_offset returns an unsigned CORE_ADDR, but treat it as a
+	 LONGEST for a nicer representation.  */
+      arc_print ("\taddr_offset=%s\n",
+		 plongest (arc_insn_get_memory_offset (insn)));
+    }
+
+  arc_print ("\toperands_count=%u\n", insn.operands_count);
+  for (unsigned int i = 0; i < insn.operands_count; ++i)
+    {
+      int is_reg = (insn.operands[i].kind == ARC_OPERAND_KIND_REG);
+
+      arc_print ("\toperand[%u] = {\n", i);
+      arc_print ("\t\tis_reg=%i\n", is_reg);
+      if (is_reg)
+	arc_print ("\t\tregister=%s\n",
+		   gdbarch_register_name (gdbarch, insn.operands[i].value));
+      /* Don't know if this value is signed or not, so print both
+	 representations.  This tends to look quite ugly, especially for big
+	 numbers.  */
+      arc_print ("\t\tunsigned value=%s\n",
+		 pulongest (arc_insn_get_operand_value (insn, i)));
+      arc_print ("\t\tsigned value=%s\n",
+		 plongest (arc_insn_get_operand_value_signed (insn, i)));
+      arc_print ("\t}\n");
+    }
+}
+
+CORE_ADDR
+arc_insn_get_linear_next_pc (const struct arc_instruction &insn)
+{
+  /* In ARC long immediate is always 4 bytes.  */
+  return (insn.address + insn.length + (insn.limm_p ? 4 : 0));
+}
+
+CORE_ADDR
+arc_insn_get_branch_target (const struct arc_instruction &insn)
+{
+  gdb_assert (insn.is_control_flow);
+
+  /* BI [c]: PC = nextPC + (c << 2).  */
+  if (insn.insn_class == BI)
+    {
+      ULONGEST reg_value = arc_insn_get_operand_value (insn, 0);
+      return arc_insn_get_linear_next_pc (insn) + (reg_value << 2);
+    }
+  /* BIH [c]: PC = nextPC + (c << 1).  */
+  else if (insn.insn_class == BIH)
+    {
+      ULONGEST reg_value = arc_insn_get_operand_value (insn, 0);
+      return arc_insn_get_linear_next_pc (insn) + (reg_value << 1);
+    }
+  /* JLI and EI.  */
+  /* JLI and EI depend on optional AUX registers.  Not supported right now.  */
+  else if (insn.insn_class == JLI)
+    {
+      fprintf_unfiltered (gdb_stderr,
+			  "JLI_S instruction is not supported by the GDB.");
+      return 0;
+    }
+  else if (insn.insn_class == EI)
+    {
+      fprintf_unfiltered (gdb_stderr,
+			  "EI_S instruction is not supported by the GDB.");
+      return 0;
+    }
+  /* LEAVE_S: PC = BLINK.  */
+  else if (insn.insn_class == LEAVE)
+    {
+      struct regcache *regcache = get_current_regcache ();
+      ULONGEST value;
+      regcache_cooked_read_unsigned (regcache, ARC_BLINK_REGNUM, &value);
+      return value;
+    }
+  /* BBIT0/1, BRcc: PC = currentPC + operand.  */
+  else if (insn.insn_class == BBIT0 || insn.insn_class == BBIT1
+	   || insn.insn_class == BRCC)
+    {
+      /* Most instructions has branch target as their sole argument.  However
+	 conditional brcc/bbit has it as a third operand.  */
+      CORE_ADDR pcrel_addr = arc_insn_get_operand_value (insn, 2);
+
+      /* Offset is relative to the 4-byte aligned address of the current
+	 instruction, hence last two bits should be truncated.  */
+      return pcrel_addr + align_down (insn.address, 4);
+    }
+  /* B, Bcc, BL, BLcc, LP, LPcc: PC = currentPC + operand.  */
+  else if (insn.insn_class == BRANCH || insn.insn_class == LOOP)
+    {
+      CORE_ADDR pcrel_addr = arc_insn_get_operand_value (insn, 0);
+
+      /* Offset is relative to the 4-byte aligned address of the current
+	 instruction, hence last two bits should be truncated.  */
+      return pcrel_addr + align_down (insn.address, 4);
+    }
+  /* J, Jcc, JL, JLcc: PC = operand.  */
+  else if (insn.insn_class == JUMP)
+    {
+      /* All jumps are single-operand.  */
+      return arc_insn_get_operand_value (insn, 0);
+    }
+
+  /* This is some new and unknown instruction.  */
+  gdb_assert_not_reached ("Unknown branch instruction.");
+}
+
+ULONGEST
+arc_insn_get_operand_value (const struct arc_instruction &insn,
+			    unsigned int operand_num)
+{
+  switch (insn.operands[operand_num].kind)
+    {
+    case ARC_OPERAND_KIND_LIMM:
+      gdb_assert (insn.limm_p);
+      return insn.limm_value;
+    case ARC_OPERAND_KIND_SHIMM:
+      return insn.operands[operand_num].value;
+    default:
+      /* Value in instruction is a register number.  */
+      struct regcache *regcache = get_current_regcache ();
+      ULONGEST value;
+      regcache_cooked_read_unsigned (regcache,
+				     insn.operands[operand_num].value,
+				     &value);
+      return value;
+    }
+}
+
+LONGEST
+arc_insn_get_operand_value_signed (const struct arc_instruction &insn,
+				   unsigned int operand_num)
+{
+  switch (insn.operands[operand_num].kind)
+    {
+    case ARC_OPERAND_KIND_LIMM:
+      gdb_assert (insn.limm_p);
+      /* Convert unsigned raw value to signed one.  This assumes 2's
+	 complement arithmetic, but so is the LONG_MIN value from generic
+	 defs.h and that assumption is true for ARC.  */
+      gdb_static_assert (sizeof (insn.limm_value) == sizeof (int));
+      return (((LONGEST) insn.limm_value) ^ INT_MIN) - INT_MIN;
+    case ARC_OPERAND_KIND_SHIMM:
+      /* Sign conversion has been done by binutils.  */
+      return insn.operands[operand_num].value;
+    default:
+      /* Value in instruction is a register number.  */
+      struct regcache *regcache = get_current_regcache ();
+      LONGEST value;
+      regcache_cooked_read_signed (regcache,
+				   insn.operands[operand_num].value,
+				   &value);
+      return value;
+    }
+}
+
+int
+arc_insn_get_memory_base_reg (const struct arc_instruction &insn)
+{
+  /* POP_S and PUSH_S have SP as an implicit argument in a disassembler.  */
+  if (insn.insn_class == PUSH || insn.insn_class == POP)
+    return ARC_SP_REGNUM;
+
+  gdb_assert (insn.insn_class == LOAD || insn.insn_class == STORE);
+
+  /* Other instructions all have at least two operands: operand 0 is data,
+     operand 1 is address.  Operand 2 is offset from address.  However, see
+     comment to arc_instruction.operands - in some cases, third operand may be
+     missing, namely if it is 0.  */
+  gdb_assert (insn.operands_count >= 2);
+  return insn.operands[1].value;
+}
+
+CORE_ADDR
+arc_insn_get_memory_offset (const struct arc_instruction &insn)
+{
+  /* POP_S and PUSH_S have offset as an implicit argument in a
+     disassembler.  */
+  if (insn.insn_class == POP)
+    return 4;
+  else if (insn.insn_class == PUSH)
+    return -4;
+
+  gdb_assert (insn.insn_class == LOAD || insn.insn_class == STORE);
+
+  /* Other instructions all have at least two operands: operand 0 is data,
+     operand 1 is address.  Operand 2 is offset from address.  However, see
+     comment to arc_instruction.operands - in some cases, third operand may be
+     missing, namely if it is 0.  */
+  if (insn.operands_count < 3)
+    return 0;
+
+  CORE_ADDR value = arc_insn_get_operand_value (insn, 2);
+  /* Handle scaling.  */
+  if (insn.writeback_mode == ARC_WRITEBACK_AS)
+    {
+      /* Byte data size is not valid for AS.  Halfword means shift by 1 bit.
+	 Word and double word means shift by 2 bits.  */
+      gdb_assert (insn.data_size_mode != ARC_SCALING_B);
+      if (insn.data_size_mode == ARC_SCALING_H)
+	value <<= 1;
+      else
+	value <<= 2;
+    }
+  return value;
+}
diff --git a/gdb/arch/arc-insn.h b/gdb/arch/arc-insn.h
new file mode 100644
index 0000000..e25d226
--- /dev/null
+++ b/gdb/arch/arc-insn.h
@@ -0,0 +1,64 @@ 
+/* ARC disassembler helper.
+
+   Copyright 2017 Free Software Foundation, Inc.
+   Contributed by Synopsys Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef ARC_INSN_H
+#define ARC_INSN_H
+
+#include "opcodes/arc-dis.h"
+
+/* Dump INSN into gdb_stdlog.  */
+
+void arc_insn_dump (const struct arc_instruction &insn);
+
+/* Get address of next instruction after INSN, assuming linear execution (no
+   taken branches).  If instruction has a delay slot, then returned value will
+   point at the instruction in delay slot.  That is - "address of instruction +
+   instruction length with LIMM".  */
+
+CORE_ADDR arc_insn_get_linear_next_pc (const struct arc_instruction &insn);
+
+/* Get branch/jump target address for the INSN.  Note that this function
+   returns branch target and doesn't evaluate if this branch is taken or not.
+   For the indirect jumps value depends in register state, hence can change.
+   It is an error to call this function for a non-branch instruction.  */
+
+CORE_ADDR arc_insn_get_branch_target (const struct arc_instruction &insn);
+
+/* Returns an unsigned value of OPERAND_NUM in instruction INSN.
+   For relative branch instructions returned value is an offset, not an actual
+   branch target.  */
+
+ULONGEST arc_insn_get_operand_value (const struct arc_instruction &insn,
+				     unsigned int operand_num);
+
+/* Like arc_insn_get_operand_value, but returns a signed value.  */
+
+LONGEST arc_insn_get_operand_value_signed (const struct arc_instruction &insn,
+					   unsigned int operand_num);
+
+/* Get register with base address of memory operation.  */
+
+int arc_insn_get_memory_base_reg (const struct arc_instruction &insn);
+
+/* Get offset of a memory operation INSN.  */
+
+CORE_ADDR arc_insn_get_memory_offset (const struct arc_instruction &insn);
+
+#endif /* ARC_INSN_H */
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index cb909e7..532ac54 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -86,12 +86,12 @@  am33_2.0*-*-linux*)
 
 arc*-*-elf32)
 	# Target: baremetal ARC elf32 (newlib) target
-	gdb_target_obs="arc-newlib-tdep.o arc-tdep.o"
+	gdb_target_obs="arc-insn.o arc-newlib-tdep.o arc-tdep.o"
 	;;
 
 arc*-*-*)
 	# Target: Unidentified ARC target
-	gdb_target_obs="arc-tdep.o"
+	gdb_target_obs="arc-insn.o arc-tdep.o"
 	;;
 
 arm*-wince-pe | arm*-*-mingw32ce*)
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index f619470..8cb656a 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -22084,6 +22084,10 @@  messages.
 @kindex show debug arc
 Show the level of ARC specific debugging in operation.
 
+@item maint print arc arc-instruction @var{address}
+@kindex maint print arc arc-instruction
+Print internal disassembler information about instruction at a given address.
+
 @end table
 
 @node ARM
diff --git a/gdb/testsuite/gdb.arch/arc-decode-insn.S b/gdb/testsuite/gdb.arch/arc-decode-insn.S
new file mode 100644
index 0000000..030f158
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/arc-decode-insn.S
@@ -0,0 +1,1002 @@ 
+; This testcase is part of GDB, the GNU debugger.
+
+; Copyright 2017 Synopsys Inc.
+
+; This program is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 3 of the License, or
+; (at your option) any later version.
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+.section .text
+.global main
+
+#define TEST_J
+#define TEST_JCC
+#define TEST_JL
+#define TEST_JLCC
+#define TEST_B
+#define TEST_BBIT
+#define TEST_BCC
+#define TEST_BI
+#define TEST_BL
+#define TEST_BRCC
+#define TEST_JLI
+#define TEST_LEAVE_S
+#define TEST_LPCC
+
+; JLI-specific stuff
+#ifdef TEST_JLI
+jli_table:
+    .word 0xdeadbeea
+    .word 0xdeadbeea
+jli_target:
+    .word 0xdeadbeea
+    .word 0xdeadbeea
+
+.set jli_offset, 3
+#endif
+main:
+
+; Each test case requires several symbols to be set, that identify expected
+; parameters of this instruction.  Required symbols:
+;   ${test}_start: symbol points to start of the test
+;   ${test}_end: symbol points to the instruction after the jump/branch
+;      instruction.
+;   ${test}_target: branch target address.
+;   ${test}_has_delay_slot: whether instruction has delay slot.
+;   ${test}_cc: condition code numeric value.
+
+    .set r12_value, 0xdead0000
+    .set blink_value, 0xdead0004
+    .set limm_value, 0xdead0008
+    ; Just an integer
+    .set r4_value, 0xdead000c
+    ; Just an integer
+    .set r5_value, 0xdead0010
+    ; offset index for BI [c]
+    .set r7_value, 4
+    .set u6_value, 0x20
+    .set s12_target, 0x100
+
+    mov r12, @r12_value
+    mov r4, @r4_value
+    mov r5, @r5_value
+    mov r7, @r7_value
+    mov blink, @blink_value
+#ifdef TEST_JLI
+    ; jli_base aux regnum = 0x290
+    sr jli_table, [0x290]
+#endif
+
+start_branch_tests:
+
+#ifdef TEST_J
+
+#define TEST_NAME j_c
+    ; j [c]
+    .set j_c_target, @r4_value
+    .set j_c_has_delay_slot,   0
+    .set j_c_cc, 0
+    j_c_start:
+	j [r4]
+    j_c_end:
+
+    ; j [blink]
+    .set j_blink_target, @blink_value
+    .set j_blink_has_delay_slot,   0
+    .set j_blink_cc, 0
+    mov blink, @j_blink_target
+    j_blink_start:
+	j [blink]
+    j_blink_end:
+
+    ; j limm
+    .set j_limm_target, @limm_value
+    .set j_limm_has_delay_slot,   0
+    .set j_limm_cc, 0
+    j_limm_start:
+	j @j_limm_target
+    j_limm_end:
+
+    ; j u6
+    .set j_u6_target, @u6_value
+    .set j_u6_has_delay_slot,   0
+    .set j_u6_cc, 0
+    j_u6_start:
+	j @j_u6_target
+    j_u6_end:
+
+    ; j s12
+    .set j_s12_target, @s12_target
+    .set j_s12_has_delay_slot,   0
+    .set j_s12_cc, 0
+    j_s12_start:
+	j @j_s12_target
+    j_s12_end:
+
+    ; j.d [c]
+    .set j_d_c_target, @r4_value
+    .set j_d_c_has_delay_slot,   1
+    .set j_d_c_cc, 0
+    j_d_c_start:
+	j.d [r4]
+    j_d_c_end:
+	nop_s
+
+    ; j.d [blink]
+    .set j_d_blink_target, @blink_value
+    .set j_d_blink_has_delay_slot,   1
+    .set j_d_blink_cc, 0
+    j_d_blink_start:
+	j.d [blink]
+    j_d_blink_end:
+	nop_s
+
+    ; j.d u6
+    .set j_d_u6_target, @u6_value
+    .set j_d_u6_has_delay_slot,   1
+    .set j_d_u6_cc, 0
+    j_d_u6_start:
+	j.d @j_d_u6_target
+    j_d_u6_end:
+	nop_s
+
+    ; j.d s12
+    .set j_d_s12_target, @s12_target
+    .set j_d_s12_has_delay_slot,   1
+    .set j_d_s12_cc, 0
+    j_d_s12_start:
+	j.d @j_d_s12_target
+    j_d_s12_end:
+	nop_s
+
+    ; j_s [b]
+    .set j_s_b_target, @r12_value
+    .set j_s_b_has_delay_slot,   0
+    .set j_s_b_cc, 0
+    j_s_b_start:
+	j_s [r12]
+    j_s_b_end:
+
+    ; j_s.d [b]
+    .set j_s_d_b_target, @r12_value
+    .set j_s_d_b_has_delay_slot,   1
+    .set j_s_d_b_cc, 0
+    j_s_d_b_start:
+	j_s.d [r12]
+    j_s_d_b_end:
+	nop_s
+
+    ; j_s [blink]
+    .set j_s_blink_target, @blink_value
+    .set j_s_blink_has_delay_slot,   0
+    .set j_s_blink_cc, 0
+    j_s_blink_start:
+	j_s [blink]
+    j_s_blink_end:
+
+    ; j_s.d [blink]
+    .set j_s_d_blink_target, @blink_value
+    .set j_s_d_blink_has_delay_slot,   1
+    .set j_c_cc, 0
+    j_s_d_blink_start:
+	j_s.d [blink]
+    j_s_d_blink_end:
+	nop_s
+#endif /* TEST_J */
+
+#ifdef TEST_JCC
+    ; jcc [c]
+    .set jcc_c_target, @r4_value
+    .set jcc_c_has_delay_slot,   0
+    .set jcc_c_cc, 1
+    jcc_c_start:
+	jeq [r4]
+    jcc_c_end:
+
+    ; jcc [blink]
+    .set jcc_blink_target, @blink_value
+    .set jcc_blink_has_delay_slot,   0
+    .set jcc_blink_cc, 2
+    jcc_blink_start:
+	jnz [blink]
+    jcc_blink_end:
+
+    ; jcc limm
+    .set jcc_limm_target, @limm_value
+    .set jcc_limm_has_delay_slot,   0
+    .set jcc_limm_cc, 9
+    jcc_limm_start:
+	jgt @jcc_limm_target
+    jcc_limm_end:
+
+    ; jcc u6
+    .set jcc_u6_target, @u6_value
+    .set jcc_u6_has_delay_slot,   0
+    .set jcc_u6_cc, 0xA
+    jcc_u6_start:
+	jge @jcc_u6_target
+    jcc_u6_end:
+
+    ; jcc.d [c]
+    .set jcc_d_c_target, @r4_value
+    .set jcc_d_c_has_delay_slot,   1
+    .set jcc_d_c_cc, 0xB
+    jcc_d_c_start:
+	jlt.d [r4]
+    jcc_d_c_end:
+	nop_s
+
+    ; jcc.d [blink]
+    .set jcc_d_blink_target, @blink_value
+    .set jcc_d_blink_has_delay_slot,   1
+    .set jcc_d_blink_cc, 0xC
+    jcc_d_blink_start:
+	jle.d [blink]
+    jcc_d_blink_end:
+	nop_s
+
+    ; jcc.d u6
+    .set jcc_d_u6_target, @u6_value
+    .set jcc_d_u6_has_delay_slot,   1
+    .set jcc_d_u6_cc, 0xE
+    jcc_d_u6_start:
+	jls.d @jcc_d_u6_target
+    jcc_d_u6_end:
+	nop_s
+
+    ; jeq_s [blink]
+    .set jcc_eq_s_blink_target, @blink_value
+    .set jcc_eq_s_blink_has_delay_slot,   0
+    .set jcc_eq_s_blink_cc, 1
+    jcc_eq_s_blink_start:
+	jeq_s [blink]
+    jcc_eq_s_blink_end:
+
+    ; jne_s [blink]
+    .set jcc_ne_s_blink_target, @blink_value
+    .set jcc_ne_s_blink_has_delay_slot,   0
+    .set jcc_ne_s_blink_cc, 2
+    jcc_ne_s_blink_start:
+	jne_s [blink]
+    jcc_ne_s_blink_end:
+#endif /* TEST_JCC */
+
+#ifdef TEST_JL
+    ; jl [c]
+    .set jl_c_target, @r4_value
+    .set jl_c_has_delay_slot,   0
+    .set jl_c_cc, 0
+    jl_c_start:
+	jl [r4]
+    jl_c_end:
+
+    ; jl limm
+    .set jl_limm_target, @limm_value
+    .set jl_limm_has_delay_slot,   0
+    .set jl_limm_cc, 0
+    jl_limm_start:
+	jl @jl_limm_target
+    jl_limm_end:
+
+    ; jl u6
+    .set jl_u6_target, @u6_value
+    .set jl_u6_has_delay_slot,   0
+    .set jl_u6_cc, 0
+    jl_u6_start:
+	jl @jl_u6_target
+    jl_u6_end:
+
+    ; jl s12
+    .set jl_s12_target, @s12_target
+    .set jl_s12_has_delay_slot,   0
+    .set jl_s12_cc, 0
+    jl_s12_start:
+	jl @jl_s12_target
+    jl_s12_end:
+
+    ; jl.d [c]
+    .set jl_d_c_target, @r4_value
+    .set jl_d_c_has_delay_slot,   1
+    .set jl_d_c_cc, 0
+    jl_d_c_start:
+	jl.d [r4]
+    jl_d_c_end:
+	nop_s
+
+    ; jl.d u6
+    .set jl_d_u6_target, @u6_value
+    .set jl_d_u6_has_delay_slot,   1
+    .set jl_d_u6_cc, 0
+    jl_d_u6_start:
+	jl.d @jl_d_u6_target
+    jl_d_u6_end:
+	nop_s
+
+    ; jl.d s12
+    .set jl_d_s12_target, @s12_target
+    .set jl_d_s12_has_delay_slot,   1
+    .set jl_d_s12_cc, 0
+    jl_d_s12_start:
+	jl.d @jl_d_s12_target
+    jl_d_s12_end:
+	nop_s
+
+    ; jl_s [b]
+    .set jl_s_b_target, @r12_value
+    .set jl_s_b_has_delay_slot,   0
+    .set jl_s_b_cc, 0
+    jl_s_b_start:
+	jl_s [r12]
+    jl_s_b_end:
+
+    ; jl_s.d [b]
+    .set jl_s_d_b_target, @r12_value
+    .set jl_s_d_b_has_delay_slot,   1
+    .set jl_s_d_b_cc, 0
+    jl_s_d_b_start:
+	jl_s.d [r12]
+    jl_s_d_b_end:
+	nop_s
+#endif /* TEST_JL */
+
+#ifdef TEST_JLCC
+    ; jlcc [c]
+    .set jlcc_c_target, @r4_value
+    .set jlcc_c_has_delay_slot,   0
+    .set jlcc_c_cc, 1
+    jlcc_c_start:
+	jleq [r4]
+    jlcc_c_end:
+
+    ; jlcc limm
+    .set jlcc_limm_target, @limm_value
+    .set jlcc_limm_has_delay_slot,   0
+    .set jlcc_limm_cc, 0x9
+    jlcc_limm_start:
+	jlgt @jlcc_limm_target
+    jlcc_limm_end:
+
+    ; jlcc u6
+    .set jlcc_u6_target, @u6_value
+    .set jlcc_u6_has_delay_slot,   0
+    .set jlcc_u6_cc, 0xA
+    jlcc_u6_start:
+	jlge @jlcc_u6_target
+    jlcc_u6_end:
+
+    ; jlcc.d [c]
+    .set jlcc_d_c_target, @r4_value
+    .set jlcc_d_c_has_delay_slot,   1
+    .set jlcc_d_c_cc, 0xB
+    jlcc_d_c_start:
+	jllt.d [r4]
+    jlcc_d_c_end:
+	nop_s
+
+    ; jlcc.d u6
+    .set jlcc_d_u6_target, @u6_value
+    .set jlcc_d_u6_has_delay_slot,   1
+    .set jlcc_d_u6_cc, 0xE
+    jlcc_d_u6_start:
+	jlls.d @jlcc_d_u6_target
+    jlcc_d_u6_end:
+	nop_s
+#endif /* TEST_JLCC */
+
+#ifdef TEST_B
+.Lb_target:
+    ; Artifical nop, so that first b will not branch to itself.
+    nop_s
+    ; b s25
+    .set b_s25_target, @.Lb_target
+    .set b_s25_has_delay_slot,   0
+    .set b_s25_cc, 0
+    b_s25_start:
+	b @b_s25_target
+    b_s25_end:
+
+    ; b.d s25
+    .set b_d_s25_target, @.Lb_target
+    .set b_d_s25_has_delay_slot,   1
+    .set b_d_s25_cc, 0
+    b_d_s25_start:
+	b.d @b_d_s25_target
+    b_d_s25_end:
+	nop_s
+
+    ; b_s s10
+    .set b_s_s10_target, @.Lb_target
+    .set b_s_s10_has_delay_slot,   0
+    .set b_s_s10_cc, 0
+    b_s_s10_start:
+	b_s @b_s_s10_target
+    b_s_s10_end:
+#endif /* TEST_B */
+
+#ifdef TEST_BBIT
+
+; Due to specifics of bbit implementation in assembler, only local symbols can
+; be used as a branch targets for bbit and brcc.
+; bbits and brcc don't have condition code set to anything.
+.Lbbit_target:
+    nop_s
+
+    ; bbit0.nt b,c,s9
+    .set bbit0_nt_b_c_s9_target, @.Lbbit_target
+    .set bbit0_nt_b_c_s9_has_delay_slot,   0
+    .set bbit0_nt_b_c_s9_cc, 0
+    bbit0_nt_b_c_s9_start:
+	bbit0.nt r4,r5,@bbit0_nt_b_c_s9_target
+    bbit0_nt_b_c_s9_end:
+
+    ; bbit0.d.nt b,c,s9
+    .set bbit0_d_nt_b_c_s9_target, @.Lbbit_target
+    .set bbit0_d_nt_b_c_s9_has_delay_slot,   1
+    .set bbit0_d_nt_b_c_s9_cc, 0
+    bbit0_d_nt_b_c_s9_start:
+	bbit0.d.nt r4,r5,@.Lbbit_target
+    bbit0_d_nt_b_c_s9_end:
+	nop_s
+
+    ; bbit0.t b,c,s9
+    .set bbit0_t_b_c_s9_target, @.Lbbit_target
+    .set bbit0_t_b_c_s9_has_delay_slot,   0
+    .set bbit0_t_b_c_s9_cc, 0
+    bbit0_t_b_c_s9_start:
+	bbit0.t r4,r5,@.Lbbit_target
+    bbit0_t_b_c_s9_end:
+
+    ; bbit0.d.t b,c,s9
+    .set bbit0_d_t_b_c_s9_target, @.Lbbit_target
+    .set bbit0_d_t_b_c_s9_has_delay_slot,   1
+    .set bbit0_d_t_b_c_s9_cc, 0
+    bbit0_d_t_b_c_s9_start:
+	bbit0.d.t r4,r5,@.Lbbit_target
+    bbit0_d_t_b_c_s9_end:
+	nop_s
+
+    ; bbit0.nt b,u6,s9
+    .set bbit0_nt_b_u6_s9_target, @.Lbbit_target
+    .set bbit0_nt_b_u6_s9_has_delay_slot,   0
+    .set bbit0_nt_b_u6_s9_cc, 0
+    bbit0_nt_b_u6_s9_start:
+	bbit0.nt r4,u6_value,@.Lbbit_target
+    bbit0_nt_b_u6_s9_end:
+
+    ; bbit0.d.nt b,u6,s9
+    .set bbit0_d_nt_b_u6_s9_target, @.Lbbit_target
+    .set bbit0_d_nt_b_u6_s9_has_delay_slot,   1
+    .set bbit0_d_nt_b_u6_s9_cc, 0
+    bbit0_d_nt_b_u6_s9_start:
+	bbit0.d.nt r4,u6_value,@.Lbbit_target
+    bbit0_d_nt_b_u6_s9_end:
+	nop_s
+
+    ; bbit0.nt b,u6,s9
+    .set bbit0_t_b_u6_s9_target, @.Lbbit_target
+    .set bbit0_t_b_u6_s9_has_delay_slot,   0
+    .set bbit0_t_b_u6_s9_cc, 0
+    bbit0_t_b_u6_s9_start:
+	bbit0.t r4,u6_value,@.Lbbit_target
+    bbit0_t_b_u6_s9_end:
+
+    ; bbit0.d.nt b,u6,s9
+    .set bbit0_d_t_b_u6_s9_target, @.Lbbit_target
+    .set bbit0_d_t_b_u6_s9_has_delay_slot,   1
+    .set bbit0_d_t_b_u6_s9_cc, 0
+    bbit0_d_t_b_u6_s9_start:
+	bbit0.d.t r4,u6_value,@.Lbbit_target
+    bbit0_d_t_b_u6_s9_end:
+	nop_s
+
+    ; bbit0.nt b,limm,s9
+    .set bbit0_nt_b_limm_s9_target, @.Lbbit_target
+    .set bbit0_nt_b_limm_s9_has_delay_slot,   0
+    .set bbit0_nt_b_limm_s9_cc, 0
+    bbit0_nt_b_limm_s9_start:
+	bbit0.nt r4,limm_value,@.Lbbit_target
+    bbit0_nt_b_limm_s9_end:
+
+    ; bbit0.t b,limm,s9
+    .set bbit0_t_b_limm_s9_target, @.Lbbit_target
+    .set bbit0_t_b_limm_s9_has_delay_slot,   0
+    .set bbit0_t_b_limm_s9_cc, 0
+    bbit0_t_b_limm_s9_start:
+	bbit0.t r4,limm_value,@.Lbbit_target
+    bbit0_t_b_limm_s9_end:
+
+    ; bbit0.nt limm,c,s9
+    .set bbit0_nt_limm_c_s9_target, @.Lbbit_target
+    .set bbit0_nt_limm_c_s9_has_delay_slot,   0
+    .set bbit0_nt_limm_c_s9_cc, 0
+    bbit0_nt_limm_c_s9_start:
+	bbit0.nt limm_value,r4,@.Lbbit_target
+    bbit0_nt_limm_c_s9_end:
+
+    ; bbit0.t limm,c,s9
+    .set bbit0_t_limm_c_s9_target, @.Lbbit_target
+    .set bbit0_t_limm_c_s9_has_delay_slot,   0
+    .set bbit0_t_limm_c_s9_cc, 0
+    bbit0_t_limm_c_s9_start:
+	bbit0.t limm_value,r4,@.Lbbit_target
+    bbit0_t_limm_c_s9_end:
+
+    ; bbit0.nt limm,u6,s9
+    .set bbit0_nt_limm_u6_s9_target, @.Lbbit_target
+    .set bbit0_nt_limm_u6_s9_has_delay_slot,   0
+    .set bbit0_nt_limm_u6_s9_cc, 0
+    bbit0_nt_limm_u6_s9_start:
+	bbit0.nt limm_value,u6_value,@.Lbbit_target
+    bbit0_nt_limm_u6_s9_end:
+
+    ; bbit0.t limm,u6,s9
+    .set bbit0_t_limm_u6_s9_target, @.Lbbit_target
+    .set bbit0_t_limm_u6_s9_has_delay_slot,   0
+    .set bbit0_t_limm_u6_s9_cc, 0
+    bbit0_t_limm_u6_s9_start:
+	bbit0.t limm_value,u6_value,@.Lbbit_target
+    bbit0_t_limm_u6_s9_end:
+
+    ; bbit1.nt b,c,s9
+    .set bbit1_nt_b_c_s9_target, @.Lbbit_target
+    .set bbit1_nt_b_c_s9_has_delay_slot,   0
+    .set bbit1_nt_b_c_s9_cc, 0
+    bbit1_nt_b_c_s9_start:
+	bbit1.nt r4,r5,@.Lbbit_target
+    bbit1_nt_b_c_s9_end:
+
+    ; bbit1.d.nt b,c,s9
+    .set bbit1_d_nt_b_c_s9_target, @.Lbbit_target
+    .set bbit1_d_nt_b_c_s9_has_delay_slot,   1
+    .set bbit1_d_nt_b_c_s9_cc, 0
+    bbit1_d_nt_b_c_s9_start:
+	bbit1.d.nt r4,r5,@.Lbbit_target
+    bbit1_d_nt_b_c_s9_end:
+	nop_s
+
+    ; bbit1.t b,c,s9
+    .set bbit1_t_b_c_s9_target, @.Lbbit_target
+    .set bbit1_t_b_c_s9_has_delay_slot,   0
+    .set bbit1_t_b_c_s9_cc, 0
+    bbit1_t_b_c_s9_start:
+	bbit1.t r4,r5,@.Lbbit_target
+    bbit1_t_b_c_s9_end:
+
+    ; bbit1.d.t b,c,s9
+    .set bbit1_d_t_b_c_s9_target, @.Lbbit_target
+    .set bbit1_d_t_b_c_s9_has_delay_slot,   1
+    .set bbit1_d_t_b_c_s9_cc, 0
+    bbit1_d_t_b_c_s9_start:
+	bbit1.d.t r4,r5,@.Lbbit_target
+    bbit1_d_t_b_c_s9_end:
+	nop_s
+
+    ; bbit1.nt b,u6,s9
+    .set bbit1_nt_b_u6_s9_target, @.Lbbit_target
+    .set bbit1_nt_b_u6_s9_has_delay_slot,   0
+    .set bbit1_nt_b_u6_s9_cc, 0
+    bbit1_nt_b_u6_s9_start:
+	bbit1.nt r4,u6_value,@.Lbbit_target
+    bbit1_nt_b_u6_s9_end:
+
+    ; bbit1.d.nt b,u6,s9
+    .set bbit1_d_nt_b_u6_s9_target, @.Lbbit_target
+    .set bbit1_d_nt_b_u6_s9_has_delay_slot,   1
+    .set bbit1_d_nt_b_u6_s9_cc, 0
+    bbit1_d_nt_b_u6_s9_start:
+	bbit1.d.nt r4,u6_value,@.Lbbit_target
+    bbit1_d_nt_b_u6_s9_end:
+	nop_s
+
+    ; bbit1.nt b,u6,s9
+    .set bbit1_t_b_u6_s9_target, @.Lbbit_target
+    .set bbit1_t_b_u6_s9_has_delay_slot,   0
+    .set bbit1_t_b_u6_s9_cc, 0
+    bbit1_t_b_u6_s9_start:
+	bbit1.t r4,u6_value,@.Lbbit_target
+    bbit1_t_b_u6_s9_end:
+
+    ; bbit1.d.nt b,u6,s9
+    .set bbit1_d_t_b_u6_s9_target, @.Lbbit_target
+    .set bbit1_d_t_b_u6_s9_has_delay_slot,   1
+    .set bbit1_d_t_b_u6_s9_cc, 0
+    bbit1_d_t_b_u6_s9_start:
+	bbit1.d.t r4,u6_value,@.Lbbit_target
+    bbit1_d_t_b_u6_s9_end:
+	nop_s
+
+    ; bbit1.nt b,limm,s9
+    .set bbit1_nt_b_limm_s9_target, @.Lbbit_target
+    .set bbit1_nt_b_limm_s9_has_delay_slot,   0
+    .set bbit1_nt_b_limm_s9_cc, 0
+    bbit1_nt_b_limm_s9_start:
+	bbit1.nt r4,limm_value,@.Lbbit_target
+    bbit1_nt_b_limm_s9_end:
+
+    ; bbit1.t b,limm,s9
+    .set bbit1_t_b_limm_s9_target, @.Lbbit_target
+    .set bbit1_t_b_limm_s9_has_delay_slot,   0
+    .set bbit1_t_b_limm_s9_cc, 0
+    bbit1_t_b_limm_s9_start:
+	bbit1.t r4,limm_value,@.Lbbit_target
+    bbit1_t_b_limm_s9_end:
+
+    ; bbit1.nt limm,c,s9
+    .set bbit1_nt_limm_c_s9_target, @.Lbbit_target
+    .set bbit1_nt_limm_c_s9_has_delay_slot,   0
+    .set bbit1_nt_limm_c_s9_cc, 0
+    bbit1_nt_limm_c_s9_start:
+	bbit1.nt limm_value,r4,@.Lbbit_target
+    bbit1_nt_limm_c_s9_end:
+
+    ; bbit1.t limm,c,s9
+    .set bbit1_t_limm_c_s9_target, @.Lbbit_target
+    .set bbit1_t_limm_c_s9_has_delay_slot,   0
+    .set bbit1_t_limm_c_s9_cc, 0
+    bbit1_t_limm_c_s9_start:
+	bbit1.t limm_value,r4,@.Lbbit_target
+    bbit1_t_limm_c_s9_end:
+
+    ; bbit1.nt limm,u6,s9
+    .set bbit1_nt_limm_u6_s9_target, @.Lbbit_target
+    .set bbit1_nt_limm_u6_s9_has_delay_slot,   0
+    .set bbit1_nt_limm_u6_s9_cc, 0
+    bbit1_nt_limm_u6_s9_start:
+	bbit1.nt limm_value,u6_value,@.Lbbit_target
+    bbit1_nt_limm_u6_s9_end:
+
+    ; bbit1.t limm,u6,s9
+    .set bbit1_t_limm_u6_s9_target, @.Lbbit_target
+    .set bbit1_t_limm_u6_s9_has_delay_slot,   0
+    .set bbit1_t_limm_u6_s9_cc, 0
+    bbit1_t_limm_u6_s9_start:
+	bbit1.t limm_value,u6_value,@.Lbbit_target
+    bbit1_t_limm_u6_s9_end:
+#endif /* TEST_BBIT */
+
+#ifdef TEST_BCC
+.Lbcc_target:
+    ; bcc s21
+    .set bcc_s21_target, @.Lbcc_target
+    .set bcc_s21_has_delay_slot,   0
+    .set bcc_s21_cc, 1
+    bcc_s21_start:
+	; beq @bcc_s21_target
+	beq @.Lbcc_target
+    bcc_s21_end:
+
+    ; bcc.d s21
+    .set bcc_d_s21_target, @.Lbcc_target
+    .set bcc_d_s21_has_delay_slot,   1
+    .set bcc_d_s21_cc, 1
+    bcc_d_s21_start:
+	beq.d @bcc_d_s21_target
+    bcc_d_s21_end:
+	nop_s
+
+.Lbcc_s_target:
+    ; beq_s s10
+    .set beq_s_s10_target, @.Lbcc_s_target
+    .set beq_s_s10_has_delay_slot,   0
+    .set beq_s_s10_cc, 1
+    beq_s_s10_start:
+	# beq_s.d @beq_s_s10_target
+	beq_s @.Lbcc_s_target
+    beq_s_s10_end:
+
+    ; bne_s s10
+    .set bne_s_s10_target, @.Lbcc_s_target
+    .set bne_s_s10_has_delay_slot,   0
+    .set bne_s_s10_cc, 2
+    bne_s_s10_start:
+	bne_s @bne_s_s10_target
+    bne_s_s10_end:
+
+    ; bgt_s s7
+    .set bgt_s_s7_target, @.Lbcc_s_target
+    .set bgt_s_s7_has_delay_slot,   0
+    .set bgt_s_s7_cc, 0x9
+    bgt_s_s7_start:
+	bgt_s @bgt_s_s7_target
+    bgt_s_s7_end:
+
+    ; bge_s s7
+    .set bge_s_s7_target, @.Lbcc_s_target
+    .set bge_s_s7_has_delay_slot,   0
+    .set bge_s_s7_cc, 0xA
+    bge_s_s7_start:
+	bge_s @bge_s_s7_target
+    bge_s_s7_end:
+
+    ; blt_s s7
+    .set blt_s_s7_target, @.Lbcc_s_target
+    .set blt_s_s7_has_delay_slot,   0
+    .set blt_s_s7_cc, 0xB
+    blt_s_s7_start:
+	blt_s @blt_s_s7_target
+    blt_s_s7_end:
+
+    ; ble_s s7
+    .set ble_s_s7_target, @.Lbcc_s_target
+    .set ble_s_s7_has_delay_slot,   0
+    .set ble_s_s7_cc, 0xC
+    ble_s_s7_start:
+	ble_s @ble_s_s7_target
+    ble_s_s7_end:
+
+    ; bhi_s s7
+    .set bhi_s_s7_target, @.Lbcc_s_target
+    .set bhi_s_s7_has_delay_slot,   0
+    .set bhi_s_s7_cc, 0xD
+    bhi_s_s7_start:
+	bhi_s @bhi_s_s7_target
+    bhi_s_s7_end:
+
+    ; bhs_s s7
+    .set bhs_s_s7_target, @.Lbcc_s_target
+    .set bhs_s_s7_has_delay_slot,   0
+    .set bhs_s_s7_cc, 0x6
+    bhs_s_s7_start:
+	bhs_s @bhs_s_s7_target
+    bhs_s_s7_end:
+
+    ; blo_s s7
+    .set blo_s_s7_target, @.Lbcc_s_target
+    .set blo_s_s7_has_delay_slot,   0
+    .set blo_s_s7_cc, 0x5
+    blo_s_s7_start:
+	blo_s @blo_s_s7_target
+    blo_s_s7_end:
+
+    ; bls_s s7
+    .set bls_s_s7_target, @.Lbcc_s_target
+    .set bls_s_s7_has_delay_slot,   0
+    .set bls_s_s7_cc, 0xE
+    bls_s_s7_start:
+	bls_s @bls_s_s7_target
+    bls_s_s7_end:
+#endif /* TEST_BCC */
+
+#ifdef TEST_BI
+    ; bi [c]
+    .set bi_c_target, @bi_c_end + (@r7_value << 2)
+    .set bi_c_has_delay_slot,   0
+    .set bi_c_cc, 0
+    bi_c_start:
+	bi [r7]
+    bi_c_end:
+
+    ; bih [c]
+    .set bih_c_target, @bih_c_end + (@r7_value << 1)
+    .set bih_c_has_delay_slot,   0
+    .set bih_c_cc, 0
+    bih_c_start:
+	bih [r7]
+    bih_c_end:
+#endif /* TEST_BI */
+
+#ifdef TEST_BL
+.Lbl_target:
+    ; bl s25
+    .set bl_s25_target, @.Lbl_target
+    .set bl_s25_has_delay_slot,   0
+    .set bl_s25_cc, 0
+    bl_s25_start:
+	bl @bl_s25_target
+    bl_s25_end:
+
+    ; bl.d s25
+    .set bl_d_s25_target, @.Lbl_target
+    .set bl_d_s25_has_delay_slot,   1
+    .set bl_d_s25_cc, 0
+    bl_d_s25_start:
+	bl.d @bl_d_s25_target
+    bl_d_s25_end:
+	nop_s
+
+    ; bl_s s13
+    .set bl_s_s13_target, @.Lbl_target
+    .set bl_s_s13_has_delay_slot,   0
+    .set bl_s_s13_cc, 0
+    bl_s_s13_start:
+	bl_s @bl_s_s13_target
+    bl_s_s13_end:
+
+    ; blcc s21
+    .set blcc_s21_target, @.Lbl_target
+    .set blcc_s21_has_delay_slot,   0
+    .set blcc_s21_cc, 1
+    blcc_s21_start:
+	bleq @blcc_s21_target
+    blcc_s21_end:
+
+    ; blcc.d s21
+    .set blcc_d_s21_target, @.Lbl_target
+    .set blcc_d_s21_has_delay_slot,   1
+    .set blcc_d_s21_cc, 2
+    blcc_d_s21_start:
+	blnz.d @blcc_d_s21_target
+    blcc_d_s21_end:
+	nop_s
+#endif /* TEST_BL */
+
+#ifdef TEST_BRCC
+.Lbrcc_target:
+    ; breq.nt b,c,s9
+    .set breq_nt_b_c_s9_target, @.Lbrcc_target
+    .set breq_nt_b_c_s9_has_delay_slot,   0
+    .set breq_nt_b_c_s9_cc, 1
+    breq_nt_b_c_s9_start:
+	breq.nt r4,r5,@.Lbrcc_target
+    breq_nt_b_c_s9_end:
+
+    ; breq.d.nt b,c,s9
+    .set breq_d_nt_b_c_s9_target, @.Lbrcc_target
+    .set breq_d_nt_b_c_s9_has_delay_slot,   1
+    .set breq_d_nt_b_c_s9_cc, 1
+    breq_d_nt_b_c_s9_start:
+	breq.d.nt r4,r5,@.Lbrcc_target
+    breq_d_nt_b_c_s9_end:
+	nop_s
+
+    ; breq.t b,c,s9
+    .set breq_t_b_c_s9_target, @.Lbrcc_target
+    .set breq_t_b_c_s9_has_delay_slot,   0
+    .set breq_t_b_c_s9_cc, 1
+    breq_t_b_c_s9_start:
+	breq.t r4,r5,@.Lbrcc_target
+    breq_t_b_c_s9_end:
+
+    ; breq.d.t b,c,s9
+    .set breq_d_t_b_c_s9_target, @.Lbrcc_target
+    .set breq_d_t_b_c_s9_has_delay_slot,   1
+    .set breq_d_t_b_c_s9_cc, 1
+    breq_d_t_b_c_s9_start:
+	breq.d.t r4,r5,@.Lbrcc_target
+    breq_d_t_b_c_s9_end:
+	nop_s
+
+    ; breq.nt b,u6,s9
+    .set breq_nt_b_u6_s9_target, @.Lbrcc_target
+    .set breq_nt_b_u6_s9_has_delay_slot,   0
+    .set breq_nt_b_u6_s9_cc, 1
+    breq_nt_b_u6_s9_start:
+	breq.nt r4,u6_value,@.Lbrcc_target
+    breq_nt_b_u6_s9_end:
+
+    ; breq.d.nt b,u6,s9
+    .set breq_d_nt_b_u6_s9_target, @.Lbrcc_target
+    .set breq_d_nt_b_u6_s9_has_delay_slot,   1
+    .set breq_d_nt_b_u6_s9_cc, 1
+    breq_d_nt_b_u6_s9_start:
+	breq.d.nt r4,u6_value,@.Lbrcc_target
+    breq_d_nt_b_u6_s9_end:
+	nop_s
+
+    ; breq.nt b,u6,s9
+    .set breq_t_b_u6_s9_target, @.Lbrcc_target
+    .set breq_t_b_u6_s9_has_delay_slot,   0
+    .set breq_t_b_u6_s9_cc, 1
+    breq_t_b_u6_s9_start:
+	breq.t r4,u6_value,@.Lbrcc_target
+    breq_t_b_u6_s9_end:
+
+    ; breq.d.nt b,u6,s9
+    .set breq_d_t_b_u6_s9_target, @.Lbrcc_target
+    .set breq_d_t_b_u6_s9_has_delay_slot,   1
+    .set breq_d_t_b_u6_s9_cc, 1
+    breq_d_t_b_u6_s9_start:
+	breq.d.t r4,u6_value,@.Lbrcc_target
+    breq_d_t_b_u6_s9_end:
+	nop_s
+
+    ; breq.nt b,limm,s9
+    .set breq_nt_b_limm_s9_target, @.Lbrcc_target
+    .set breq_nt_b_limm_s9_has_delay_slot,   0
+    .set breq_nt_b_limm_s9_cc, 1
+    breq_nt_b_limm_s9_start:
+	breq.nt r4,limm_value,@.Lbrcc_target
+    breq_nt_b_limm_s9_end:
+
+    ; breq.t b,limm,s9
+    .set breq_t_b_limm_s9_target, @.Lbrcc_target
+    .set breq_t_b_limm_s9_has_delay_slot,   0
+    .set breq_t_b_limm_s9_cc, 1
+    breq_t_b_limm_s9_start:
+	breq.t r4,limm_value,@.Lbrcc_target
+    breq_t_b_limm_s9_end:
+
+    ; breq.nt limm,c,s9
+    .set breq_nt_limm_c_s9_target, @.Lbrcc_target
+    .set breq_nt_limm_c_s9_has_delay_slot,   0
+    .set breq_nt_limm_c_s9_cc, 1
+    breq_nt_limm_c_s9_start:
+	breq.nt limm_value,r4,@.Lbrcc_target
+    breq_nt_limm_c_s9_end:
+
+    ; breq.t limm,c,s9
+    .set breq_t_limm_c_s9_target, @.Lbrcc_target
+    .set breq_t_limm_c_s9_has_delay_slot,   0
+    .set breq_t_limm_c_s9_cc, 1
+    breq_t_limm_c_s9_start:
+	breq.t limm_value,r4,@.Lbrcc_target
+    breq_t_limm_c_s9_end:
+
+    ; breq.nt limm,u6,s9
+    .set breq_nt_limm_u6_s9_target, @.Lbrcc_target
+    .set breq_nt_limm_u6_s9_has_delay_slot,   0
+    .set breq_nt_limm_u6_s9_cc, 1
+    breq_nt_limm_u6_s9_start:
+	breq.nt limm_value,u6_value,@.Lbrcc_target
+    breq_nt_limm_u6_s9_end:
+
+    ; breq.t limm,u6,s9
+    .set breq_t_limm_u6_s9_target, @.Lbrcc_target
+    .set breq_t_limm_u6_s9_has_delay_slot,   0
+    .set breq_t_limm_u6_s9_cc, 1
+    breq_t_limm_u6_s9_start:
+	breq.t limm_value,u6_value,@.Lbrcc_target
+    breq_t_limm_u6_s9_end:
+
+    ; brne_s b,0,s8
+    .set brne_s_b_0_s8_target, @.Lbrcc_target
+    .set brne_s_b_0_s8_has_delay_slot,   0
+    .set brne_s_b_0_s8_cc, 1
+    brne_s_b_0_s8_start:
+	brne r12,0,@.Lbrcc_target
+    brne_s_b_0_s8_end:
+
+    ; breq_s b,0,s8
+    .set breq_s_b_0_s8_target, @.Lbrcc_target
+    .set breq_s_b_0_s8_has_delay_slot,   0
+    .set breq_s_b_0_s8_cc, 1
+    breq_s_b_0_s8_start:
+	breq r12,0,@.Lbrcc_target
+    breq_s_b_0_s8_end:
+#endif /* TEST_BRCC */
+
+#ifdef TEST_JLI
+    ; jli_s u10
+    .set jli_s_u10_target, @jli_target
+    .set jli_s_u10_has_delay_slot,   0
+    .set jli_s_u10_cc, 0
+    jli_s_u10_start:
+	jli_s jli_offset
+    jli_s_u10_end:
+#endif
+
+#ifdef TEST_LEAVE_S
+    ; leave_s
+    .set leave_s_target, @blink_value
+    .set leave_s_has_delay_slot,   0
+    .set leave_s_cc, 0
+    leave_s_start:
+	; leave_s [r13-gp,fp,blink,pcl]
+	leave_s (14 + 16 + 32 + 64)
+    leave_s_end:
+#endif
+
+#ifdef TEST_LPCC
+    ; lpcc
+    .set lpcc_u7_target, @.Llpcc_end
+    .set lpcc_u7_has_delay_slot,   0
+    .set lpcc_u7_cc, 1
+    lpcc_u7_start:
+	lpeq @lpcc_u7_target
+    lpcc_u7_end:
+	nop
+	nop
+.Llpcc_end:
+#endif
+
+.Lend:
+
diff --git a/gdb/testsuite/gdb.arch/arc-decode-insn.exp b/gdb/testsuite/gdb.arch/arc-decode-insn.exp
new file mode 100644
index 0000000..329b4ef
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/arc-decode-insn.exp
@@ -0,0 +1,136 @@ 
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2017 Synopsys Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+# This tests provides certain degree of testing for arch/arc-insn.c functions,
+# however it is not a comprehensive testsuite that would go through all
+# possible ARC instructions - instead this particular test is focused on branch
+# instructions and whether branch targets are evaluated properly.  Most of the
+# non-branch aspects of instruction decoder are used during prologue analysis,
+# so are indirictly tested there.
+
+# To maintain separation of test data and test logic, all of the information
+# about instructions, like if it has delay slot, condition code, branch target
+# address, is all specified in the test assembly file as a symbols, while this
+# test case reads those symbols to learn which values are right, then compares
+# values coming from arc-insn.c with those found in symbols.  More information
+# about requirements to actual test cases can be found in corresponding
+# assembly file of this test case (arc-decode-insn.S).
+
+if {![istarget "arc*-*-*"]} then {
+    verbose "Skipping ARC decoder test."
+    return
+}
+
+standard_testfile .S
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable "" ] != "" } {
+    untested arc-decode-insn.exp
+    return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+if ![runto_main] {
+    fail "Can't run to main"
+    return 0
+}
+
+# Helper function that reads properties of instruction from the ELF file via
+# its symbols and then confirms that decoder output aligns to the expected
+# values.
+proc test_branch_insn { test_name } {
+
+    # Make messages for failed cases more clear, by using hex in them.
+    set pc [get_hexadecimal_valueof &${test_name}_start -1]
+
+    # Calculate instruction length, based on ${test_name}_end symbol.
+    set end_pc [get_hexadecimal_valueof &${test_name}_end -1]
+    set length [expr $end_pc - $pc]
+
+    set target_address [get_hexadecimal_valueof &${test_name}_target -1]
+
+    # Figure out if there is a delay slot, using symbol
+    # ${test_name}_has_delay_slot.  Note that it should be read via &,
+    # otherwise it would try to print value at the address specified in
+    # ${test_name}_has_delay_slot, while a symbol value itself is required.
+    if { 0 == [get_integer_valueof &${test_name}_has_delay_slot 0] } {
+	set has_delay_slot 0
+    } else {
+	set has_delay_slot 1
+    }
+
+    set cc [get_hexadecimal_valueof &${test_name}_cc 0]
+
+    gdb_test_sequence "mt print arc arc-instruction $pc" "" "
+	length_with_limm=$length
+	cc=$cc
+	is_control_flow=1
+	has_delay_slot=$has_delay_slot
+	branch_target=$target_address"
+}
+
+set branch_test_list { }
+
+# Add items in the same groups as they can be enabled/disabled in assembly
+# file.
+lappend branch_test_list \
+    j_c j_blink j_limm j_u6 j_s12 j_d_c j_d_blink j_d_u6
+lappend branch_test_list \
+    jcc_c jcc_blink jcc_limm jcc_u6 jcc_d_c jcc_d_blink jcc_d_u6 jcc_eq_s_blink \
+    jcc_ne_s_blink
+lappend branch_test_list \
+    jl_c jl_limm jl_u6 jl_s12 jl_d_c jl_d_u6 jl_d_s12 jl_s_b jl_s_d_b
+lappend branch_test_list \
+    jlcc_c jlcc_limm jlcc_u6 jlcc_d_c jlcc_d_u6
+lappend branch_test_list \
+    b_s25 b_d_s25 b_s_s10
+lappend branch_test_list \
+    bbit0_nt_b_c_s9 bbit0_d_nt_b_c_s9 bbit0_t_b_c_s9 bbit0_d_t_b_c_s9 \
+    bbit0_nt_b_u6_s9 bbit0_d_nt_b_u6_s9 bbit0_t_b_u6_s9 bbit0_d_t_b_u6_s9 \
+    bbit0_nt_b_limm_s9 bbit0_t_b_limm_s9 bbit0_nt_limm_c_s9 bbit0_t_limm_c_s9 \
+    bbit0_nt_limm_u6_s9 bbit0_t_limm_u6_s9 \
+    bbit1_nt_b_c_s9 bbit1_d_nt_b_c_s9 bbit1_t_b_c_s9 bbit1_d_t_b_c_s9 \
+    bbit1_nt_b_u6_s9 bbit1_d_nt_b_u6_s9 bbit1_t_b_u6_s9 bbit1_d_t_b_u6_s9 \
+    bbit1_nt_b_limm_s9 bbit1_t_b_limm_s9 bbit1_nt_limm_c_s9 bbit1_t_limm_c_s9 \
+    bbit1_nt_limm_u6_s9 bbit1_t_limm_u6_s9
+lappend branch_test_list \
+    bcc_s21 bcc_d_s21 \
+    beq_s_s10 bne_s_s10 bgt_s_s7 bge_s_s7 blt_s_s7 ble_s_s7 bhi_s_s7 bhs_s_s7 \
+    blo_s_s7 bls_s_s7
+lappend branch_test_list \
+    bi_c bih_c
+lappend branch_test_list \
+    bl_s25 bl_d_s25 bl_s_s13 \
+    blcc_s21 blcc_d_s21
+lappend branch_test_list \
+     breq_nt_b_c_s9 breq_d_nt_b_c_s9 breq_t_b_c_s9 breq_d_t_b_c_s9 \
+     breq_nt_b_u6_s9 breq_d_nt_b_u6_s9 breq_t_b_u6_s9 breq_d_t_b_u6_s9 \
+     breq_nt_b_limm_s9 breq_t_b_limm_s9 breq_nt_limm_c_s9 breq_t_limm_c_s9 \
+     breq_nt_limm_u6_s9 breq_t_limm_u6_s9
+# lappend branch_test_list jli_s_u10
+lappend branch_test_list leave_s
+lappend branch_test_list lpcc_u7
+
+runto start_branch_tests
+foreach test $branch_test_list {
+    test_branch_insn $test
+}
+