[ARM,11/16] New BFCSEL instruction for Armv8.1-M Mainline

Message ID b6b7b2fa-e095-22a7-8e63-a5a8b546e682@arm.com
State New
Headers show
Series
  • Add support for Armv8.1-M Mainline
Related show

Commit Message

Andre Vieira (lists) April 4, 2019, 1:41 p.m.
Hi

This patch is part of a series of patches to add support for Armv8.1-M 
Mainline instructions to binutils.

This patch adds the BFCSEL instruction. It also adds a local relocation 
with a new bfd_reloc_code_real enum.
Testing: Added new test for the valid instruction operands. Testsuite 
shows no regression when run for arm-none-eabi targets.

Thanks
Sudi


ChangeLog entries are as follows :

*** bfd/ChangeLog ***

2019-04-04  Sudakshina Das  <sudi.das@arm.com>

	* reloc.c (BFD_RELOC_THUMB_PCREL_BFCSEL): New relocation.
	* bfd-in2.h: Regenerated.
	* libbfd.h: Likewise.

*** gas/ChangeLog ***

2019-04-04  Sudakshina Das  <sudi.das@arm.com>

	* config/tc-arm.c (T16_32_TAB): New entriy for bfcsel.
	(do_t_v8_1_branch): New switch case for bfcsel.
	(toU): Define.
	(insns): New instruction for bfcsel.
	(md_pcrel_from_section): New switch case
	for BFD_RELOC_THUMB_PCREL_BFCSEL.
	(md_appdy_fix): Likewise
	(tc_gen_reloc): Likewise.
	* testsuite/gas/arm/armv8_1-m-bfcsel.d: New.
	* testsuite/gas/arm/armv8_1-m-bfcsel.s: New.

*** ld/ChangeLog ***

2019-04-04  Sudakshina Das  <sudi.das@arm.com>

	* testsuite/ld-arm/bfcsel.s: New.
	* testsuite/ld-arm/bfcsel.d: New.
	* testsuite/ld-arm/arm-elf.exp: Add above test.

*** opcodes/ChangeLog ***

2019-04-04  Sudakshina Das  <sudi.das@arm.com>

	* arm-dis.c (thumb32_opcodes): New instruction bfcsel.
	(print_insn_thumb32): Edit the switch case for %Z.

Comments

Andre Vieira (lists) April 12, 2019, 10:39 a.m. | #1
Hi,

Fixed some testisms highlighted by Nick.

This OK?

*** bfd/ChangeLog ***

2019-04-12  Sudakshina Das  <sudi.das@arm.com>

	* reloc.c (BFD_RELOC_THUMB_PCREL_BFCSEL): New relocation.
	* bfd-in2.h: Regenerated.
	* libbfd.h: Likewise.

*** gas/ChangeLog ***

2019-04-12  Sudakshina Das  <sudi.das@arm.com>
             Andre Vieira  <andre.simoesdiasvieira@arm.com>

	* config/tc-arm.c (T16_32_TAB): New entriy for bfcsel.
	(do_t_v8_1_branch): New switch case for bfcsel.
	(toU): Define.
	(insns): New instruction for bfcsel.
	(md_pcrel_from_section): New switch case
	for BFD_RELOC_THUMB_PCREL_BFCSEL.
	(md_appdy_fix): Likewise
	(tc_gen_reloc): Likewise.
	* testsuite/gas/arm/armv8_1-m-bfcsel.d: New.
	* testsuite/gas/arm/armv8_1-m-bfcsel.s: New.

*** ld/ChangeLog ***

2019-04-12  Sudakshina Das  <sudi.das@arm.com>

	* testsuite/ld-arm/bfcsel.s: New.
	* testsuite/ld-arm/bfcsel.d: New.
	* testsuite/ld-arm/arm-elf.exp: Add above test.

*** opcodes/ChangeLog ***

2019-04-12  Sudakshina Das  <sudi.das@arm.com>

	* arm-dis.c (thumb32_opcodes): New instruction bfcsel.
	(print_insn_thumb32): Edit the switch case for %Z.

On 04/04/2019 14:41, Andre Vieira (lists) wrote:
> Hi

> 

> This patch is part of a series of patches to add support for Armv8.1-M 

> Mainline instructions to binutils.

> 

> This patch adds the BFCSEL instruction. It also adds a local relocation 

> with a new bfd_reloc_code_real enum.

> Testing: Added new test for the valid instruction operands. Testsuite 

> shows no regression when run for arm-none-eabi targets.

> 

> Thanks

> Sudi

> 

> 

> ChangeLog entries are as follows :

> 

> *** bfd/ChangeLog ***

