2006-03-20 Paul Brook <paul@codesourcery.com>
authorPaul Brook <paul@codesourcery.com>
Mon, 20 Mar 2006 15:38:02 +0000 (15:38 +0000)
committerPaul Brook <paul@codesourcery.com>
Mon, 20 Mar 2006 15:38:02 +0000 (15:38 +0000)
gas/
* config/tc-arm.c (BAD_BRANCH, BAD_NOT_IT): Define.
(do_t_branch): Encode branches inside IT blocks as unconditional.
(do_t_cps): New function.
(do_t_blx, do_t_bkpt, do_t_branch23, do_t_bx, do_t_bxj, do_t_cpsi,
do_t_czb, do_t_it, do_t_setend, do_t_tb): Add IT constaints.
(opcode_lookup): Allow conditional suffixes on all instructions in
Thumb mode.
(md_assemble): Advance condexec state before checking for errors.
(insns): Use do_t_cps.
gas/testsuite/
* gas/arm/thumb2_bcond.d: New test.
* gas/arm/thumb2_bcond.s: New test.
* gas/arm/thumb2_it_bad.d: New test.
* gas/arm/thumb2_it_bad.l: New test.
* gas/arm/thumb2_it_bad.s: New test.

gas/ChangeLog
gas/config/tc-arm.c
gas/testsuite/ChangeLog
gas/testsuite/gas/arm/thumb2_bcond.d [new file with mode: 0644]
gas/testsuite/gas/arm/thumb2_bcond.s [new file with mode: 0644]
gas/testsuite/gas/arm/thumb2_it_bad.d [new file with mode: 0644]
gas/testsuite/gas/arm/thumb2_it_bad.l [new file with mode: 0644]
gas/testsuite/gas/arm/thumb2_it_bad.s [new file with mode: 0644]

index 7ea4f29f4c546e436ca7305faab9904c3776b596..53f3bb25131cd017100861ff5b296af2036b365a 100644 (file)
@@ -1,3 +1,15 @@
+2006-03-20  Paul Brook  <paul@codesourcery.com>
+
+       * config/tc-arm.c (BAD_BRANCH, BAD_NOT_IT): Define.
+       (do_t_branch): Encode branches inside IT blocks as unconditional.
+       (do_t_cps): New function.
+       (do_t_blx, do_t_bkpt, do_t_branch23, do_t_bx, do_t_bxj, do_t_cpsi,
+       do_t_czb, do_t_it, do_t_setend, do_t_tb): Add IT constaints.
+       (opcode_lookup): Allow conditional suffixes on all instructions in
+       Thumb mode.
+       (md_assemble): Advance condexec state before checking for errors.
+       (insns): Use do_t_cps.
+
 2006-03-20  Paul Brook  <paul@codesourcery.com>
 
        * config/tc-arm.c (output_relax_insn): Call dwarf2_emit_insn before
index 01b49e3e32ccfa2e9e3f95d82c8a4484429099a2..583acf27ba53a8540d6b660a7bdd0775c354326c 100644 (file)
@@ -568,6 +568,8 @@ struct asm_opcode
 #define BAD_HIREG      _("lo register required")
 #define BAD_THUMB32    _("instruction not supported in Thumb16 mode")
 #define BAD_ADDR_MODE   _("instruction does not accept this addressing mode");
+#define BAD_BRANCH     _("branch must be last instruction in IT block")
+#define BAD_NOT_IT     _("instruction not allowed in IT block")
 
 static struct hash_control *arm_ops_hsh;
 static struct hash_control *arm_cond_hsh;
