2007-09-28 Bernd Schmidt <bernd.schmidt@analog.com>
[deliverable/binutils-gdb.git] / gas / config / bfin-parse.y
index 917c2d27ba0f0104405d639af6b95a811e91dd62..d22f774b1c850ffcf38038a5f604917f22267a80 100644 (file)
@@ -1,12 +1,12 @@
 /* bfin-parse.y  ADI Blackfin parser
-   Copyright 2005
+   Copyright 2005, 2006, 2007, 2008
    Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
    GAS 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 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    GAS is distributed in the hope that it will be useful,
    02110-1301, USA.  */
 %{
 
-#include <stdio.h>
-#include <stdarg.h>
+#include "as.h"
 #include <obstack.h>
 
-#include "bfin-aux.h"  // opcode generating auxiliaries
+#include "bfin-aux.h"  /* Opcode generating auxiliaries.  */
 #include "libbfd.h"
 #include "elf/common.h"
 #include "elf/bfin.h"
@@ -170,13 +169,13 @@ int yyerror (char *msg);
 void error (char *format, ...)
 {
     va_list ap;
-    char buffer[2000];
+    static char buffer[2000];
     
     va_start (ap, format);
     vsprintf (buffer, format, ap);
     va_end (ap);
 
-    as_bad (buffer);
+    as_bad ("%s", buffer);
 }
 
 int
@@ -265,6 +264,29 @@ check_multiply_halfregs (Macfunc *aa, Macfunc *ab)
 }
 
 
+/* Check mac option.  */
+
+static int
+check_macfunc_option (Macfunc *a, Opt_mode *opt)
+{
+  /* Default option is always valid.  */
+  if (opt->mod == 0)
+    return 0;
+
+  if ((a->w == 1 && a->P == 1
+       && opt->mod != M_FU && opt->mod != M_IS && opt->mod != M_IU
+       && opt->mod != M_S2RND && opt->mod != M_ISS2)
+      || (a->w == 1 && a->P == 0
+         && opt->mod != M_FU && opt->mod != M_IS && opt->mod != M_IU
+         && opt->mod != M_T && opt->mod != M_TFU && opt->mod != M_S2RND
+         && opt->mod != M_ISS2 && opt->mod != M_IH)
+      || (a->w == 0 && a->P == 0
+         && opt->mod != M_FU && opt->mod != M_IS && opt->mod != M_W32))
+    return -1;
+
+  return 0;
+}
+
 /* Check (vector) mac funcs and ops.  */
 
 static int