> 

> 2019-04-04  Sudakshina Das  <sudi.das@arm.com>

> 

>      * reloc.c (BFD_RELOC_THUMB_PCREL_BFCSEL): New relocation.

>      * bfd-in2.h: Regenerated.

>      * libbfd.h: Likewise.

> 

> *** gas/ChangeLog ***

> 

> 2019-04-04  Sudakshina Das  <sudi.das@arm.com>

> 

>      * config/tc-arm.c (T16_32_TAB): New entriy for bfcsel.

>      (do_t_v8_1_branch): New switch case for bfcsel.

>      (toU): Define.

>      (insns): New instruction for bfcsel.

>      (md_pcrel_from_section): New switch case

>      for BFD_RELOC_THUMB_PCREL_BFCSEL.

>      (md_appdy_fix): Likewise

>      (tc_gen_reloc): Likewise.

>      * testsuite/gas/arm/armv8_1-m-bfcsel.d: New.

>      * testsuite/gas/arm/armv8_1-m-bfcsel.s: New.

> 

> *** ld/ChangeLog ***

> 

> 2019-04-04  Sudakshina Das  <sudi.das@arm.com>

> 

>      * testsuite/ld-arm/bfcsel.s: New.

>      * testsuite/ld-arm/bfcsel.d: New.

>      * testsuite/ld-arm/arm-elf.exp: Add above test.

> 

> *** opcodes/ChangeLog ***

> 

> 2019-04-04  Sudakshina Das  <sudi.das@arm.com>

> 

>      * arm-dis.c (thumb32_opcodes): New instruction bfcsel.

>      (print_insn_thumb32): Edit the switch case for %Z.
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 95d66b586d608ea397121f9124f24b0f2e9a9307..4a3fa75867c814f082ba3ab3079cf60c30ad2b62 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -3567,6 +3567,9 @@ field in the instruction.  */
 /* ARM 5-bit pc-relative branch for Branch Future instructions.  */
   BFD_RELOC_THUMB_PCREL_BRANCH5,
 
+/* ARM 6-bit pc-relative branch for BFCSEL instruction.  */
+  BFD_RELOC_THUMB_PCREL_BFCSEL,
+
 /* ARM 17-bit pc-relative branch for Branch Future instructions.  */
   BFD_RELOC_ARM_THUMB_BF17,
 
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index b3d71d976a437454593dde7afb7c0d8e368c56ca..32080db8c3f6141ae9aa9674c8776694db29905a 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -1530,6 +1530,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_ARM_PCREL_CALL",
   "BFD_RELOC_ARM_PCREL_JUMP",
   "BFD_RELOC_THUMB_PCREL_BRANCH5",
+  "BFD_RELOC_THUMB_PCREL_BFCSEL",
   "BFD_RELOC_ARM_THUMB_BF17",
   "BFD_RELOC_ARM_THUMB_BF13",
   "BFD_RELOC_ARM_THUMB_BF19",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index c41b2fe75d10e9441cd38861b2f6f02f546f6a64..c0e413cd19dbfaf5100143c8879d84cb63ba4a17 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -3019,6 +3019,11 @@ ENUM
 ENUMDOC
   ARM 5-bit pc-relative branch for Branch Future instructions.
 
+ENUM
+  BFD_RELOC_THUMB_PCREL_BFCSEL
+ENUMDOC
+  ARM 6-bit pc-relative branch for BFCSEL instruction.
+
 ENUM
   BFD_RELOC_ARM_THUMB_BF17
 ENUMDOC
diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c
index 5d7f2c0a6d4d7834038b92d6c4256cee7e69ed4c..5e59078890752b0580ae443c7b330e32baecccf6 100644
--- a/gas/config/tc-arm.c
+++ b/gas/config/tc-arm.c
@@ -10506,6 +10506,7 @@ encode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d)
   X(_b,     e000, f000b000),			\
   X(_bcond, d000, f0008000),			\
   X(_bf,    0000, f040e001),			\
+  X(_bfcsel,0000, f000e001),			\
   X(_bfx,   0000, f060e001),			\
   X(_bfl,   0000, f000c001),			\
   X(_bflx,  0000, f070e001),			\
@@ -13384,6 +13385,46 @@ do_t_branch_future (void)
 	  }
 	break;
 
