This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH 3/6] [ARC] Add BI/BIH instruction support.
- From: Andrew Burgess <andrew dot burgess at embecosm dot com>
- To: Claudiu Zissulescu <claziss at gmail dot com>
- Cc: gcc-patches at gcc dot gnu dot org, fbedard at synopsys dot com, claziss at synopsys dot com
- Date: Tue, 16 Oct 2018 23:22:47 +0100
- Subject: Re: [PATCH 3/6] [ARC] Add BI/BIH instruction support.
- References: <20181010080016.12317-1-claziss@gmail.com> <20181010080016.12317-4-claziss@gmail.com>
* Claudiu Zissulescu <claziss@gmail.com> [2018-10-10 11:00:13 +0300]:
> Use BI/BIH instruction to implement casesi pattern. Only ARC V2.
This removes the compact-casesi as an option for earlier ARC, right?
Was there a reason why that had to be done?
>
> gcc/
> 2018-03-21 Claudiu Zissulescu <claziss@synopsys.com>
>
> * config/arc/arc.c (arc_override_options): Remove
> TARGET_COMPACT_CASESI.
> * config/arc/arc.h (ASM_OUTPUT_ADDR_DIFF_ELT): Update.
> (CASE_VECTOR_MODE): Likewise.
> (CASE_VECTOR_PC_RELATIVE): Likewise.
> (CASE_VECTOR_SHORTEN_MODE): Likewise.
> (CASE_VECTOR_SHORTEN_MODE1): Delete.
> (ADDR_VEC_ALIGN): Update.
> (ASM_OUTPUT_CASE_LABEL): Undefine.
> (ASM_OUTPUT_BEFORE_CASE_LABEL): Undefine.
> (TARGET_BI_BIH): Define.
> (DEFAULT_BRANCH_INDEX): Likewise.
> * config/arc/arc.md (casesi): Rework to accept BI/BIH
> instructions, remove compact_casesi use case.
> (casesi_compact_jump): Remove.
> (casesi_dispatch): New pattern.
> * config/arc/arc.opt: Add mbranch-index option. Deprecate
> compact_casesi option.
> * doc/invoke.texi: Document mbranch-index option.
I guess if you feel that dropping compact-casesi support for earlier
targets is appropriate, then that's fine. There's some formatting
issues I point out below. But otherwise seems reasonable.
Thanks,
Andrew
>
> gcc/testsuite
> Claudiu Zissulescu <claziss@synopsys.com>
>
> * gcc.target/arc/jumptable.c: New test.
> ---
> gcc/config/arc/arc.c | 19 --
> gcc/config/arc/arc.h | 106 ++++++-----
> gcc/config/arc/arc.md | 218 +++++++----------------
> gcc/config/arc/arc.opt | 6 +-
> gcc/doc/invoke.texi | 9 +-
> gcc/testsuite/gcc.target/arc/jumptable.c | 34 ++++
> 6 files changed, 171 insertions(+), 221 deletions(-)
> create mode 100644 gcc/testsuite/gcc.target/arc/jumptable.c
>
> diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c
> index 56f566795ff..18dd0de6af7 100644
> --- a/gcc/config/arc/arc.c
> +++ b/gcc/config/arc/arc.c
> @@ -1291,33 +1291,14 @@ arc_override_options (void)
> if (arc_size_opt_level == 3)
> optimize_size = 1;
>
> - /* Compact casesi is not a valid option for ARCv2 family. */
> - if (TARGET_V2)
> - {
> - if (TARGET_COMPACT_CASESI)
> - {
> - warning (OPT_mcompact_casesi,
> - "compact-casesi is not applicable to ARCv2");
> - TARGET_COMPACT_CASESI = 0;
> - }
> - }
> - else if (optimize_size == 1
> - && !global_options_set.x_TARGET_COMPACT_CASESI)
> - TARGET_COMPACT_CASESI = 1;
> -
> if (flag_pic)
> target_flags |= MASK_NO_SDATA_SET;
>
> if (flag_no_common == 255)
> flag_no_common = !TARGET_NO_SDATA_SET;
>
> - /* TARGET_COMPACT_CASESI needs the "q" register class. */
> if (TARGET_MIXED_CODE)
> TARGET_Q_CLASS = 1;
> - if (!TARGET_Q_CLASS)
> - TARGET_COMPACT_CASESI = 0;
> - if (TARGET_COMPACT_CASESI)
> - TARGET_CASE_VECTOR_PC_RELATIVE = 1;
>
> /* Check for small data option */
> if (!global_options_set.x_g_switch_value && !TARGET_NO_SDATA_SET)
> diff --git a/gcc/config/arc/arc.h b/gcc/config/arc/arc.h
> index dd78a6bbbd1..cb48b85d6e7 100644
> --- a/gcc/config/arc/arc.h
> +++ b/gcc/config/arc/arc.h
> @@ -1264,25 +1264,39 @@ do { \
> } while (0)
>
> /* This is how to output an element of a case-vector that is relative. */
> -#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
> -do { \
> - char label[30]; \
> - ASM_GENERATE_INTERNAL_LABEL (label, "L", VALUE); \
> - switch (GET_MODE (BODY)) \
> - { \
> - case E_QImode: fprintf (FILE, "\t.byte "); break; \
> - case E_HImode: fprintf (FILE, "\t.hword "); break; \
> - case E_SImode: fprintf (FILE, "\t.word "); break; \
> - default: gcc_unreachable (); \
> - } \
> - assemble_name (FILE, label); \
> - fprintf (FILE, "-"); \
> - ASM_GENERATE_INTERNAL_LABEL (label, "L", REL); \
> - assemble_name (FILE, label); \
> - if (TARGET_COMPACT_CASESI) \
> - fprintf (FILE, " + %d", 4 + arc_get_unalign ()); \
> - fprintf(FILE, "\n"); \
> -} while (0)
> +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
> + do { \
> + char label[30]; \
> + ASM_GENERATE_INTERNAL_LABEL (label, "L", VALUE); \
> + if (!TARGET_BI_BIH) \
> + { \
> + switch (GET_MODE (BODY)) \
> + { \
> + case E_QImode: fprintf (FILE, "\t.byte "); break; \
> + case E_HImode: fprintf (FILE, "\t.hword "); break; \
> + case E_SImode: fprintf (FILE, "\t.word "); break; \
> + default: gcc_unreachable (); \
> + } \
> + assemble_name (FILE, label); \
> + fprintf (FILE, "-"); \
> + ASM_GENERATE_INTERNAL_LABEL (label, "L", REL); \
> + assemble_name (FILE, label); \
> + fprintf(FILE, "\n"); \
Missing whitespace before (.
> + } else { \
Split the '} else {' over separate lines.
> + switch (GET_MODE (BODY)) \
> + { \
> + case E_SImode: fprintf (FILE, "\tb\t@"); break; \
> + case E_HImode: \
> + case E_QImode: fprintf (FILE, "\tb_s\t@"); break; \
> + default: gcc_unreachable (); \
> + } \
> + assemble_name (FILE, label); \
> + fprintf(FILE, "\n"); \
Missing whitespace before (.
> + } \
> + } while (0)
> +
> +/* Defined to also emit an .align in elfos.h. We don't want that. */
> +#undef ASM_OUTPUT_CASE_LABEL
>
> /* ADDR_DIFF_VECs are in the text section and thus can affect the
> current alignment. */
> @@ -1380,36 +1394,34 @@ do { \
> for the index in the tablejump instruction.
> If we have pc relative case vectors, we start the case vector shortening
> with QImode. */
> -#define CASE_VECTOR_MODE \
> - ((optimize && (CASE_VECTOR_PC_RELATIVE || flag_pic)) ? QImode : Pmode)
> +#define CASE_VECTOR_MODE \
> + (TARGET_BI_BIH ? SImode \
> + : (optimize && (CASE_VECTOR_PC_RELATIVE || flag_pic)) ? QImode : Pmode)
>
> /* Define as C expression which evaluates to nonzero if the tablejump
> instruction expects the table to contain offsets from the address of the
> table.
> Do not define this if the table should contain absolute addresses. */
> -#define CASE_VECTOR_PC_RELATIVE TARGET_CASE_VECTOR_PC_RELATIVE
> -
> -#define CASE_VECTOR_SHORTEN_MODE(MIN_OFFSET, MAX_OFFSET, BODY) \
> - CASE_VECTOR_SHORTEN_MODE_1 \
> - (MIN_OFFSET, TARGET_COMPACT_CASESI ? MAX_OFFSET + 6 : MAX_OFFSET, BODY)
> -
> -#define CASE_VECTOR_SHORTEN_MODE_1(MIN_OFFSET, MAX_OFFSET, BODY) \
> -((MIN_OFFSET) >= 0 && (MAX_OFFSET) <= 255 \
> - ? (ADDR_DIFF_VEC_FLAGS (BODY).offset_unsigned = 1, QImode) \
> - : (MIN_OFFSET) >= -128 && (MAX_OFFSET) <= 127 \
> - ? (ADDR_DIFF_VEC_FLAGS (BODY).offset_unsigned = 0, QImode) \
> - : (MIN_OFFSET) >= 0 && (MAX_OFFSET) <= 65535 \
> - ? (ADDR_DIFF_VEC_FLAGS (BODY).offset_unsigned = 1, HImode) \
> - : (MIN_OFFSET) >= -32768 && (MAX_OFFSET) <= 32767 \
> - ? (ADDR_DIFF_VEC_FLAGS (BODY).offset_unsigned = 0, HImode) \
> - : SImode)
> -
> -#define ADDR_VEC_ALIGN(VEC_INSN) \
> - (exact_log2 (GET_MODE_SIZE (as_a <scalar_int_mode> \
> - (GET_MODE (PATTERN (VEC_INSN))))))
> -#undef ASM_OUTPUT_BEFORE_CASE_LABEL
> -#define ASM_OUTPUT_BEFORE_CASE_LABEL(FILE, PREFIX, NUM, TABLE) \
> - ASM_OUTPUT_ALIGN ((FILE), ADDR_VEC_ALIGN (TABLE))
> +#define CASE_VECTOR_PC_RELATIVE \
> + (TARGET_CASE_VECTOR_PC_RELATIVE || TARGET_BI_BIH)
> +
> +#define CASE_VECTOR_SHORTEN_MODE(MIN_OFFSET, MAX_OFFSET, BODY) \
> + (TARGET_BI_BIH ? \
> + ((MIN_OFFSET) >= -512 && (MAX_OFFSET) <= 508 ? HImode : SImode) \
> + : ((MIN_OFFSET) >= 0 && (MAX_OFFSET) <= 255 \
> + ? (ADDR_DIFF_VEC_FLAGS (BODY).offset_unsigned = 1, QImode) \
> + : (MIN_OFFSET) >= -128 && (MAX_OFFSET) <= 127 \
> + ? (ADDR_DIFF_VEC_FLAGS (BODY).offset_unsigned = 0, QImode) \
> + : (MIN_OFFSET) >= 0 && (MAX_OFFSET) <= 65535 \
> + ? (ADDR_DIFF_VEC_FLAGS (BODY).offset_unsigned = 1, HImode) \
> + : (MIN_OFFSET) >= -32768 && (MAX_OFFSET) <= 32767 \
> + ? (ADDR_DIFF_VEC_FLAGS (BODY).offset_unsigned = 0, HImode) \
> + : SImode))
> +
> +#define ADDR_VEC_ALIGN(VEC_INSN) \
> + (TARGET_BI_BIH ? 0 \
> + : exact_log2 (GET_MODE_SIZE (as_a <scalar_int_mode> \
> + (GET_MODE (PATTERN (VEC_INSN))))))
>
> #define INSN_LENGTH_ALIGNMENT(INSN) \
> ((JUMP_TABLE_DATA_P (INSN) \
> @@ -1636,4 +1648,10 @@ enum
> #define TARGET_LRA arc_lra_p()
> #endif
>
> +/* BI/BIH feature macro. */
> +#define TARGET_BI_BIH (TARGET_BRANCH_INDEX && TARGET_CODE_DENSITY)
> +
> +/* The default option for BI/BIH instructions. */
> +#define DEFAULT_BRANCH_INDEX 0
> +
> #endif /* GCC_ARC_H */
> diff --git a/gcc/config/arc/arc.md b/gcc/config/arc/arc.md
> index 6ea67791627..1ed230fa5f0 100644
> --- a/gcc/config/arc/arc.md
> +++ b/gcc/config/arc/arc.md
> @@ -3968,60 +3968,72 @@ archs4x, archs4xd, archs4xd_slow"
> (set_attr "cond" "canuse,canuse_limm,canuse,canuse,canuse")])
>
> ;; Implement a switch statement.
> -
> (define_expand "casesi"
> - [(set (match_dup 5)
> - (minus:SI (match_operand:SI 0 "register_operand" "")
> - (match_operand:SI 1 "nonmemory_operand" "")))
> - (set (reg:CC CC_REG)
> - (compare:CC (match_dup 5)
> - (match_operand:SI 2 "nonmemory_operand" "")))
> - (set (pc)
> - (if_then_else (gtu (reg:CC CC_REG)
> - (const_int 0))
> - (label_ref (match_operand 4 "" ""))
> - (pc)))
> - (set (match_dup 6)
> - (unspec:SI [(match_operand 3 "" "")
> - (match_dup 5) (match_dup 7)] UNSPEC_ARC_CASESI))
> - (parallel [(set (pc) (match_dup 6)) (use (match_dup 7))])]
> + [(match_operand:SI 0 "register_operand" "") ; Index
> + (match_operand:SI 1 "const_int_operand" "") ; Lower bound
> + (match_operand:SI 2 "const_int_operand" "") ; Total range
> + (match_operand:SI 3 "" "") ; Table label
> + (match_operand:SI 4 "" "")] ; Out of range label
> ""
> - "
> -{
> - rtx x;
> -
> - operands[5] = gen_reg_rtx (SImode);
> - operands[6] = gen_reg_rtx (SImode);
> - operands[7] = operands[3];
> - emit_insn (gen_subsi3 (operands[5], operands[0], operands[1]));
> - emit_insn (gen_cmpsi_cc_insn_mixed (operands[5], operands[2]));
> - x = gen_rtx_GTU (VOIDmode, gen_rtx_REG (CCmode, CC_REG), const0_rtx);
> - x = gen_rtx_IF_THEN_ELSE (VOIDmode, x,
> - gen_rtx_LABEL_REF (VOIDmode, operands[4]), pc_rtx);
> - emit_jump_insn (gen_rtx_SET (pc_rtx, x));
> - if (TARGET_COMPACT_CASESI)
> - {
> - emit_jump_insn (gen_casesi_compact_jump (operands[5], operands[7]));
> - }
> - else
> - {
> + {
> + if (operands[1] != const0_rtx)
> + {
> + rtx reg = gen_reg_rtx (SImode);
> + emit_insn (gen_subsi3 (reg, operands[0], operands[1]));
> + operands[0] = reg;
> + }
Indentation seems wonky here.
> + emit_jump_insn (gen_cbranchsi4 (gen_rtx_GTU (SImode, operands[0],
> + operands[2]),
> + operands[0], operands[2], operands[4]));
> + if (TARGET_BI_BIH)
> + {
> + emit_jump_insn (gen_casesi_dispatch (operands[0], operands[3]));
> + }
Don't think the {} are needed for a single line.
> + else
> + {
Shouldn't the '{' be indented? And the block below accordingly?
> + rtx reg = gen_reg_rtx (SImode);
> + rtx lbl = operands[3];
> operands[3] = gen_rtx_LABEL_REF (VOIDmode, operands[3]);
> - if (flag_pic || !cse_not_expected)
> + if (flag_pic)
> operands[3] = force_reg (Pmode, operands[3]);
> - emit_insn (gen_casesi_load (operands[6],
> - operands[3], operands[5], operands[7]));
> + emit_insn (gen_casesi_load (reg,
> + operands[3], operands[0], lbl));
> if (CASE_VECTOR_PC_RELATIVE || flag_pic)
> - emit_insn (gen_addsi3 (operands[6], operands[6], operands[3]));
> - emit_jump_insn (gen_casesi_jump (operands[6], operands[7]));
> + emit_insn (gen_addsi3 (reg, reg, operands[3]));
> + emit_jump_insn (gen_casesi_jump (reg, lbl));
> + }
> + DONE;
> + })
> +
> +(define_insn "casesi_dispatch"
> + [(set (pc)
> + (unspec:SI [(match_operand:SI 0 "register_operand" "r")
> + (label_ref (match_operand 1 "" ""))]
> + UNSPEC_ARC_CASESI))]
> + "TARGET_BI_BIH"
> + {
> + rtx diff_vec = PATTERN (next_nonnote_insn (as_a<rtx_insn *> (operands[1])));
> + gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC);
> + switch (GET_MODE (diff_vec))
> + {
Indent the { I think.
> + case E_SImode:
> + return \"bi\\t[%0]\";
> + case E_HImode:
> + case E_QImode:
> + return \"bih\\t[%0]\";
> + default: gcc_unreachable ();
> }
> - DONE;
> -}")
> + }
> + [(set_attr "type" "brcc_no_delay_slot")
> + (set_attr "iscompact" "false")
> + (set_attr "length" "4")])
>
> (define_insn "casesi_load"
> - [(set (match_operand:SI 0 "register_operand" "=Rcq,r,r")
> - (unspec:SI [(match_operand:SI 1 "nonmemory_operand" "Rcq,c,Cal")
> - (match_operand:SI 2 "register_operand" "Rcq,c,c")
> - (label_ref (match_operand 3 "" ""))] UNSPEC_ARC_CASESI))]
> + [(set (match_operand:SI 0 "register_operand" "=q,r,r")
> + (mem:SI (unspec:SI [(match_operand:SI 1 "nonmemory_operand" "q,r,Cal")
> + (match_operand:SI 2 "register_operand" "q,r,r")]
> + UNSPEC_ARC_CASESI)))
> + (use (label_ref (match_operand 3 "" "")))]
> ""
> "*
> {
> @@ -4037,15 +4049,15 @@ archs4x, archs4xd, archs4xd_slow"
> switch (GET_MODE (diff_vec))
> {
> case E_SImode:
> - return \"ld.as %0,[%1,%2]%&\";
> + return \"ld.as\\t%0,[%1,%2]%&\";
> case E_HImode:
> if (ADDR_DIFF_VEC_FLAGS (diff_vec).offset_unsigned)
> - return \"ld%_.as %0,[%1,%2]\";
> - return \"ld%_.x.as %0,[%1,%2]\";
> + return \"ld%_.as\\t%0,[%1,%2]\";
> + return \"ld%_.x.as\\t%0,[%1,%2]\";
> case E_QImode:
> if (ADDR_DIFF_VEC_FLAGS (diff_vec).offset_unsigned)
> - return \"ldb%? %0,[%1,%2]%&\";
> - return \"ldb.x %0,[%1,%2]\";
> + return \"ldb%?\\t%0,[%1,%2]%&\";
> + return \"ldb.x\\t%0,[%1,%2]\";
> default:
> gcc_unreachable ();
> }
> @@ -4085,110 +4097,6 @@ archs4x, archs4xd, archs4xd_slow"
> (set_attr "iscompact" "false,maybe,false")
> (set_attr "cond" "canuse")])
>
> -(define_insn "casesi_compact_jump"
> - [(set (pc)
> - (unspec:SI [(match_operand:SI 0 "register_operand" "c,q")]
> - UNSPEC_ARC_CASESI))
> - (use (label_ref (match_operand 1 "" "")))
> - (clobber (match_scratch:SI 2 "=q,0"))]
> - "TARGET_COMPACT_CASESI"
> - "*
> -{
> - rtx diff_vec = PATTERN (next_nonnote_insn (as_a<rtx_insn *> (operands[1])));
> - int unalign = arc_get_unalign ();
> - rtx xop[3];
> - const char *s;
> -
> - xop[0] = operands[0];
> - xop[2] = operands[2];
> - gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC);
> -
> - switch (GET_MODE (diff_vec))
> - {
> - case E_SImode:
> - /* Max length can be 12 in this case, but this is OK because
> - 2 of these are for alignment, and are anticipated in the length
> - of the ADDR_DIFF_VEC. */
> - if (unalign && !satisfies_constraint_Rcq (xop[0]))
> - s = \"add2 %2,pcl,%0\n\tld_s %2,[%2,12]\";
> - else if (unalign)
> - s = \"add_s %2,%0,2\n\tld.as %2,[pcl,%2]\";
> - else
> - s = \"add %2,%0,2\n\tld.as %2,[pcl,%2]\";
> - arc_clear_unalign ();
> - break;
> - case E_HImode:
> - if (ADDR_DIFF_VEC_FLAGS (diff_vec).offset_unsigned)
> - {
> - if (satisfies_constraint_Rcq (xop[0]))
> - {
> - s = \"add_s %2,%0,%1\n\tld%_.as %2,[pcl,%2]\";
> - xop[1] = GEN_INT ((10 - unalign) / 2U);
> - }
> - else
> - {
> - s = \"add1 %2,pcl,%0\n\tld%__s %2,[%2,%1]\";
> - xop[1] = GEN_INT (10 + unalign);
> - }
> - }
> - else
> - {
> - if (satisfies_constraint_Rcq (xop[0]))
> - {
> - s = \"add_s %2,%0,%1\n\tld%_.x.as %2,[pcl,%2]\";
> - xop[1] = GEN_INT ((10 - unalign) / 2U);
> - }
> - else
> - {
> - s = \"add1 %2,pcl,%0\n\tld%__s.x %2,[%2,%1]\";
> - xop[1] = GEN_INT (10 + unalign);
> - }
> - }
> - arc_toggle_unalign ();
> - break;
> - case E_QImode:
> - if (ADDR_DIFF_VEC_FLAGS (diff_vec).offset_unsigned)
> - {
> - if ((rtx_equal_p (xop[2], xop[0])
> - || find_reg_note (insn, REG_DEAD, xop[0]))
> - && satisfies_constraint_Rcq (xop[0]))
> - {
> - s = \"add_s %0,%0,pcl\n\tldb_s %2,[%0,%1]\";
> - xop[1] = GEN_INT (8 + unalign);
> - }
> - else
> - {
> - s = \"add %2,%0,pcl\n\tldb_s %2,[%2,%1]\";
> - xop[1] = GEN_INT (10 + unalign);
> - arc_toggle_unalign ();
> - }
> - }
> - else if ((rtx_equal_p (xop[0], xop[2])
> - || find_reg_note (insn, REG_DEAD, xop[0]))
> - && satisfies_constraint_Rcq (xop[0]))
> - {
> - s = \"add_s %0,%0,%1\n\tldb.x %2,[pcl,%0]\";
> - xop[1] = GEN_INT (10 - unalign);
> - arc_toggle_unalign ();
> - }
> - else
> - {
> - /* ??? Length is 12. */
> - s = \"add %2,%0,%1\n\tldb.x %2,[pcl,%2]\";
> - xop[1] = GEN_INT (8 + unalign);
> - }
> - break;
> - default:
> - gcc_unreachable ();
> - }
> - output_asm_insn (s, xop);
> - return \"add_s %2,%2,pcl\n\tj_s%* [%2]\";
> -}"
> - [(set_attr "length" "10")
> - (set_attr "type" "jump")
> - (set_attr "iscompact" "true")
> - (set_attr "cond" "nocond")])
> -
> (define_expand "call"
> ;; operands[1] is stack_size_rtx
> ;; operands[2] is next_arg_register
> diff --git a/gcc/config/arc/arc.opt b/gcc/config/arc/arc.opt
> index ee06c063837..3e96b58375d 100644
> --- a/gcc/config/arc/arc.opt
> +++ b/gcc/config/arc/arc.opt
> @@ -328,7 +328,7 @@ Target Var(TARGET_CASE_VECTOR_PC_RELATIVE)
> Use pc-relative switch case tables - this enables case table shortening.
>
> mcompact-casesi
> -Target Var(TARGET_COMPACT_CASESI)
> +Target Warn(%qs is deprecated)
> Enable compact casesi pattern.
>
> mq-class
> @@ -528,3 +528,7 @@ Enum(arc_lpc) String(32) Value(32)
> mrf16
> Target Report Mask(RF16)
> Enable 16-entry register file.
> +
> +mbranch-index
> +Target Report Var(TARGET_BRANCH_INDEX) Init(DEFAULT_BRANCH_INDEX)
> +Enable use of BI/BIH instructions when available.
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 802cc642453..454587310c8 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -650,7 +650,7 @@ Objective-C and Objective-C++ Dialects}.
> -mmixed-code -mq-class -mRcq -mRcw -msize-level=@var{level} @gol
> -mtune=@var{cpu} -mmultcost=@var{num} @gol
> -munalign-prob-threshold=@var{probability} -mmpy-option=@var{multo} @gol
> --mdiv-rem -mcode-density -mll64 -mfpu=@var{fpu} -mrf16}
> +-mdiv-rem -mcode-density -mll64 -mfpu=@var{fpu} -mrf16 -mbranch-index}
>
> @emph{ARM Options}
> @gccoptlist{-mapcs-frame -mno-apcs-frame @gol
> @@ -15814,6 +15814,11 @@ This option instructs the compiler to generate code for a 16-entry
> register file. This option defines the @code{__ARC_RF16__}
> preprocessor macro.
>
> +@item -mbranch-index
> +@opindex mbranch-index
> +Enable use of @code{bi} or @code{bih} instructions to implement jump
> +tables.
> +
> @end table
>
> The following options are passed through to the assembler, and also
> @@ -15985,7 +15990,7 @@ This is the default for @option{-Os}.
> @item -mcompact-casesi
> @opindex mcompact-casesi
> Enable compact @code{casesi} pattern. This is the default for @option{-Os},
> -and only available for ARCv1 cores.
> +and only available for ARCv1 cores. This option is deprecated.
>
> @item -mno-cond-exec
> @opindex mno-cond-exec
> diff --git a/gcc/testsuite/gcc.target/arc/jumptable.c b/gcc/testsuite/gcc.target/arc/jumptable.c
> new file mode 100644
> index 00000000000..fbc58e33149
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/arc/jumptable.c
> @@ -0,0 +1,34 @@
> +/* { dg-do compile } */
> +/* { dg-skip-if "" { arc700 || arc6xx } } */
> +/* { dg-options "-O2 -mbranch-index -mcode-density" { target { arcem || archs } } } */
> +
> +extern void max( int,int);
> +
> +int switchCase(int value, int b)
> +{
> + switch(value){
> + case 100:
> + value = b * value;
> + break;
> + case 101:
> + value = b << value;
> + break;
> + case 102:
> + value = b / value;
> + break;
> + case 103:
> + value = b >> value;
> + break;
> + case 104:
> + value = b + value;
> + break;
> + case 105:
> + value = b - value;
> + break;
> + }
> + max(value, b);
> + return 0;
> +}
> +
> +/* { dg-final { scan-assembler-times "bih" 1 } } */
> +/* { dg-final { scan-assembler-times "b_s" 8 } } */
> --
> 2.17.1
>