@@ -275,6 +297,11 @@ check_macfuncs (Macfunc *aa, Opt_mode *opa,
   Macfunc mtmp;
   Opt_mode otmp;
 
+  /* The option mode should be put at the end of the second instruction
+     of the vector except M, which should follow MAC1 instruction.  */
+  if (opa->mod != 0)
+    return yyerror ("Bad opt mode");
+
   /* If a0macfunc comes before a1macfunc, swap them.  */
        
   if (aa->n == 0)
@@ -292,15 +319,14 @@ check_macfuncs (Macfunc *aa, Opt_mode *opa,
     {
       if (opb->MM != 0)
        return yyerror ("(M) not allowed with A0MAC");
-      if (opa->mod != 0)
-       return yyerror ("Bad opt mode");
       if (ab->n != 0)
        return yyerror ("Vector AxMACs can't be same");
     }
 
-  /*  If both ops are != 3, we have multiply_halfregs in both
+  /*  If both ops are one of 0, 1, or 2, we have multiply_halfregs in both
   assignment_or_macfuncs.  */
-  if (aa->op == ab->op && aa->op != 3)
+  if ((aa->op == 0 || aa->op == 1 || aa->op == 2)
+      && (ab->op == 0 || ab->op == 1 || ab->op == 2))
     {
       if (check_multiply_halfregs (aa, ab) < 0)
        return -1;
@@ -321,20 +347,18 @@ check_macfuncs (Macfunc *aa, Opt_mode *opa,
       if (aa->w && (aa->dst.regno - ab->dst.regno != 1))
        return yyerror ("Destination Dregs must differ by one");
     }
-  /* We assign to full regs, thus obey even/odd rules.  */
-  else if ((aa->w && aa->P && IS_EVEN (aa->dst)) 
-          || (ab->w && ab->P && !IS_EVEN (ab->dst)))
-    return yyerror ("Even/Odd register assignment mismatch");
-  /* We assign to half regs, thus obey hi/low rules.  */
-  else if ( (aa->w && !aa->P && !IS_H (aa->dst)) 
-           || (ab->w && !aa->P && IS_H (ab->dst)))
-    return yyerror ("High/Low register assignment mismatch");
+
+  /* Make sure mod flags get ORed, too.  */
+  opb->mod |= opa->mod;
+
+  /* Check option.  */
+  if (check_macfunc_option (aa, opb) < 0
+      && check_macfunc_option (ab, opb) < 0)
+    return yyerror ("bad option");
 
   /* Make sure first macfunc has got both P flags ORed.  */
   aa->P |= ab->P;
 
-  /* Make sure mod flags get ORed, too.  */
-  opb->mod |= opa->mod;
   return 0;    
 }
 
@@ -361,6 +385,28 @@ is_group2 (INSTR_T x)
   return 0;
 }
 
+static INSTR_T
+gen_multi_instr_1 (INSTR_T dsp32, INSTR_T dsp16_grp1, INSTR_T dsp16_grp2)
+{
+  int mask1 = dsp32 ? insn_regmask (dsp32->value, dsp32->next->value) : 0;
+  int mask2 = dsp16_grp1 ? insn_regmask (dsp16_grp1->value, 0) : 0;
+  int mask3 = dsp16_grp2 ? insn_regmask (dsp16_grp2->value, 0) : 0;
+
+  if ((mask1 & mask2) || (mask1 & mask3) || (mask2 & mask3))
+    yyerror ("resource conflict in multi-issue instruction");
+
+  /* Anomaly 05000074 */
+  if (ENABLE_AC_05000074
+      && (dsp32->value & 0xf780) == 0xc680
+      && ((dsp16_grp1->value & 0xfe40) == 0x9240
+         || (dsp16_grp1->value & 0xfe08) == 0xba08
+         || (dsp16_grp1->value & 0xfc00) == 0xbc00))
+    yyerror ("anomaly 05000074 - Multi-Issue Instruction with \
+dsp32shiftimm in slot1 and P-reg Store in slot2 Not Supported");
+
+  return bfin_gen_multi_instr (dsp32, dsp16_grp1, dsp16_grp2);
+}
+
 %}
 
 %union {
@@ -584,27 +630,27 @@ asm: asm_1 SEMICOLON
          if (($1->value & 0xf800) == 0xc000)
            {
              if (is_group1 ($3) && is_group2 ($5))
-               $$ = bfin_gen_multi_instr ($1, $3, $5);
+               $$ = gen_multi_instr_1 ($1, $3, $5);
              else if (is_group2 ($3) && is_group1 ($5))
-               $$ = bfin_gen_multi_instr ($1, $5, $3);
+               $$ = gen_multi_instr_1 ($1, $5, $3);
              else
                return yyerror ("Wrong 16 bit instructions groups, slot 2 and slot 3 must be 16-bit instrution group");
            }
          else if (($3->value & 0xf800) == 0xc000)
            {
              if (is_group1 ($1) && is_group2 ($5))
-               $$ = bfin_gen_multi_instr ($3, $1, $5);
+               $$ = gen_multi_instr_1 ($3, $1, $5);
              else if (is_group2 ($1) && is_group1 ($5))
-               $$ = bfin_gen_multi_instr ($3, $5, $1);
+               $$ = gen_multi_instr_1 ($3, $5, $1);
              else
                return yyerror ("Wrong 16 bit instructions groups, slot 1 and slot 3 must be 16-bit instrution group");
            }
          else if (($5->value & 0xf800) == 0xc000)
            {
              if (is_group1 ($1) && is_group2 ($3))
-               $$ = bfin_gen_multi_instr ($5, $1, $3);
+               $$ = gen_multi_instr_1 ($5, $1, $3);
              else if (is_group2 ($1) && is_group1 ($3))
-               $$ = bfin_gen_multi_instr ($5, $3, $1);
+               $$ = gen_multi_instr_1 ($5, $3, $1);
              else
                return yyerror ("Wrong 16 bit instructions groups, slot 1 and slot 2 must be 16-bit instrution group");
            }
@@ -617,25 +663,25 @@ asm: asm_1 SEMICOLON
          if (($1->value & 0xf800) == 0xc000)
            {
              if (is_group1 ($3))
-               $$ = bfin_gen_multi_instr ($1, $3, 0);
+               $$ = gen_multi_instr_1 ($1, $3, 0);
              else if (is_group2 ($3))
-               $$ = bfin_gen_multi_instr ($1, 0, $3);
+               $$ = gen_multi_instr_1 ($1, 0, $3);
              else
                return yyerror ("Wrong 16 bit instructions groups, slot 2 must be the 16-bit instruction group");
            }
          else if (($3->value & 0xf800) == 0xc000)
            {
              if (is_group1 ($1))
-               $$ = bfin_gen_multi_instr ($3, $1, 0);
+               $$ = gen_multi_instr_1 ($3, $1, 0);
              else if (is_group2 ($1))
-               $$ = bfin_gen_multi_instr ($3, 0, $1);
+               $$ = gen_multi_instr_1 ($3, 0, $1);
              else
                return yyerror ("Wrong 16 bit instructions groups, slot 1 must be the 16-bit instruction group");
            }
          else if (is_group1 ($1) && is_group2 ($3))
-             $$ = bfin_gen_multi_instr (0, $1, $3);
+             $$ = gen_multi_instr_1 (0, $1, $3);
          else if (is_group2 ($1) && is_group1 ($3))
-           $$ = bfin_gen_multi_instr (0, $3, $1);
+           $$ = gen_multi_instr_1 (0, $3, $1);
          else
            return yyerror ("Wrong 16 bit instructions groups, slot 1 and slot 2 must be the 16-bit instruction group");
        }