+      case T_MNEM_bfcsel:
+	/* Operand 1.  */
+	if (inst.operands[1].hasreloc == 0)
+	  {
+	    int val = inst.operands[1].imm;
+	    int immA = (val & 0x00001000) >> 12;
+	    int immB = (val & 0x00000ffc) >> 2;
+	    int immC = (val & 0x00000002) >> 1;
+	    inst.instruction |= (immA << 16) | (immB << 1) | (immC << 11);
+	  }
+	  else
+	  {
+	    inst.relocs[1].type = BFD_RELOC_ARM_THUMB_BF13;
+	    inst.relocs[1].pc_rel = 1;
+	  }
+
+	/* Operand 2.  */
+	if (inst.operands[2].hasreloc == 0)
+	  {
+	      constraint ((inst.operands[0].hasreloc != 0), BAD_ARGS);
+	      int val2 = inst.operands[2].imm;
+	      int val0 = inst.operands[0].imm & 0x1f;
+	      int diff = val2 - val0;
+	      if (diff == 4)
+		inst.instruction |= 1 << 17; /* T bit.  */
+	      else if (diff != 2)
+		as_bad (_("out of range label-relative fixup value"));
+	  }
+	else
+	  {
+	      constraint ((inst.operands[0].hasreloc == 0), BAD_ARGS);
+	      inst.relocs[2].type = BFD_RELOC_THUMB_PCREL_BFCSEL;
+	      inst.relocs[2].pc_rel = 1;
+	  }
+
+	/* Operand 3.  */
+	constraint (inst.cond != COND_ALWAYS, BAD_COND);
+	inst.instruction |= (inst.operands[3].imm & 0xf) << 18;
+	break;
+
       case T_MNEM_bfx:
       case T_MNEM_bflx:
 	inst.instruction |= inst.operands[1].reg << 16;