@@ -6597,6 +6599,7 @@ do_t_bfx (void)
 static void
 do_t_blx (void)
 {
+  constraint (current_it_mask && current_it_mask != 0x10, BAD_BRANCH);
   if (inst.operands[0].isreg)
     /* We have a register, so this is BLX(2).  */
     inst.instruction |= inst.operands[0].reg << 3;
@@ -6618,7 +6621,20 @@ static void
 do_t_branch (void)
 {
   int opcode;
-  if (inst.cond != COND_ALWAYS)
+  int cond;
+
+  if (current_it_mask)
+    {
+      /* Conditional branches inside IT blocks are encoded as unconditional
+         branches.  */
+      cond = COND_ALWAYS;
+      /* A branch must be the last instruction in an IT block.  */
+      constraint (current_it_mask != 0x10, BAD_BRANCH);
+    }
+  else
+    cond = inst.cond;
+
+  if (cond != COND_ALWAYS)
     opcode = T_MNEM_bcond;
   else
     opcode = inst.instruction;
@@ -6626,23 +6642,23 @@ do_t_branch (void)
   if (unified_syntax && inst.size_req == 4)
     {
       inst.instruction = THUMB_OP32(opcode);
-      if (inst.cond == COND_ALWAYS)
+      if (cond == COND_ALWAYS)
        inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH25;
       else
        {
-         assert (inst.cond != 0xF);
-         inst.instruction |= inst.cond << 22;
+         assert (cond != 0xF);
+         inst.instruction |= cond << 22;
          inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH20;
        }
     }
   else
     {
       inst.instruction = THUMB_OP16(opcode);
-      if (inst.cond == COND_ALWAYS)
+      if (cond == COND_ALWAYS)
        inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH12;
       else
        {
-         inst.instruction |= inst.cond << 8;
+         inst.instruction |= cond << 8;
          inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH9;
        }
       /* Allow section relaxation.  */
@@ -6656,6 +6672,8 @@ do_t_branch (void)
 static void
 do_t_bkpt (void)
 {
+  constraint (inst.cond != COND_ALWAYS,
+             _("instruction is always unconditional"));
   if (inst.operands[0].present)
     {
       constraint (inst.operands[0].imm > 255,
@@ -6667,6 +6685,7 @@ do_t_bkpt (void)
 static void
 do_t_branch23 (void)
 {
+  constraint (current_it_mask && current_it_mask != 0x10, BAD_BRANCH);
   inst.reloc.type   = BFD_RELOC_THUMB_PCREL_BRANCH23;
   inst.reloc.pc_rel = 1;
 
@@ -6685,6 +6704,7 @@ do_t_branch23 (void)
 static void
 do_t_bx (void)
 {
+  constraint (current_it_mask && current_it_mask != 0x10, BAD_BRANCH);
   inst.instruction |= inst.operands[0].reg << 3;
   /* ??? FIXME: Should add a hacky reloc here if reg is REG_PC.         The reloc
      should cause the alignment to be checked once it is known.         This is
@@ -6694,6 +6714,7 @@ do_t_bx (void)
 static void
 do_t_bxj (void)
 {
+  constraint (current_it_mask && current_it_mask != 0x10, BAD_BRANCH);
   if (inst.operands[0].reg == REG_PC)
     as_tsktsk (_("use of r15 in bxj is not really useful"));
 
@@ -6708,9 +6729,17 @@ do_t_clz (void)
   inst.instruction |= inst.operands[1].reg;
 }
 
+static void
+do_t_cps (void)
+{
+  constraint (current_it_mask, BAD_NOT_IT);
+  inst.instruction |= inst.operands[0].imm;
+}
+
 static void
 do_t_cpsi (void)
 {
+  constraint (current_it_mask, BAD_NOT_IT);
   if (unified_syntax
       && (inst.operands[1].present || inst.size_req == 4)
       && ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v6_notm))
@@ -6757,6 +6786,7 @@ do_t_cpy (void)
 static void
 do_t_czb (void)
 {
+  constraint (current_it_mask, BAD_NOT_IT);
   constraint (inst.operands[0].reg > 7, BAD_HIREG);
   inst.instruction |= inst.operands[0].reg;
   inst.reloc.pc_rel = 1;
@@ -6793,6 +6823,7 @@ do_t_it (void)
 {
   unsigned int cond = inst.operands[0].imm;
 
+  constraint (current_it_mask, BAD_NOT_IT);
   current_it_mask = (inst.instruction & 0xf) | 0x10;
   current_cc = cond;
 
@@ -7627,6 +7658,7 @@ do_t_rsb (void)
 static void
 do_t_setend (void)
 {
+  constraint (current_it_mask, BAD_NOT_IT);
   if (inst.operands[0].imm)
     inst.instruction |= 0x8;
 }
@@ -7895,12 +7927,13 @@ do_t_tb (void)
   int half;
 
   half = (inst.instruction & 0x10) != 0;
+  constraint (current_it_mask && current_it_mask != 0x10, BAD_BRANCH);
+  constraint (inst.operands[0].immisreg,
+             _("instruction requires register index"));
   constraint (inst.operands[0].imm == 15,
              _("PC is not a valid index register"));
   constraint (!half && inst.operands[0].shifted,
              _("instruction does not allow shifted index"));
-  constraint (half && !inst.operands[0].shifted,
-             _("instruction requires shifted index"));
   inst.instruction |= (inst.operands[0].reg << 16) | inst.operands[0].imm;
 }
 
@@ -8225,9 +8258,16 @@ opcode_lookup (char **str)
 
        case OT_unconditional:
        case OT_unconditionalF:
-         /* delayed diagnostic */
-         inst.error = BAD_COND;
-         inst.cond = COND_ALWAYS;
+         if (thumb_mode)
+           {
+             inst.cond = cond->value;
+           }
+         else
+           {
+             /* delayed diagnostic */
+             inst.error = BAD_COND;
+             inst.cond = COND_ALWAYS;
+           }
          return opcode;
 
        default:
@@ -8322,13 +8362,15 @@ md_assemble (char *str)
        {
          int cond;
          cond = current_cc ^ ((current_it_mask >> 4) & 1) ^ 1;
-         if (cond != inst.cond)
+         current_it_mask <<= 1;
+         current_it_mask &= 0x1f;
+         /* The BKPT instruction is unconditional even in an IT block.  */
+         if (!inst.error
+             && cond != inst.cond && opcode->tencode != do_t_bkpt)
            {
              as_bad (_("incorrect condition in IT block"));
              return;
            }
-         current_it_mask <<= 1;
-         current_it_mask &= 0x1f;
        }
       else if (inst.cond != COND_ALWAYS && opcode->tencode != do_t_branch)
        {
@@ -8824,7 +8866,8 @@ static struct asm_barrier_opt barrier_opt_names[] =
        TxCM(m1,m2, aop, T_MNEM_##top, nops, ops, ae, te)
 
 /* Mnemonic that cannot be conditionalized.  The ARM condition-code
-   field is still 0xE.  */
+   field is still 0xE.  Many of the Thumb variants can be executed
+   conditionally, so this is checked separately.  */
 #define TUE(mnem, op, top, nops, ops, ae, te)                          \
   { #mnem, OPS##nops ops, OT_unconditional, 0x##op, 0x##top, ARM_VARIANT, \
     THUMB_VARIANT, do_##ae, do_##te }
@@ -9162,7 +9205,7 @@ static const struct asm_opcode insns[] =
 /*  ARM V6 not included in V7M (eg. integer SIMD).  */
 #undef THUMB_VARIANT
 #define THUMB_VARIANT &arm_ext_v6_notm
- TUF(cps,      1020000, f3af8100, 1, (I31b),                     imm0, imm0),
+ TUF(cps,      1020000, f3af8100, 1, (I31b),                     imm0, t_cps),
  TCE(pkhbt,    6800010, eac00000, 4, (RRnpc, RRnpc, RRnpc, oSHll),   pkhbt, t_pkhbt),
  TCE(pkhtb,    6800050, eac00020, 4, (RRnpc, RRnpc, RRnpc, oSHar),   pkhtb, t_pkhtb),
  TCE(qadd16,   6200f10, fa90f010, 3, (RRnpc, RRnpc, RRnpc),       rd_rn_rm, t_simd),
index 982f74b246ab82f26dbae7bd09d77ae2513dac61..cde23291605f941190d8aaa3357754cc0d51e14d 100644 (file)
@@ -1,3 +1,11 @@
+2006-03-20  Paul Brook  <paul@codesourcery.com>
+
+       * gas/arm/thumb2_bcond.d: New test.
+       * gas/arm/thumb2_bcond.s: New test.
+       * gas/arm/thumb2_it_bad.d: New test.
+       * gas/arm/thumb2_it_bad.l: New test.
+       * gas/arm/thumb2_it_bad.s: New test.
+
 2006-03-17  Paul Brook  <paul@codesourcery.com>
 
        * gas/arm/thumb32.d: Add ldm and stm tests.
diff --git a/gas/testsuite/gas/arm/thumb2_bcond.d b/gas/testsuite/gas/arm/thumb2_bcond.d
new file mode 100644 (file)
index 0000000..90b8e20
--- /dev/null
@@ -0,0 +1,25 @@
+# as:
+# objdump: -dr --prefix-addresses --show-raw-insn
+
+.*: +file format .*arm.*
+
+Disassembly of section .text:
+0+000 <[^>]+> bf18             it      ne
+0+002 <[^>]+> e7fd             b(|ne).n        0+0 <[^>]+>
+0+004 <[^>]+> bf38             it      cc
+0+006 <[^>]+> f7ff bffb        b(|cc).w        0+0 <[^>]+>
+0+00a <[^>]+> bf28             it      cs
+0+00c <[^>]+> f7ff fff8        bl(|cs) 0+0 <[^>]+>
+0+010 <[^>]+> bfb8             it      lt
+0+012 <[^>]+> 47a8             blx(|lr)        r5
+0+014 <[^>]+> bf08             it      eq
+0+016 <[^>]+> 4740             bx(|eq) r8
+0+018 <[^>]+> bfc8             it      gt
+0+01a <[^>]+> e8d4 f001        tbb(|gt)        \[r4, r1\]
+0+01e <[^>]+> bfb8             it      lt
+0+020 <[^>]+> df00             svc(|lt)        0
+0+022 <[^>]+> bfdc             itt     le
+0+024 <[^>]+> be00             bkpt    0x0000
+0+026 <[^>]+> bf00             nop
+0+028 <[^>]+> bf00             nop
+0+02a <[^>]+> bf00             nop
diff --git a/gas/testsuite/gas/arm/thumb2_bcond.s b/gas/testsuite/gas/arm/thumb2_bcond.s
new file mode 100644 (file)
index 0000000..4a066f2
--- /dev/null
@@ -0,0 +1,25 @@
+       .text
+       .arch armv7
+       .thumb
+       .syntax unified
+       .thumb_func
+thumb2_bcond:
+       it ne
+       bne thumb2_bcond
+       it cc
+       bcc.w thumb2_bcond
+       it cs
+       blcs thumb2_bcond
+       it lt
+       blxlt r5
+       it eq
+       bxeq r8
+       it gt
+       tbbgt [r4, r1]
+       it lt
+       svclt 0
+       itt le
+       bkpt #0
+       nople
+       nop
+       nop
diff --git a/gas/testsuite/gas/arm/thumb2_it_bad.d b/gas/testsuite/gas/arm/thumb2_it_bad.d
new file mode 100644 (file)
index 0000000..1cca8b9
--- /dev/null
@@ -0,0 +1,3 @@
+#name: Invalid IT instructions
+#as:
+#error-output: thumb2_it_bad.l
diff --git a/gas/testsuite/gas/arm/thumb2_it_bad.l b/gas/testsuite/gas/arm/thumb2_it_bad.l
new file mode 100644 (file)
index 0000000..e2e96cd
--- /dev/null
@@ -0,0 +1,12 @@
+[^:]*: Assembler messages:
+[^:]*:8: Error: branch must be last instruction in IT block -- `beq foo'
+[^:]*:9: Error: branch must be last instruction in IT block -- `bleq foo'
+[^:]*:10: Error: branch must be last instruction in IT block -- `blxeq r0'
+[^:]*:11: Error: instruction not allowed in IT block -- `cbzeq r0,foo'
+[^:]*:13: Error: branch must be last instruction in IT block -- `bxeq r0'
+[^:]*:14: Error: branch must be last instruction in IT block -- `tbbeq \[r0,r1\]'
+[^:]*:15: Error: instruction not allowed in IT block -- `cpsieeq f'
+[^:]*:17: Error: instruction not allowed in IT block -- `cpseq #0x10'
+[^:]*:19: Error: instruction is always unconditional -- `bkpteq 0'
+[^:]*:20: Error: instruction not allowed in IT block -- `setendeq le'
+[^:]*:22: Error: instruction not allowed in IT block -- `iteq eq'
diff --git a/gas/testsuite/gas/arm/thumb2_it_bad.s b/gas/testsuite/gas/arm/thumb2_it_bad.s
new file mode 100644 (file)
index 0000000..6add4fb
--- /dev/null
@@ -0,0 +1,24 @@
+       .text
+       .syntax unified
+       .arch armv7a
+       .thumb
+       .thumb_func
+thumb2_it_bad:
+       itttt   eq
+       beq     foo
+       bleq    foo
+       blxeq   r0
+       cbzeq   r0, foo
+       ittt    eq
+       bxeq    r0
+       tbbeq   [r0, r1]
+       cpsieeq f
+       it      eq
+       cpseq   #0x10
+       itt     eq
+       bkpteq  0
+       setendeq        le
+       it      eq
+       iteq    eq
+       nop
+foo: