gas: blackfin: gas: blackfin: reject invalid BYTEOP16P insns
[binutils-gdb.git] / gas / config / bfin-parse.y
index a520226ecb630e0f7be70343e3cdd42fb41dea83..12e752584c2308403b56817b195451e6f3b5fa4f 100644 (file)
@@ -1,5 +1,5 @@
 /* bfin-parse.y  ADI Blackfin parser
-   Copyright 2005, 2006, 2007, 2008, 2009, 2010
+   Copyright 2005, 2006, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
@@ -336,11 +336,15 @@ check_macfuncs (Macfunc *aa, Opt_mode *opa,
       aa->s1.regno |= (ab->s1.regno & CODE_MASK);
     }
 
-  if (aa->w == ab->w  && aa->P != ab->P)
+  if (aa->w == ab->w && aa->P != ab->P)
+    return yyerror ("Destination Dreg sizes (full or half) must match");
+
+  if (aa->w && ab->w)
     {
-      return yyerror ("macfuncs must differ");
-      if (aa->w && (aa->dst.regno - ab->dst.regno != 1))
-       return yyerror ("Destination Dregs must differ by one");
+      if (aa->P && (aa->dst.regno - ab->dst.regno) != 1)
+       return yyerror ("Destination Dregs (full) must differ by one");
+      if (!aa->P && aa->dst.regno != ab->dst.regno)
+       return yyerror ("Destination Dregs (half) must match");
     }
 
   /* Make sure mod flags get ORed, too.  */
@@ -380,6 +384,36 @@ is_group2 (INSTR_T x)
   return 0;
 }
 
+static int
+is_store (INSTR_T x)
+{
+  if (!x)
+    return 0;
+
+  if ((x->value & 0xf000) == 0x8000)
+    {
+      int aop = ((x->value >> 9) & 0x3);
+      int w = ((x->value >> 11) & 0x1);
+      if (!w || aop == 3)
+       return 0;
+      return 1;
+    }
+
+  if (((x->value & 0xFF60) == 0x9E60) ||  /* dagMODim_0 */
+      ((x->value & 0xFFF0) == 0x9F60))    /* dagMODik_0 */
+    return 0;
+
+  /* decode_dspLDST_0 */
+  if ((x->value & 0xFC00) == 0x9C00)
+    {
+      int w = ((x->value >> 9) & 0x1);
+      if (w)
+       return 1;
+    }
+
+  return 0;
+}
+
 static INSTR_T
 gen_multi_instr_1 (INSTR_T dsp32, INSTR_T dsp16_grp1, INSTR_T dsp16_grp2)
 {
@@ -400,6 +434,9 @@ gen_multi_instr_1 (INSTR_T dsp32, INSTR_T dsp16_grp1, INSTR_T dsp16_grp2)
     yyerror ("anomaly 05000074 - Multi-Issue Instruction with \
 dsp32shiftimm in slot1 and P-reg Store in slot2 Not Supported");
 
+  if (is_store (dsp16_grp1) && is_store (dsp16_grp2))
+    yyerror ("Only one instruction in multi-issue instruction can be a store");
+
   return bfin_gen_multi_instr (dsp32, dsp16_grp1, dsp16_grp2);
 }
 
@@ -422,7 +459,7 @@ dsp32shiftimm in slot1 and P-reg Store in slot2 Not Supported");
 
 /* Vector Specific.  */
 %token BYTEOP16P BYTEOP16M
-%token BYTEOP1P BYTEOP2P BYTEOP2M BYTEOP3P
+%token BYTEOP1P BYTEOP2P BYTEOP3P
 %token BYTEUNPACK BYTEPACK
 %token PACK
 %token SAA
@@ -794,13 +831,15 @@ asm_1:
        {
          if (!IS_DREG ($2) || !IS_DREG ($4))
            return yyerror ("Dregs expected");
+         else if (REG_SAME ($2, $4))
+           return yyerror ("Illegal dest register combination");
          else if (!valid_dreg_pair (&$9, $11))
            return yyerror ("Bad dreg pair");
          else if (!valid_dreg_pair (&$13, $15))
            return yyerror ("Bad dreg pair");
          else
            {
-             notethat ("dsp32alu: (dregs , dregs ) = BYTEOP16P (dregs_pair , dregs_pair ) (half)\n");
+             notethat ("dsp32alu: (dregs , dregs ) = BYTEOP16P (dregs_pair , dregs_pair ) (aligndir)\n");
              $$ = DSP32ALU (21, 0, &$2, &$4, &$9, &$13, $17.r0, 0, 0);
            }
        }