@@ -19616,6 +19657,11 @@ static struct asm_barrier_opt barrier_opt_names[] =
   { mnem, OPS##nops ops, OT_csuffix, 0x0, T_MNEM##top, 0, THUMB_VARIANT, NULL, \
     do_##te }
 
+/* T_MNEM_xyz enumerator variants of ToU.  */
+#define toU(mnem, top, nops, ops, te) \
+  { mnem, OPS##nops ops, OT_unconditional, 0x0, T_MNEM##top, 0, THUMB_VARIANT, \
+    NULL, do_##te }
+
 /* Legacy mnemonics that always have conditional infix after the third
    character.  */
 #define CL(mnem, op, nops, ops, ae)	\
@@ -21706,6 +21752,7 @@ static const struct asm_opcode insns[] =
 #undef  THUMB_VARIANT
 #define THUMB_VARIANT & arm_ext_v8_1m_main
  toC("bf",     _bf,	2, (EXPs, EXPs),	     t_branch_future),
+ toU("bfcsel", _bfcsel,	4, (EXPs, EXPs, EXPs, COND), t_branch_future),
  toC("bfx",    _bfx,	2, (EXPs, RRnpcsp),	     t_branch_future),
  toC("bfl",    _bfl,	2, (EXPs, EXPs),	     t_branch_future),
  toC("bflx",   _bflx,	2, (EXPs, RRnpcsp),	     t_branch_future),
@@ -21741,6 +21788,7 @@ static const struct asm_opcode insns[] =
 #undef ToC
 #undef toC
 #undef ToU
+#undef toU
 
 /* MD interface: bits in the object file.  */
 
@@ -22944,6 +22992,7 @@ md_pcrel_from_section (fixS * fixP, segT seg)
     case BFD_RELOC_THUMB_PCREL_BRANCH12:
     case BFD_RELOC_THUMB_PCREL_BRANCH20:
     case BFD_RELOC_THUMB_PCREL_BRANCH25:
+    case BFD_RELOC_THUMB_PCREL_BFCSEL:
     case BFD_RELOC_ARM_THUMB_BF17:
     case BFD_RELOC_ARM_THUMB_BF19:
     case BFD_RELOC_ARM_THUMB_BF13:
@@ -24844,6 +24893,39 @@ md_apply_fix (fixS *	fixP,
 	}
       break;
 
+    case BFD_RELOC_THUMB_PCREL_BFCSEL:
+      if (fixP->fx_addsy
+	  && (S_GET_SEGMENT (fixP->fx_addsy) == seg)
+	  && !S_FORCE_RELOC (fixP->fx_addsy, TRUE)
+	  && ARM_IS_FUNC (fixP->fx_addsy)
+	  && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v8_1m_main))
+	{
+	  fixP->fx_done = 0;
+	}
+      if ((value & ~0x7f) && ((value & ~0x3f) != ~0x3f))
+	as_bad_where (fixP->fx_file, fixP->fx_line,
+		      _("branch out of range"));
+
+      if (fixP->fx_done || !seg->use_rela_p)
+	{
+	  newval  = md_chars_to_number (buf, THUMB_SIZE);
+
+	  addressT boff = ((newval & 0x0780) >> 7) << 1;
+	  addressT diff = value - boff;
+
+	  if (diff == 4)
+	    {
+	      newval |= 1 << 1; /* T bit.  */
+	    }
+	  else if (diff != 2)
+	    {
+	      as_bad_where (fixP->fx_file, fixP->fx_line,
+			    _("out of range label-relative fixup value"));
+	    }
+	  md_number_to_chars (buf, newval, THUMB_SIZE);
+	}
+      break;
+
     case BFD_RELOC_ARM_THUMB_BF17:
       if (fixP->fx_addsy
 	  && (S_GET_SEGMENT (fixP->fx_addsy) == seg)
@@ -25158,6 +25240,7 @@ tc_gen_reloc (asection *section, fixS *fixp)
       return NULL;
 
     case BFD_RELOC_THUMB_PCREL_BRANCH5:
+    case BFD_RELOC_THUMB_PCREL_BFCSEL:
       as_bad_where (fixp->fx_file, fixp->fx_line,
 		    _("%s used for a symbol not defined in the same file"),
 		    bfd_get_reloc_code_name (fixp->fx_r_type));
diff --git a/gas/testsuite/gas/arm/armv8_1-m-bfcsel.d b/gas/testsuite/gas/arm/armv8_1-m-bfcsel.d
new file mode 100644
index 0000000000000000000000000000000000000000..a498f06cd3e68370b737976ac3453855852f5b58
--- /dev/null
+++ b/gas/testsuite/gas/arm/armv8_1-m-bfcsel.d
@@ -0,0 +1,12 @@
+#name: Valid Armv8.1-M Mainline BFCSEL instruction
+#as: -march=armv8.1-m.main
+#objdump: -dr --prefix-addresses --show-raw-insn
+
+.*: +file format .*arm.*
+
+Disassembly of section .text:
+0[0-9a-f]+ <[^>]+> f080 e803 	bfcsel	2, 0000000a <foo\+0xa>, 4, eq
+0[0-9a-f]+ <[^>]+> 4609      	mov	r1, r1
+0[0-9a-f]+ <[^>]+> d000      	beq.n	0000000a <foo\+0xa>
+0[0-9a-f]+ <[^>]+> 4613      	mov	r3, r2
+0[0-9a-f]+ <[^>]+> 4614      	mov	r4, r2
diff --git a/gas/testsuite/gas/arm/armv8_1-m-bfcsel.s b/gas/testsuite/gas/arm/armv8_1-m-bfcsel.s
new file mode 100644
index 0000000000000000000000000000000000000000..07903ba5f0d282e865e383b32982ca178e1daa2b
--- /dev/null
+++ b/gas/testsuite/gas/arm/armv8_1-m-bfcsel.s
@@ -0,0 +1,12 @@
+	.syntax unified
+	.text
+	.thumb
+foo:
+	bfcsel .LB1, .LBranch, .LB2, eq
+	mov r1, r1
+.LB1:
+	beq .LBranch
+.LB2:
+	mov r3, r2
+.LBranch:
+	mov r4, r2
diff --git a/ld/testsuite/ld-arm/arm-elf.exp b/ld/testsuite/ld-arm/arm-elf.exp
index 528565e97bee829c193ad54ab21e2f9a7071a718..5471895e63a68c0ee5e9c9644564e7b9235a4184 100644
--- a/ld/testsuite/ld-arm/arm-elf.exp
+++ b/ld/testsuite/ld-arm/arm-elf.exp
@@ -673,6 +673,9 @@ set armeabitests_nonacl {
      {"Armv8.1-M Mainline BFL" "-r -Ttext 0x1000 --section-start .foo=0x1001000" "" "-march=armv8.1-m.main" {bfl.s}
       {{objdump -dr bfl.d}}
      "bfl"}
+     {"Armv8.1-M Mainline BFCSEL" "-r -Ttext 0x1000 --section-start .foo=0x1001000" "" "-march=armv8.1-m.main" {bfcsel.s}
+      {{objdump -dr bfcsel.d}}
+     "bfcsel"}
 
     {"R_ARM_THM_JUMP24 Relocation veneers: Short 1"
      "--no-fix-arm1176 --section-start destsect=0x00009000 --section-start .text=0x8000" ""
diff --git a/ld/testsuite/ld-arm/bfcsel.d b/ld/testsuite/ld-arm/bfcsel.d
new file mode 100644
index 0000000000000000000000000000000000000000..914ea93cec431126613bf6326f1446482fba95e0
--- /dev/null
+++ b/ld/testsuite/ld-arm/bfcsel.d
@@ -0,0 +1,18 @@
+
+.*:     file format elf32-.*arm
+
+
+Disassembly of section .text:
+
+00001000 <_start>:
+    1000:	f101 e7ff 	bfcsel	4, 1001000 <bar>, 6, eq
+			1000: R_ARM_THM_BF12	bar
+    1004:	4623      	mov	r3, r4
+    1006:	4611      	mov	r1, r2
+    1008:	d0ff      	beq.n	100a <_start\+0xa>
+    100a:	4613      	mov	r3, r2
+
+Disassembly of section .foo:
+
+01001000 <bar>:
+ 1001000:	4770      	bx	lr
diff --git a/ld/testsuite/ld-arm/bfcsel.s b/ld/testsuite/ld-arm/bfcsel.s
new file mode 100644
index 0000000000000000000000000000000000000000..675e2ea1ae28b64663cd02411550670112dd91a2
--- /dev/null
+++ b/ld/testsuite/ld-arm/bfcsel.s
@@ -0,0 +1,25 @@
+	.global _start
+	.syntax unified
+
+@ We will place the section .text at 0x1000.
+
+	.text
+	.thumb_func
+
+_start:
+	bfcsel .LB1, bar, .LB2, eq
+	mov r3, r4
+	mov r1, r2
+.LB1:
+	beq .LB2
+.LB2:
+	mov r3, r2
+
+@ We will place the section .foo at 0x1001000.
+
+	.section .foo, "xa"
+	.thumb_func
+
+bar:
+	bx lr
+
diff --git a/opcodes/arm-dis.c b/opcodes/arm-dis.c
index f53afc584cfdd271fde85d86ecab219a87c77bd3..b4865c1a42a04bb6a9b156d7369c065ca351efb4 100644
--- a/opcodes/arm-dis.c
+++ b/opcodes/arm-dis.c
@@ -2759,6 +2759,8 @@ static const struct opcode32 thumb32_opcodes[] =
     0xf000c001, 0xf800f001, "bfl%c\t%G, %Y"},
   {ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_1M_MAIN),
     0xf070e001, 0xf8f0f001, "bflx%c\t%G, %16-19S"},
+  {ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_1M_MAIN),
+    0xf000e001, 0xf840f001, "bfcsel\t%G, %Z, %18-21c"},
 
 
   /* ARMv8-M and ARMv8-M Security Extensions instructions.  */
@@ -5934,6 +5936,12 @@ print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given)
 		  offset = (offset & 0x1000) ? offset - (1 << 13) : offset;
 
 		  info->print_address_func (pc + 4 + offset, info);
