/* bfin-parse.y ADI Blackfin parser
- Copyright 2005
+ Copyright 2005, 2006
Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
02110-1301, USA. */
%{
-#include <stdio.h>
-#include "bfin-aux.h"
-#include <stdarg.h>
+#include "as.h"
#include <obstack.h>
+#include "bfin-aux.h" // opcode generating auxiliaries
+#include "libbfd.h"
+#include "elf/common.h"
+#include "elf/bfin.h"
+
#define DSP32ALU(aopcde, HL, dst1, dst0, src0, src1, s, x, aop) \
bfin_gen_dsp32alu (HL, aopcde, aop, s, x, dst0, dst1, src0, src1)
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 < 3 && aa->op >=0
+ && ab->op < 3 && ab->op >= 0)
{
if (check_multiply_halfregs (aa, ab) < 0)
return -1;
%token STATUS_REG
%token MNOP
%token SYMBOL NUMBER
-%token GOT AT PLTPC
+%token GOT GOT17M4 FUNCDESC_GOT17M4
+%token AT PLTPC
/* Types. */
%type <instr> asm
%type <expr> got
%type <expr> got_or_expr
%type <expr> pltpc
-
+%type <value> any_gotrel GOT GOT17M4 FUNCDESC_GOT17M4
/* Precedence rules. */
%left BAR
/* 7 bit immediate value if possible.
We will check for that constant value for efficiency
If it goes to reloc, it will be 16 bit. */
- if (IS_CONST ($3) && IS_IMM ($3, 7) && (IS_DREG ($1) || IS_PREG ($1)))
+ if (IS_CONST ($3) && IS_IMM ($3, 7) && IS_DREG ($1))
+ {
+ notethat ("COMPI2opD: dregs = imm7 (x) \n");
+ $$ = COMPI2OPD (&$1, imm7 ($3), 0);
+ }
+ else if (IS_CONST ($3) && IS_IMM ($3, 7) && IS_PREG ($1))
{
- /* if the expr is a relocation, generate it. */
- if (IS_DREG ($1) && IS_IMM ($3, 7))
- {
- notethat ("COMPI2opD: dregs = imm7 (x) \n");
- $$ = COMPI2OPD (&$1, imm7 ($3), 0);
- }
- else if (IS_PREG ($1) && IS_IMM ($3, 7))
- {
- notethat ("COMPI2opP: pregs = imm7 (x)\n");
- $$ = COMPI2OPP (&$1, imm7 ($3), 0);
- }
- else
- return yyerror ("Bad register or value for assigment");
+ notethat ("COMPI2opP: pregs = imm7 (x)\n");
+ $$ = COMPI2OPP (&$1, imm7 ($3), 0);
}
else
{
+ if (IS_CONST ($3) && !IS_IMM ($3, 16))
+ return yyerror ("Immediate value out of range");
+
notethat ("LDIMMhalf: regs = luimm16 (x)\n");
/* reg, H, S, Z. */
$$ = LDIMMHALF_R5 (&$1, 0, 1, 0, $3);
{
/* (z) There is no 7 bit zero extended instruction.
If the expr is a relocation, generate it. */
+
+ if (IS_CONST ($3) && !IS_UIMM ($3, 16))
+ return yyerror ("Immediate value out of range");
+
notethat ("LDIMMhalf: regs = luimm16 (x)\n");
/* reg, H, S, Z. */
$$ = LDIMMHALF_R5 (&$1, 0, 0, 1, $3);
$$ = 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
if (!IS_DREG ($1))
return yyerror ("Dreg expected");
+ if (IS_EVEN ($1) && $4.MM)
+ return yyerror ("(M) not allowed with MAC0");
+
if (!IS_EVEN ($1))
{
notethat ("dsp32mult: dregs = multiply_halfregs (opt_mode)\n");
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
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
}
-
-/* Expression Assignment. */
-
- | expr ASSIGN expr
- {
- bfin_equals ($1);
- $$ = 0;
- }
-
-
/* PushPopMultiple. */
| reg_with_predec ASSIGN LPAREN REG COLON expr COMMA REG COLON expr RPAREN
{
}
;
-got: symbol AT GOT
+any_gotrel:
+ GOT
+ { $$ = BFD_RELOC_BFIN_GOT; }
+ | GOT17M4
+ { $$ = BFD_RELOC_BFIN_GOT17M4; }
+ | FUNCDESC_GOT17M4
+ { $$ = BFD_RELOC_BFIN_FUNCDESC_GOT17M4; }
+ ;
+
+got: symbol AT any_gotrel
{
- $$ = $1;
+ Expr_Node_Value val;
+ val.i_value = $3;
+ $$ = Expr_Node_Create (Expr_Node_GOT_Reloc, val, $1, NULL);
}
;
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)
}
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)
+ {
+ 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)
{
- /* Create a new expression structure. */
- Expr_Node_Value val;
- val.op_value = op;
- return Expr_Node_Create (Expr_Node_Binop, val, x, y);
- }
+ 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 *