@@ -660,6 +706,9 @@ asm_1:
          int w0 = 0, w1 = 0;
          int h00, h10, h01, h11;
 
+         if (check_macfunc_option (&$1, &$2) < 0)
+           return yyerror ("bad option");
+
          if ($1.n == 0)
            {
              if ($2.MM) 
@@ -1432,6 +1481,8 @@ asm_1:
              notethat ("COMPI2opD: dregs += imm7\n");
              $$ = COMPI2OPD (&$1, imm7 ($3), 1);
            }
+         else if ((IS_DREG ($1) || IS_PREG ($1)) && IS_CONST ($3))
+           return yyerror ("Immediate value out of range");
          else
            return yyerror ("Register mismatch");
        }
@@ -1552,23 +1603,23 @@ asm_1:
        }
        | CCREG ASSIGN REG_A _ASSIGN_ASSIGN REG_A
        {
-         if (!REG_SAME ($3, $5))
+         if ($3.regno == REG_A0 && $5.regno == REG_A1)
            {
              notethat ("CCflag: CC = A0 == A1\n");
              $$ = CCFLAG (0, 0, 5, 0, 0);
            }
          else
-           return yyerror ("CC register expected");
+           return yyerror ("AREGs are in bad order or same");
        }
        | CCREG ASSIGN REG_A LESS_THAN REG_A
        {
-         if (!REG_SAME ($3, $5))
+         if ($3.regno == REG_A0 && $5.regno == REG_A1)
            {
              notethat ("CCflag: CC = A0 < A1\n");
              $$ = CCFLAG (0, 0, 6, 0, 0);
            }
          else
-           return yyerror ("Register mismatch");
+           return yyerror ("AREGs are in bad order or same");
        }
        | CCREG ASSIGN REG LESS_THAN REG iu_or_nothing
        {
@@ -1597,7 +1648,9 @@ asm_1:
            {
              notethat ("CCflag: CC = dpregs == dpregs\n");
              $$ = CCFLAG (&$3, $5.regno & CODE_MASK, 0, 0, IS_PREG ($3) ? 1 : 0);
-           } 
+           }
+         else
+           return yyerror ("Compare only of same register class");
        }
        | CCREG ASSIGN REG _ASSIGN_ASSIGN expr
        {
@@ -1611,13 +1664,13 @@ asm_1:
        }
        | CCREG ASSIGN REG_A _LESS_THAN_ASSIGN REG_A
        {
-         if (!REG_SAME ($3, $5))
+         if ($3.regno == REG_A0 && $5.regno == REG_A1)
            {
              notethat ("CCflag: CC = A0 <= A1\n");
              $$ = CCFLAG (0, 0, 7, 0, 0);
            }
          else
-           return yyerror ("CC register expected");
+           return yyerror ("AREGs are in bad order or same");
        }
        | CCREG ASSIGN REG _LESS_THAN_ASSIGN REG iu_or_nothing
        {
@@ -1719,6 +1772,11 @@ asm_1:
          if (!IS_H ($1) && $4.MM)
            return yyerror ("(M) not allowed with MAC0");
 
+         if ($4.mod != 0 && $4.mod != M_FU && $4.mod != M_IS
+             && $4.mod != M_IU && $4.mod != M_T && $4.mod != M_TFU
+             && $4.mod != M_S2RND && $4.mod != M_ISS2 && $4.mod != M_IH)
+           return yyerror ("bad option.");
+
          if (IS_H ($1))
            {
              $$ = DSP32MULT (0, $4.MM, $4.mod, 1, 0,
@@ -1730,7 +1788,7 @@ asm_1:
              $$ = DSP32MULT (0, 0, $4.mod, 0, 0,
                              0, 0, IS_H ($3.s0), IS_H ($3.s1), 
                              &$1, 0, &$3.s0, &$3.s1, 1);
-               }       
+           }
        }
 
        | REG ASSIGN multiply_halfregs opt_mode 