+
+		  unsigned int T    = (given & 0x00020000u) >> 17;
+		  unsigned int endoffset = (((given & 0x07800000) >> 23) << 1);
+		  unsigned int boffset   = (T == 1) ? 4 : 2;
+		  func (stream, ", ");
+		  func (stream, "%x", endoffset + boffset);
 		}
 		break;

Patch

diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 95d66b586d608ea397121f9124f24b0f2e9a9307..4a3fa75867c814f082ba3ab3079cf60c30ad2b62 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -3567,6 +3567,9 @@  field in the instruction.  */
 /* ARM 5-bit pc-relative branch for Branch Future instructions.  */
   BFD_RELOC_THUMB_PCREL_BRANCH5,
 
+/* ARM 6-bit pc-relative branch for BFCSEL instruction.  */
+  BFD_RELOC_THUMB_PCREL_BFCSEL,
+
 /* ARM 17-bit pc-relative branch for Branch Future instructions.  */
   BFD_RELOC_ARM_THUMB_BF17,
 
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index b3d71d976a437454593dde7afb7c0d8e368c56ca..32080db8c3f6141ae9aa9674c8776694db29905a 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -1530,6 +1530,7 @@  static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_ARM_PCREL_CALL",
   "BFD_RELOC_ARM_PCREL_JUMP",
   "BFD_RELOC_THUMB_PCREL_BRANCH5",
+  "BFD_RELOC_THUMB_PCREL_BFCSEL",
   "BFD_RELOC_ARM_THUMB_BF17",
   "BFD_RELOC_ARM_THUMB_BF13",
   "BFD_RELOC_ARM_THUMB_BF19",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index c41b2fe75d10e9441cd38861b2f6f02f546f6a64..c0e413cd19dbfaf5100143c8879d84cb63ba4a17 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -3019,6 +3019,11 @@  ENUM
 ENUMDOC
   ARM 5-bit pc-relative branch for Branch Future instructions.
 