@@ -835,6 +874,9 @@ asm_1:
        }
        | LPAREN REG COMMA REG RPAREN ASSIGN SEARCH REG LPAREN searchmod RPAREN
        {
+         if (REG_SAME ($2, $4))
+           return yyerror ("Illegal dest register combination");
+
          if (IS_DREG ($2) && IS_DREG ($4) && IS_DREG ($8))
            {
              notethat ("dsp32alu: (dregs , dregs ) = SEARCH dregs (searchmod)\n");
@@ -846,6 +888,9 @@ asm_1:
        | REG ASSIGN A_ONE_DOT_L PLUS A_ONE_DOT_H COMMA
          REG ASSIGN A_ZERO_DOT_L PLUS A_ZERO_DOT_H
        {
+         if (REG_SAME ($1, $7))
+           return yyerror ("Illegal dest register combination");
+
          if (IS_DREG ($1) && IS_DREG ($7))
            {
              notethat ("dsp32alu: dregs = A1.l + A1.h, dregs = A0.l + A0.h  \n");
@@ -858,6 +903,9 @@ asm_1:
 
        | REG ASSIGN REG_A PLUS REG_A COMMA REG ASSIGN REG_A MINUS REG_A amod1
        {
+         if (REG_SAME ($1, $7))
+           return yyerror ("Resource conflict in dest reg");
+
          if (IS_DREG ($1) && IS_DREG ($7) && !REG_SAME ($3, $5)
              && IS_A1 ($9) && !IS_A1 ($11))
            {
@@ -901,6 +949,8 @@ asm_1:
          if (!IS_DREG ($1) || !IS_DREG ($3) || !IS_DREG ($5) || !IS_DREG ($7))
            return yyerror ("Dregs expected");
 
+         if (REG_SAME ($1, $7))
+           return yyerror ("Resource conflict in dest reg");
 
          if ($4.r0 == 1 && $10.r0 == 2)
            {
@@ -1020,22 +1070,6 @@ asm_1:
            }
        }
 
-       | REG ASSIGN BYTEOP2M LPAREN REG COLON expr COMMA REG COLON expr RPAREN
-         rnd_op
-       {
-         if (!IS_DREG ($1))
-           return yyerror ("Dregs expected");
-         else if (!valid_dreg_pair (&$5, $7))
-           return yyerror ("Bad dreg pair");
-         else if (!valid_dreg_pair (&$9, $11))
-           return yyerror ("Bad dreg pair");
-         else
-           {
-             notethat ("dsp32alu: dregs = BYTEOP2P (dregs_pair , dregs_pair ) (rnd_op)\n");
-             $$ = DSP32ALU (22, $13.r0, 0, &$1, &$5, &$9, $13.s0, 0, $13.x0);
-           }
-       }
-
        | REG ASSIGN BYTEOP3P LPAREN REG COLON expr COMMA REG COLON expr RPAREN
          b3_op
        {
@@ -1728,16 +1762,18 @@ asm_1:
              || (IS_DAGREG ($1) && IS_DAGREG ($3))
              || (IS_GENREG ($1) && $3.regno == REG_USP)
              || ($1.regno == REG_USP && IS_GENREG ($3))
+             || ($1.regno == REG_USP && $3.regno == REG_USP)
              || (IS_DREG ($1) && IS_SYSREG ($3))
              || (IS_PREG ($1) && IS_SYSREG ($3))
-             || (IS_SYSREG ($1) && IS_DREG ($3))
-             || (IS_SYSREG ($1) && IS_PREG ($3))
+             || (IS_SYSREG ($1) && IS_GENREG ($3))
+             || (IS_ALLREG ($1) && IS_EMUDAT ($3))
+             || (IS_EMUDAT ($1) && IS_ALLREG ($3))
              || (IS_SYSREG ($1) && $3.regno == REG_USP))
            {
              $$ = bfin_gen_regmv (&$3, &$1);
            }
          else
-           return yyerror ("Register mismatch");
+           return yyerror ("Unsupported register move");
        }
 
        | CCREG ASSIGN REG
@@ -1748,7 +1784,7 @@ asm_1:
              $$ = bfin_gen_cc2dreg (1, &$3);
            }
          else
-           return yyerror ("Register mismatch");
+           return yyerror ("Only 'CC = Dreg' supported");
        }
 
        | REG ASSIGN CCREG
@@ -1759,7 +1795,7 @@ asm_1:
              $$ = bfin_gen_cc2dreg (0, &$1);
            }
          else
-           return yyerror ("Register mismatch");
+           return yyerror ("Only 'Dreg = CC' supported");
        }
 
        | CCREG _ASSIGN_BANG CCREG
@@ -2369,6 +2405,9 @@ asm_1:
 
        | BITMUX LPAREN REG COMMA REG COMMA REG_A RPAREN asr_asl
        {
+         if (REG_SAME ($3, $5))
+           return yyerror ("Illegal source register combination");
+
          if (IS_DREG ($3) && IS_DREG ($5) && !IS_A1 ($7))
            {
              notethat ("dsp32shift: BITMUX (dregs , dregs , A0) (ASR)\n");
@@ -2662,6 +2701,9 @@ asm_1:
        {
          if (IS_PREG ($3))
            {
+             if ($3.regno == REG_SP || $3.regno == REG_FP)
+               return yyerror ("Bad register for TESTSET");
+
              notethat ("ProgCtrl: TESTSET (pregs )\n");
              $$ = PROGCTRL (11, $3.regno & CODE_MASK);
            }
@@ -3538,6 +3580,17 @@ asm_1:
        }
 
 /* LOOP_BEGIN.  */
+       | LOOP_BEGIN NUMBER
+       {
+         Expr_Node_Value val;
+         val.i_value = $2;
+         Expr_Node *tmp = Expr_Node_Create (Expr_Node_Constant, val, NULL, NULL);
+         bfin_loop_attempt_create_label (tmp, 1);
+         if (!IS_RELOC (tmp))
+           return yyerror ("Invalid expression in LOOP_BEGIN statement");
+         bfin_loop_beginend (tmp, 1);
+         $$ = 0;
+       }
        | LOOP_BEGIN expr
        {
          if (!IS_RELOC ($2))
@@ -3548,6 +3601,17 @@ asm_1:
        }
 
 /* LOOP_END.  */
+       | LOOP_END NUMBER
+       {
+         Expr_Node_Value val;
+         val.i_value = $2;
+         Expr_Node *tmp = Expr_Node_Create (Expr_Node_Constant, val, NULL, NULL);
+         bfin_loop_attempt_create_label (tmp, 1);
+         if (!IS_RELOC (tmp))
+           return yyerror ("Invalid expression in LOOP_END statement");
+         bfin_loop_beginend (tmp, 0);
+         $$ = 0;
+       }
        | LOOP_END expr
        {
          if (!IS_RELOC ($2))