@@ -1739,6 +1797,13 @@ asm_1:
          if (!IS_DREG ($1))
            return yyerror ("Dreg expected");
 
+         if (IS_EVEN ($1) && $4.MM)
+           return yyerror ("(M) not allowed with MAC0");
+
+         if ($4.mod != 0 && $4.mod != M_FU && $4.mod != M_IS
+             && $4.mod != M_S2RND && $4.mod != M_ISS2)
+           return yyerror ("bad option");
+
          if (!IS_EVEN ($1))
            {
              notethat ("dsp32mult: dregs = multiply_halfregs (opt_mode)\n");
@@ -1747,15 +1812,13 @@ asm_1:
                              IS_H ($3.s0), IS_H ($3.s1), 0, 0,
                              &$1, 0, &$3.s0, &$3.s1, 0);
            }
-         else if ($4.MM == 0)
+         else
            {
              notethat ("dsp32mult: dregs = multiply_halfregs opt_mode\n");
              $$ = DSP32MULT (0, 0, $4.mod, 0, 1,
                              0, 0, IS_H ($3.s0), IS_H ($3.s1), 
                              &$1,  0, &$3.s0, &$3.s1, 1);
            }
-         else
-           return yyerror ("Register or mode mismatch");
        }
 
        | HALF_REG ASSIGN multiply_halfregs opt_mode COMMA
@@ -1764,57 +1827,56 @@ asm_1:
          if (!IS_DREG ($1) || !IS_DREG ($6)) 
            return yyerror ("Dregs expected");
 
+         if (!IS_HCOMPL($1, $6))
+           return yyerror ("Dest registers mismatch");
+
          if (check_multiply_halfregs (&$3, &$8) < 0)
            return -1;
 