+ENUM
+  BFD_RELOC_THUMB_PCREL_BFCSEL
+ENUMDOC
+  ARM 6-bit pc-relative branch for BFCSEL instruction.
+
 ENUM
   BFD_RELOC_ARM_THUMB_BF17
 ENUMDOC
diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c
index 5d7f2c0a6d4d7834038b92d6c4256cee7e69ed4c..5e59078890752b0580ae443c7b330e32baecccf6 100644
--- a/gas/config/tc-arm.c
+++ b/gas/config/tc-arm.c
@@ -10506,6 +10506,7 @@  encode_thumb32_addr_mode (int i, bfd_boolean is_t, bfd_boolean is_d)
   X(_b,     e000, f000b000),			\
   X(_bcond, d000, f0008000),			\
   X(_bf,    0000, f040e001),			\
+  X(_bfcsel,0000, f000e001),			\
   X(_bfx,   0000, f060e001),			\
   X(_bfl,   0000, f000c001),			\
   X(_bflx,  0000, f070e001),			\
@@ -13384,6 +13385,46 @@  do_t_branch_future (void)
 	  }
 	break;
 
+      case T_MNEM_bfcsel:
+	/* Operand 1.  */
+	if (inst.operands[1].hasreloc == 0)
+	  {
+	    int val = inst.operands[1].imm;
+	    int immA = (val & 0x00001000) >> 12;
+	    int immB = (val & 0x00000ffc) >> 2;
+	    int immC = (val & 0x00000002) >> 1;
+	    inst.instruction |= (immA << 16) | (immB << 1) | (immC << 11);
+	  }
+	  else
+	  {
+	    inst.relocs[1].type = BFD_RELOC_ARM_THUMB_BF13;
+	    inst.relocs[1].pc_rel = 1;
+	  }
+
+	/* Operand 2.  */
+	if (inst.operands[2].hasreloc == 0)
+	  {
+	      constraint ((inst.operands[0].hasreloc != 0), BAD_ARGS);
+	      int val2 = inst.operands[2].imm;
+	      int val0 = inst.operands[0].imm & 0x1f;
+	      int diff = val2 - val0;
+	      if (diff == 4)
+		inst.instruction |= 1 << 17; /* T bit.  */
+	      else if (diff != 2)
+		as_bad (_("out of range label-relative fixup value"));
+	  }
+	else
+	  {
+	      constraint ((inst.operands[0].hasreloc == 0), BAD_ARGS);
+	      inst.relocs[2].type = BFD_RELOC_THUMB_PCREL_BFCSEL;
+	      inst.relocs[2].pc_rel = 1;
+	  }
+
+	/* Operand 3.  */
+	constraint (inst.cond != COND_ALWAYS, BAD_COND);
+	inst.instruction |= (inst.operands[3].imm & 0xf) << 18;
+	break;
+
       case T_MNEM_bfx:
       case T_MNEM_bflx:
 	inst.instruction |= inst.operands[1].reg << 16;