-         if (IS_H ($1) && !IS_H ($6))
-           {
-             notethat ("dsp32mult: dregs_hi = multiply_halfregs mxd_mod, "
-                      "dregs_lo = multiply_halfregs opt_mode\n");
-             $$ = DSP32MULT (0, $4.MM, $9.mod, 1, 0,
-                             IS_H ($3.s0), IS_H ($3.s1), IS_H ($8.s0), IS_H ($8.s1),
-                             &$1, 0, &$3.s0, &$3.s1, 1);
-           }
-         else if (!IS_H ($1) && IS_H ($6) && $4.MM == 0)
-           {
-             $$ = DSP32MULT (0, $9.MM, $9.mod, 1, 0,
-                             IS_H ($8.s0), IS_H ($8.s1), IS_H ($3.s0), IS_H ($3.s1),
-                             &$1, 0, &$3.s0, &$3.s1, 1);
-           }
+         if ((!IS_H ($1) && $4.MM)
+             || (!IS_H ($6) && $9.MM))
+           return yyerror ("(M) not allowed with MAC0");
+
+         notethat ("dsp32mult: dregs_hi = multiply_halfregs mxd_mod, "
+                   "dregs_lo = multiply_halfregs opt_mode\n");
+
+         if (IS_H ($1))
+           $$ = DSP32MULT (0, $4.MM, $9.mod, 1, 0,
+                           IS_H ($3.s0), IS_H ($3.s1), IS_H ($8.s0), IS_H ($8.s1),
+                           &$1, 0, &$3.s0, &$3.s1, 1);
          else
-           return yyerror ("Multfunc Register or mode mismatch");
+           $$ = DSP32MULT (0, $9.MM, $9.mod, 1, 0,
+                           IS_H ($8.s0), IS_H ($8.s1), IS_H ($3.s0), IS_H ($3.s1),
+                           &$1, 0, &$3.s0, &$3.s1, 1);
        }
 
-       | REG ASSIGN multiply_halfregs opt_mode COMMA REG ASSIGN multiply_halfregs opt_mode 
+       | REG ASSIGN multiply_halfregs opt_mode COMMA REG ASSIGN multiply_halfregs opt_mode
        {
          if (!IS_DREG ($1) || !IS_DREG ($6)) 
            return yyerror ("Dregs expected");
 
+         if ((IS_EVEN ($1) && $6.regno - $1.regno != 1)
+             || (IS_EVEN ($6) && $1.regno - $6.regno != 1))
+           return yyerror ("Dest registers mismatch");
+
          if (check_multiply_halfregs (&$3, &$8) < 0)
            return -1;
 
+         if ((IS_EVEN ($1) && $4.MM)
+             || (IS_EVEN ($6) && $9.MM))
+           return yyerror ("(M) not allowed with MAC0");
+
          notethat ("dsp32mult: dregs = multiply_halfregs mxd_mod, "
                   "dregs = multiply_halfregs opt_mode\n");
-         if (IS_EVEN ($1))
-           {
-             if ($6.regno - $1.regno != 1 || $4.MM != 0)
-               return yyerror ("Dest registers or mode mismatch");
 
-             /*   op1       MM      mmod  */
-             $$ = DSP32MULT (0, 0, $9.mod, 1, 1,
-                             IS_H ($8.s0), IS_H ($8.s1), IS_H ($3.s0), IS_H ($3.s1),
-                             &$1, 0, &$3.s0, &$3.s1, 1);
-             
-           }
+         if (IS_EVEN ($1))
+           $$ = DSP32MULT (0, $9.MM, $9.mod, 1, 1,
+                           IS_H ($8.s0), IS_H ($8.s1), IS_H ($3.s0), IS_H ($3.s1),
+                           &$1, 0, &$3.s0, &$3.s1, 1);
          else
-           {
-             if ($1.regno - $6.regno != 1)
-               return yyerror ("Dest registers mismatch");
-             
-             $$ = DSP32MULT (0, $9.MM, $9.mod, 1, 1,
-                             IS_H ($3.s0), IS_H ($3.s1), IS_H ($8.s0), IS_H ($8.s1),
-                             &$1, 0, &$3.s0, &$3.s1, 1);
-           }
+           $$ = DSP32MULT (0, $4.MM, $9.mod, 1, 1,
+                           IS_H ($3.s0), IS_H ($3.s1), IS_H ($8.s0), IS_H ($8.s1),
+                           &$1, 0, &$3.s0, &$3.s1, 1);
        }
 
 \f