@@ -19616,6 +19657,11 @@  static struct asm_barrier_opt barrier_opt_names[] =
   { mnem, OPS##nops ops, OT_csuffix, 0x0, T_MNEM##top, 0, THUMB_VARIANT, NULL, \
     do_##te }
 
+/* T_MNEM_xyz enumerator variants of ToU.  */
+#define toU(mnem, top, nops, ops, te) \
+  { mnem, OPS##nops ops, OT_unconditional, 0x0, T_MNEM##top, 0, THUMB_VARIANT, \
+    NULL, do_##te }
+
 /* Legacy mnemonics that always have conditional infix after the third
    character.  */
 #define CL(mnem, op, nops, ops, ae)	\
@@ -21706,6 +21752,7 @@  static const struct asm_opcode insns[] =
 #undef  THUMB_VARIANT
 #define THUMB_VARIANT & arm_ext_v8_1m_main
  toC("bf",     _bf,	2, (EXPs, EXPs),	     t_branch_future),
+ toU("bfcsel", _bfcsel,	4, (EXPs, EXPs, EXPs, COND), t_branch_future),
  toC("bfx",    _bfx,	2, (EXPs, RRnpcsp),	     t_branch_future),
  toC("bfl",    _bfl,	2, (EXPs, EXPs),	     t_branch_future),
  toC("bflx",   _bflx,	2, (EXPs, RRnpcsp),	     t_branch_future),
@@ -21741,6 +21788,7 @@  static const struct asm_opcode insns[] =
 #undef ToC
 #undef toC
 #undef ToU
+#undef toU
 
 /* MD interface: bits in the object file.  */
 
@@ -22944,6 +22992,7 @@  md_pcrel_from_section (fixS * fixP, segT seg)
     case BFD_RELOC_THUMB_PCREL_BRANCH12:
     case BFD_RELOC_THUMB_PCREL_BRANCH20:
     case BFD_RELOC_THUMB_PCREL_BRANCH25:
+    case BFD_RELOC_THUMB_PCREL_BFCSEL:
     case BFD_RELOC_ARM_THUMB_BF17:
     case BFD_RELOC_ARM_THUMB_BF19:
     case BFD_RELOC_ARM_THUMB_BF13:
@@ -24844,6 +24893,39 @@  md_apply_fix (fixS *	fixP,
 	}
       break;
 
+    case BFD_RELOC_THUMB_PCREL_BFCSEL:
+      if (fixP->fx_addsy
+	  && (S_GET_SEGMENT (fixP->fx_addsy) == seg)
+	  && !S_FORCE_RELOC (fixP->fx_addsy, TRUE)
+	  && ARM_IS_FUNC (fixP->fx_addsy)
+	  && ARM_CPU_HAS_FEATURE (selected_cpu, arm_ext_v8_1m_main))
+	{
+	  fixP->fx_done = 0;
+	}
+      if ((value & ~0x7f) && ((value & ~0x3f) != ~0x3f))
+	as_bad_where (fixP->fx_file, fixP->fx_line,
+		      _("branch out of range"));
+
+      if (fixP->fx_done || !seg->use_rela_p)
+	{
+	  newval  = md_chars_to_number (buf, THUMB_SIZE);
+
+	  addressT boff = ((newval & 0x0780) >> 7) << 1;
+	  addressT diff = value - boff;
+
+	  if (diff == 4)
+	    {
+	      newval |= 1 << 1; /* T bit.  */
+	    }
+	  else if (diff != 2)
+	    {
+	      as_bad_where (fixP->fx_file, fixP->fx_line,
+			    _("out of range label-relative fixup value"));
+	    }
+	  md_number_to_chars (buf, newval, THUMB_SIZE);
+	}
+      break;
+
     case BFD_RELOC_ARM_THUMB_BF17:
       if (fixP->fx_addsy
 	  && (S_GET_SEGMENT (fixP->fx_addsy) == seg)
@@ -25158,6 +25240,7 @@  tc_gen_reloc (asection *section, fixS *fixp)
       return NULL;
 
     case BFD_RELOC_THUMB_PCREL_BRANCH5:
+    case BFD_RELOC_THUMB_PCREL_BFCSEL:
       as_bad_where (fixp->fx_file, fixp->fx_line,
 		    _("%s used for a symbol not defined in the same file"),
 		    bfd_get_reloc_code_name (fixp->fx_r_type));
diff --git a/gas/testsuite/gas/arm/armv8_1-m-bfcsel.d b/gas/testsuite/gas/arm/armv8_1-m-bfcsel.d
new file mode 100644
index 0000000000000000000000000000000000000000..7e2599bc37bd4b0ac631c972c6e08c899ad59aa6
--- /dev/null
+++ b/gas/testsuite/gas/arm/armv8_1-m-bfcsel.d
@@ -0,0 +1,14 @@ 
+#name: Valid Armv8.1-M Mainline BFCSEL instruction
+#source: armv8_1-m-bfcsel.s
+#as: -march=armv8.1-m.main
+#objdump: -dr --prefix-addresses --show-raw-insn
+
+.*: +file format .*arm.*
+
+Disassembly of section .text:
+0[0-9a-f]+ <[^>]+> f082 e005 	bfcsel	2, 0000000c <foo\+0xc>, 6, eq
+0[0-9a-f]+ <[^>]+> 4609      	mov	r1, r1
+0[0-9a-f]+ <[^>]+> f43f affe 	beq.w	00000000 <.target>
+			6: R_ARM_THM_JUMP19	.target
+0[0-9a-f]+ <[^>]+> 4613      	mov	r3, r2
+0[0-9a-f]+ <[^>]+> 4614      	mov	r4, r2
diff --git a/gas/testsuite/gas/arm/armv8_1-m-bfcsel.s b/gas/testsuite/gas/arm/armv8_1-m-bfcsel.s
new file mode 100644
index 0000000000000000000000000000000000000000..f9bb30292400ef40b09b243053fedc0a47e3d088
--- /dev/null
+++ b/gas/testsuite/gas/arm/armv8_1-m-bfcsel.s
@@ -0,0 +1,12 @@ 
+	.syntax unified
+	.text
+	.thumb
+foo:
+	bfcsel .LB1, .LBranch, .LB2, eq
+	mov r1, r1
+.LB1:
+	beq .target
+.LB2:
+	mov r3, r2
+.LBranch:
+	mov r4, r2
diff --git a/ld/testsuite/ld-arm/arm-elf.exp b/ld/testsuite/ld-arm/arm-elf.exp
index 528565e97bee829c193ad54ab21e2f9a7071a718..5471895e63a68c0ee5e9c9644564e7b9235a4184 100644
--- a/ld/testsuite/ld-arm/arm-elf.exp
+++ b/ld/testsuite/ld-arm/arm-elf.exp
@@ -673,6 +673,9 @@  set armeabitests_nonacl {
      {"Armv8.1-M Mainline BFL" "-r -Ttext 0x1000 --section-start .foo=0x1001000" "" "-march=armv8.1-m.main" {bfl.s}
       {{objdump -dr bfl.d}}
      "bfl"}
+     {"Armv8.1-M Mainline BFCSEL" "-r -Ttext 0x1000 --section-start .foo=0x1001000" "" "-march=armv8.1-m.main" {bfcsel.s}
+      {{objdump -dr bfcsel.d}}
+     "bfcsel"}
 
     {"R_ARM_THM_JUMP24 Relocation veneers: Short 1"
      "--no-fix-arm1176 --section-start destsect=0x00009000 --section-start .text=0x8000" ""
diff --git a/ld/testsuite/ld-arm/bfcsel.d b/ld/testsuite/ld-arm/bfcsel.d
new file mode 100644
index 0000000000000000000000000000000000000000..d9e8527d9594a9bbc41822fbe740ed507f0b9b84
--- /dev/null
+++ b/ld/testsuite/ld-arm/bfcsel.d
@@ -0,0 +1,18 @@ 
+
+.*:     file format elf32-littlearm
+
+
+Disassembly of section .text:
+
+00001000 <_start>:
+    1000:	f101 e7ff 	bfcsel	4, 1001000 <bar>, 6, eq
+			1000: R_ARM_THM_BF12	bar
+    1004:	4623      	mov	r3, r4
+    1006:	4611      	mov	r1, r2
+    1008:	d0ff      	beq.n	100a <_start\+0xa>
+    100a:	4613      	mov	r3, r2
+
+Disassembly of section .foo:
+
+01001000 <bar>:
+ 1001000:	4770      	bx	lr
diff --git a/ld/testsuite/ld-arm/bfcsel.s b/ld/testsuite/ld-arm/bfcsel.s
new file mode 100644
index 0000000000000000000000000000000000000000..675e2ea1ae28b64663cd02411550670112dd91a2
--- /dev/null
+++ b/ld/testsuite/ld-arm/bfcsel.s
@@ -0,0 +1,25 @@ 
+	.global _start
+	.syntax unified
+
+@ We will place the section .text at 0x1000.
+
+	.text
+	.thumb_func
+
+_start:
+	bfcsel .LB1, bar, .LB2, eq
+	mov r3, r4
+	mov r1, r2
+.LB1:
+	beq .LB2
+.LB2:
+	mov r3, r2
+
+@ We will place the section .foo at 0x1001000.
+
+	.section .foo, "xa"
+	.thumb_func
+
+bar:
+	bx lr
+
diff --git a/opcodes/arm-dis.c b/opcodes/arm-dis.c
index f53afc584cfdd271fde85d86ecab219a87c77bd3..b4865c1a42a04bb6a9b156d7369c065ca351efb4 100644
--- a/opcodes/arm-dis.c
+++ b/opcodes/arm-dis.c
@@ -2759,6 +2759,8 @@  static const struct opcode32 thumb32_opcodes[] =
     0xf000c001, 0xf800f001, "bfl%c\t%G, %Y"},
   {ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_1M_MAIN),
     0xf070e001, 0xf8f0f001, "bflx%c\t%G, %16-19S"},
+  {ARM_FEATURE_CORE_HIGH (ARM_EXT2_V8_1M_MAIN),
+    0xf000e001, 0xf840f001, "bfcsel\t%G, %Z, %18-21c"},
 
 
   /* ARMv8-M and ARMv8-M Security Extensions instructions.  */
@@ -5934,6 +5936,12 @@  print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given)
 		  offset = (offset & 0x1000) ? offset - (1 << 13) : offset;
 
 		  info->print_address_func (pc + 4 + offset, info);
+
+		  unsigned int T    = (given & 0x00020000u) >> 17;
+		  unsigned int endoffset = (((given & 0x07800000) >> 23) << 1);
+		  unsigned int boffset   = (T == 1) ? 4 : 2;
+		  func (stream, ", ");
+		  func (stream, "%x", endoffset + boffset);
 		}
 		break;