@@ -1892,22 +1954,20 @@ asm_1:
          else
            return yyerror ("Bad shift value or register");
        }
-       | HALF_REG ASSIGN HALF_REG LESS_LESS expr
-       {
-         if (IS_UIMM ($5, 4))
-           {
-             notethat ("dsp32shiftimm: dregs_half = dregs_half << uimm4\n");
-             $$ = DSP32SHIFTIMM (0x0, &$1, imm5 ($5), &$3, 2, HL2 ($1, $3));
-           }
-         else
-           return yyerror ("Bad shift value");
-       }
        | HALF_REG ASSIGN HALF_REG LESS_LESS expr smod 
        {
          if (IS_UIMM ($5, 4))
            {
-             notethat ("dsp32shiftimm: dregs_half = dregs_half << uimm4\n");
-             $$ = DSP32SHIFTIMM (0x0, &$1, imm5 ($5), &$3, $6.s0, HL2 ($1, $3));
+             if ($6.s0)
+               {
+                 notethat ("dsp32shiftimm: dregs_half = dregs_half << uimm4 (S)\n");
+                 $$ = DSP32SHIFTIMM (0x0, &$1, imm5 ($5), &$3, $6.s0, HL2 ($1, $3));
+               }
+             else
+               {
+                 notethat ("dsp32shiftimm: dregs_half = dregs_half << uimm4\n");
+                 $$ = DSP32SHIFTIMM (0x0, &$1, imm5 ($5), &$3, 2, HL2 ($1, $3));
+               }
            }
          else
            return yyerror ("Bad shift value");
@@ -3165,6 +3225,11 @@ asm_1:
          if (!IS_DREG ($1) && !ispreg)
            return yyerror ("Bad destination register for LOAD");
 
+         if (tmp->type == Expr_Node_Reloc
+             && strcmp (tmp->value.s_value,
+                        "_current_shared_library_p5_offset_") != 0)
+           return yyerror ("Plain symbol used as offset");
+
          if ($5.r0)
            tmp = unary (Expr_Op_Type_NEG, tmp);
 
@@ -3223,16 +3288,6 @@ asm_1:
        }
 
 
-
-/* Expression Assignment.  */
-
-       | expr ASSIGN expr
-       {
-         bfin_equals ($1);
-         $$ = 0;
-       }
-
-
 /*  PushPopMultiple.  */
        | reg_with_predec ASSIGN LPAREN REG COLON expr COMMA REG COLON expr RPAREN
        {
@@ -3971,6 +4026,11 @@ a_plusassign:
 assign_macfunc:
        REG ASSIGN REG_A
        {
+         if (IS_A1 ($3) && IS_EVEN ($1))
+           return yyerror ("Cannot move A1 to even register");
+         else if (!IS_A1 ($3) && !IS_EVEN ($1))
+           return yyerror ("Cannot move A0 to odd register");
+
          $$.w = 1;
           $$.P = 1;
           $$.n = IS_A1 ($3);
@@ -3978,11 +4038,6 @@ assign_macfunc:
           $$.dst = $1;
          $$.s0.regno = 0;
           $$.s1.regno = 0;
-
-         if (IS_A1 ($3) && IS_EVEN ($1))
-           return yyerror ("Cannot move A1 to even register");
-         else if (!IS_A1 ($3) && !IS_EVEN ($1))
-           return yyerror ("Cannot move A0 to odd register");
        }
        | a_macfunc
        {
@@ -3992,6 +4047,11 @@ assign_macfunc:
        }
        | REG ASSIGN LPAREN a_macfunc RPAREN
        {
+         if ($4.n && IS_EVEN ($1))
+           return yyerror ("Cannot move A1 to even register");
+         else if (!$4.n && !IS_EVEN ($1))
+           return yyerror ("Cannot move A0 to odd register");
+
          $$ = $4;
          $$.w = 1;
           $$.P = 1;
@@ -4000,6 +4060,11 @@ assign_macfunc:
 
        | HALF_REG ASSIGN LPAREN a_macfunc RPAREN
        {
+         if ($4.n && !IS_H ($1))
+           return yyerror ("Cannot move A1 to low half of register");
+         else if (!$4.n && IS_H ($1))
+           return yyerror ("Cannot move A0 to high half of register");
+
          $$ = $4;
          $$.w = 1;
          $$.P = 0;
@@ -4008,6 +4073,11 @@ assign_macfunc:
 
        | HALF_REG ASSIGN REG_A
        {
+         if (IS_A1 ($3) && !IS_H ($1))
+           return yyerror ("Cannot move A1 to low half of register");
+         else if (!IS_A1 ($3) && IS_H ($1))
+           return yyerror ("Cannot move A0 to high half of register");
+
          $$.w = 1;
          $$.P = 0;
          $$.n = IS_A1 ($3);
@@ -4015,11 +4085,6 @@ assign_macfunc:
           $$.dst = $1;
          $$.s0.regno = 0;
           $$.s1.regno = 0;
-
-         if (IS_A1 ($3) && !IS_H ($1))
-           return yyerror ("Cannot move A1 to low half of register");
-         else if (!IS_A1 ($3) && IS_H ($1))
-           return yyerror ("Cannot move A0 to high half of register");
        }
        ;
 
@@ -4280,6 +4345,8 @@ value_match (Expr_Node *expr, int sz, int sign, int mul, int issigned)
 static Expr_Node *
 binary (Expr_Op_Type op, Expr_Node *x, Expr_Node *y)
 {
+  Expr_Node_Value val;
+
   if (x->type == Expr_Node_Constant && y->type == Expr_Node_Constant)
     {
       switch (op)
@@ -4325,17 +4392,36 @@ binary (Expr_Op_Type op, Expr_Node *x, Expr_Node *y)
          break;
 
        default:
-         error ("%s:%d: Internal compiler error\n", __FILE__, __LINE__); 
+         error ("%s:%d: Internal assembler error\n", __FILE__, __LINE__);
        }
       return x;
     }
-  else
+  /* Canonicalize order to EXPR OP CONSTANT.  */
+  if (x->type == Expr_Node_Constant)
+    {
+      Expr_Node *t = x;
+      x = y;
+      y = t;
+    }
+  /* Canonicalize subtraction of const to addition of negated const.  */
+  if (op == Expr_Op_Type_Sub && y->type == Expr_Node_Constant)
     {
-    /* Create a new expression structure.  */
-    Expr_Node_Value val;
-    val.op_value = op;
-    return Expr_Node_Create (Expr_Node_Binop, val, x, y);
-  }
+      op = Expr_Op_Type_Add;
+      y->value.i_value = -y->value.i_value;
+    }
+  if (y->type == Expr_Node_Constant && x->type == Expr_Node_Binop
+      && x->Right_Child->type == Expr_Node_Constant)
+    {
+      if (op == x->value.op_value && x->value.op_value == Expr_Op_Type_Add)
+       {
+         x->Right_Child->value.i_value += y->value.i_value;
+         return x;
+       }
+    }
+
+  /* Create a new expression structure.  */
+  val.op_value = op;
+  return Expr_Node_Create (Expr_Node_Binop, val, x, y);
 }
 
 static Expr_Node *
@@ -4352,7 +4438,7 @@ unary (Expr_Op_Type op, Expr_Node *x)
          x->value.i_value = ~x->value.i_value;
          break;
        default:
-         error ("%s:%d: Internal compiler error\n", __FILE__, __LINE__); 
+         error ("%s:%d: Internal assembler error\n", __FILE__, __LINE__);
        }
       return x;
     }
This page took 0.034044 seconds and 4 git commands to generate.