mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-27 04:52:05 +08:00
a2c5833233
The result of running etc/update-copyright.py --this-year, fixing all the files whose mode is changed by the script, plus a build with --enable-maintainer-mode --enable-cgen-maint=yes, then checking out */po/*.pot which we don't update frequently. The copy of cgen was with commit d1dd5fcc38ead reverted as that commit breaks building of bfp opcodes files.
442 lines
9.4 KiB
Plaintext
442 lines
9.4 KiB
Plaintext
/*
|
|
Copyright (C) 2021-2022 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 3, or (at your option)
|
|
any later version.
|
|
|
|
GAS is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; see the file COPYING3. If not,
|
|
see <http://www.gnu.org/licenses/>. */
|
|
%{
|
|
#include "as.h"
|
|
#include "loongarch-lex.h"
|
|
#include "loongarch-parse.h"
|
|
static void yyerror (const char *s ATTRIBUTE_UNUSED)
|
|
{
|
|
};
|
|
int yylex (void);
|
|
|
|
|
|
static struct reloc_info *top, *end;
|
|
|
|
static expressionS const_0 =
|
|
{
|
|
.X_op = O_constant,
|
|
.X_add_number = 0
|
|
};
|
|
|
|
static int
|
|
is_const (struct reloc_info *info)
|
|
{
|
|
return (info->type == BFD_RELOC_LARCH_SOP_PUSH_ABSOLUTE
|
|
&& info->value.X_op == O_constant);
|
|
}
|
|
|
|
int
|
|
loongarch_parse_expr (const char *expr,
|
|
struct reloc_info *reloc_stack_top,
|
|
size_t max_reloc_num,
|
|
size_t *reloc_num,
|
|
offsetT *imm)
|
|
{
|
|
int ret;
|
|
struct yy_buffer_state *buffstate;
|
|
top = reloc_stack_top;
|
|
end = top + max_reloc_num;
|
|
buffstate = yy_scan_string (expr);
|
|
ret = yyparse ();
|
|
|
|
if (ret == 0)
|
|
{
|
|
if (is_const (top - 1))
|
|
*imm = (--top)->value.X_add_number;
|
|
else
|
|
*imm = 0;
|
|
*reloc_num = top - reloc_stack_top;
|
|
}
|
|
yy_delete_buffer (buffstate);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void
|
|
emit_const (offsetT imm)
|
|
{
|
|
if (end <= top)
|
|
as_fatal (_("expr too huge"));
|
|
top->type = BFD_RELOC_LARCH_SOP_PUSH_ABSOLUTE;
|
|
top->value.X_op = O_constant;
|
|
top->value.X_add_number = imm;
|
|
top++;
|
|
}
|
|
|
|
static const char *
|
|
my_getExpression (expressionS *ep, const char *str)
|
|
{
|
|
char *save_in, *ret;
|
|
if (*str == ':')
|
|
{
|
|
unsigned long j;
|
|
char *str_1 = (char *) str;
|
|
str_1++;
|
|
j = strtol (str_1, &str_1, 10);
|
|
get_internal_label (ep, j, *str_1 == 'f');
|
|
return NULL;
|
|
}
|
|
save_in = input_line_pointer;
|
|
input_line_pointer = (char *)str;
|
|
expression (ep);
|
|
ret = input_line_pointer;
|
|
input_line_pointer = save_in;
|
|
return ret;
|
|
}
|
|
|
|
static void
|
|
reloc (const char *op_c_str, const char *id_c_str, offsetT addend)
|
|
{
|
|
expressionS id_sym_expr;
|
|
|
|
if (end <= top)
|
|
as_fatal (_("expr too huge"));
|
|
|
|
if (id_c_str)
|
|
{
|
|
my_getExpression (&id_sym_expr, id_c_str);
|
|
id_sym_expr.X_add_number += addend;
|
|
}
|
|
else
|
|
{
|
|
id_sym_expr.X_op = O_constant;
|
|
id_sym_expr.X_add_number = addend;
|
|
}
|
|
|
|
if (strcmp (op_c_str, "abs") == 0)
|
|
{
|
|
top->value = id_sym_expr;
|
|
top->type = BFD_RELOC_LARCH_SOP_PUSH_ABSOLUTE;
|
|
top++;
|
|
}
|
|
else if (strcmp (op_c_str, "pcrel") == 0)
|
|
{
|
|
top->value = id_sym_expr;
|
|
top->type = BFD_RELOC_LARCH_SOP_PUSH_PCREL;
|
|
top++;
|
|
}
|
|
else if (strcmp (op_c_str, "gprel") == 0)
|
|
{
|
|
top->value = id_sym_expr;
|
|
top->type = BFD_RELOC_LARCH_SOP_PUSH_GPREL;
|
|
top++;
|
|
}
|
|
else if (strcmp (op_c_str, "tprel") == 0)
|
|
{
|
|
top->value = id_sym_expr;
|
|
top->type = BFD_RELOC_LARCH_SOP_PUSH_TLS_TPREL;
|
|
top++;
|
|
}
|
|
else if (strcmp (op_c_str, "tlsgot") == 0)
|
|
{
|
|
top->value = id_sym_expr;
|
|
top->type = BFD_RELOC_LARCH_SOP_PUSH_TLS_GOT;
|
|
top++;
|
|
}
|
|
else if (strcmp (op_c_str, "tlsgd") == 0)
|
|
{
|
|
top->value = id_sym_expr;
|
|
top->type = BFD_RELOC_LARCH_SOP_PUSH_TLS_GD;
|
|
top++;
|
|
}
|
|
else if (strcmp (op_c_str, "plt") == 0)
|
|
{
|
|
top->value = id_sym_expr;
|
|
top->type = BFD_RELOC_LARCH_SOP_PUSH_PLT_PCREL;
|
|
top++;
|
|
}
|
|
else
|
|
as_fatal (_("unknown reloc hint: %s"), op_c_str);
|
|
}
|
|
|
|
static void
|
|
emit_unary (char op)
|
|
{
|
|
struct reloc_info *s_top = top - 1;
|
|
if (is_const (s_top))
|
|
{
|
|
offsetT opr = s_top->value.X_add_number;
|
|
switch (op)
|
|
{
|
|
case '+':
|
|
break;
|
|
case '-':
|
|
opr = -opr;
|
|
break;
|
|
case '~':
|
|
opr = ~opr;
|
|
break;
|
|
case '!':
|
|
opr = !opr;
|
|
break;
|
|
default:
|
|
abort ();
|
|
}
|
|
s_top->value.X_add_number = opr;
|
|
}
|
|
else
|
|
{
|
|
if (end <= top)
|
|
as_fatal (_("expr too huge"));
|
|
switch (op)
|
|
{
|
|
case '!':
|
|
top->type = BFD_RELOC_LARCH_SOP_NOT;
|
|
break;
|
|
default:
|
|
abort ();
|
|
}
|
|
top->value = const_0;
|
|
top++;
|
|
}
|
|
}
|
|
|
|
static void
|
|
emit_bin (int op)
|
|
{
|
|
struct reloc_info *last_1st = top - 1, *last_2nd = top - 2;
|
|
if (is_const (last_1st) && is_const (last_2nd))
|
|
{
|
|
offsetT opr1 = last_2nd->value.X_add_number;
|
|
offsetT opr2 = last_1st->value.X_add_number;
|
|
switch (op)
|
|
{
|
|
case '*':
|
|
opr1 = opr1 * opr2;
|
|
break;
|
|
case '/':
|
|
opr1 = opr1 / opr2;
|
|
break;
|
|
case '%':
|
|
opr1 = opr1 % opr2;
|
|
break;
|
|
case '+':
|
|
opr1 = opr1 + opr2;
|
|
break;
|
|
case '-':
|
|
opr1 = opr1 - opr2;
|
|
break;
|
|
case LEFT_OP:
|
|
opr1 = opr1 << opr2;
|
|
break;
|
|
case RIGHT_OP:
|
|
/* Algorithm right shift. */
|
|
opr1 = (offsetT)opr1 >> (offsetT)opr2;
|
|
break;
|
|
case '<':
|
|
opr1 = opr1 < opr2;
|
|
break;
|
|
case '>':
|
|
opr1 = opr1 > opr2;
|
|
break;
|
|
case LE_OP:
|
|
opr1 = opr1 <= opr2;
|
|
break;
|
|
case GE_OP:
|
|
opr1 = opr1 >= opr2;
|
|
break;
|
|
case EQ_OP:
|
|
opr1 = opr1 == opr2;
|
|
break;
|
|
case NE_OP:
|
|
opr1 = opr1 != opr2;
|
|
break;
|
|
case '&':
|
|
opr1 = opr1 & opr2;
|
|
break;
|
|
case '^':
|
|
opr1 = opr1 ^ opr2;
|
|
break;
|
|
case '|':
|
|
opr1 = opr1 | opr2;
|
|
break;
|
|
case AND_OP:
|
|
opr1 = opr1 && opr2;
|
|
break;
|
|
case OR_OP:
|
|
opr1 = opr1 || opr2;
|
|
break;
|
|
default:
|
|
abort ();
|
|
}
|
|
last_2nd->value.X_add_number = opr1;
|
|
last_1st->type = 0;
|
|
top--;
|
|
}
|
|
else
|
|
{
|
|
if (end <= top)
|
|
as_fatal (_("expr too huge"));
|
|
switch (op)
|
|
{
|
|
case '+':
|
|
top->type = BFD_RELOC_LARCH_SOP_ADD;
|
|
break;
|
|
case '-':
|
|
top->type = BFD_RELOC_LARCH_SOP_SUB;
|
|
break;
|
|
case LEFT_OP:
|
|
top->type = BFD_RELOC_LARCH_SOP_SL;
|
|
break;
|
|
case RIGHT_OP:
|
|
top->type = BFD_RELOC_LARCH_SOP_SR;
|
|
break;
|
|
case '&':
|
|
top->type = BFD_RELOC_LARCH_SOP_AND;
|
|
break;
|
|
default:
|
|
abort ();
|
|
}
|
|
top->value = const_0;
|
|
top++;
|
|
}
|
|
}
|
|
|
|
static void
|
|
emit_if_else (void)
|
|
{
|
|
struct reloc_info *last_1st = top - 1;
|
|
struct reloc_info *last_2nd = top - 2;
|
|
struct reloc_info *last_3rd = top - 3;
|
|
if (is_const (last_1st) && is_const (last_2nd) && is_const (last_3rd))
|
|
{
|
|
offsetT opr1 = last_3rd->value.X_add_number;
|
|
offsetT opr2 = last_2nd->value.X_add_number;
|
|
offsetT opr3 = last_1st->value.X_add_number;
|
|
opr1 = opr1 ? opr2 : opr3;
|
|
last_3rd->value.X_add_number = opr1;
|
|
last_2nd->type = 0;
|
|
last_1st->type = 0;
|
|
top -= 2;
|
|
}
|
|
else
|
|
{
|
|
if (end <= top)
|
|
as_fatal (_("expr too huge"));
|
|
top->type = BFD_RELOC_LARCH_SOP_IF_ELSE;
|
|
top->value = const_0;
|
|
top++;
|
|
}
|
|
}
|
|
|
|
%}
|
|
|
|
%union {
|
|
char *c_str;
|
|
offsetT imm;
|
|
}
|
|
|
|
%token <imm> INTEGER
|
|
%token <c_str> IDENTIFIER
|
|
%type <imm> addend
|
|
|
|
%token LEFT_OP RIGHT_OP LE_OP GE_OP EQ_OP NE_OP AND_OP OR_OP
|
|
%start expression
|
|
%%
|
|
|
|
primary_expression
|
|
: INTEGER {emit_const ($1);}
|
|
| '(' expression ')'
|
|
| '%' IDENTIFIER '(' IDENTIFIER addend ')' {reloc ($2, $4, $5); free ($2); free ($4);}
|
|
| '%' IDENTIFIER '(' INTEGER addend ')' {reloc ($2, NULL, $4 + $5); free ($2);}
|
|
;
|
|
|
|
addend
|
|
: addend '-' INTEGER {$$ -= $3;}
|
|
| addend '+' INTEGER {$$ += $3;}
|
|
| {$$ = 0;}
|
|
;
|
|
|
|
unary_expression
|
|
: primary_expression
|
|
| '+' unary_expression {emit_unary ('+');}
|
|
| '-' unary_expression {emit_unary ('-');}
|
|
| '~' unary_expression {emit_unary ('~');}
|
|
| '!' unary_expression {emit_unary ('!');}
|
|
;
|
|
|
|
multiplicative_expression
|
|
: unary_expression
|
|
| multiplicative_expression '*' unary_expression {emit_bin ('*');}
|
|
| multiplicative_expression '/' unary_expression {emit_bin ('/');}
|
|
| multiplicative_expression '%' unary_expression {emit_bin ('%');}
|
|
;
|
|
|
|
additive_expression
|
|
: multiplicative_expression
|
|
| additive_expression '+' multiplicative_expression {emit_bin ('+');}
|
|
| additive_expression '-' multiplicative_expression {emit_bin ('-');}
|
|
;
|
|
|
|
shift_expression
|
|
: additive_expression
|
|
| shift_expression LEFT_OP additive_expression {emit_bin (LEFT_OP);}
|
|
| shift_expression RIGHT_OP additive_expression {emit_bin (RIGHT_OP);}
|
|
;
|
|
|
|
relational_expression
|
|
: shift_expression
|
|
| relational_expression '<' shift_expression {emit_bin ('<');}
|
|
| relational_expression '>' shift_expression {emit_bin ('>');}
|
|
| relational_expression LE_OP shift_expression {emit_bin (LE_OP);}
|
|
| relational_expression GE_OP shift_expression {emit_bin (GE_OP);}
|
|
;
|
|
|
|
equality_expression
|
|
: relational_expression
|
|
| equality_expression EQ_OP relational_expression {emit_bin (EQ_OP);}
|
|
| equality_expression NE_OP relational_expression {emit_bin (NE_OP);}
|
|
;
|
|
|
|
and_expression
|
|
: equality_expression
|
|
| and_expression '&' equality_expression {emit_bin ('&');}
|
|
;
|
|
|
|
exclusive_or_expression
|
|
: and_expression
|
|
| exclusive_or_expression '^' and_expression {emit_bin ('^');}
|
|
;
|
|
|
|
inclusive_or_expression
|
|
: exclusive_or_expression
|
|
| inclusive_or_expression '|' exclusive_or_expression {emit_bin ('|');}
|
|
;
|
|
|
|
logical_and_expression
|
|
: inclusive_or_expression
|
|
| logical_and_expression AND_OP inclusive_or_expression {emit_bin (AND_OP);}
|
|
;
|
|
|
|
logical_or_expression
|
|
: logical_and_expression
|
|
| logical_or_expression OR_OP logical_and_expression {emit_bin (OR_OP);}
|
|
;
|
|
|
|
conditional_expression
|
|
: logical_or_expression
|
|
| logical_or_expression '?' expression ':' conditional_expression {emit_if_else ();}
|
|
;
|
|
|
|
expression
|
|
: conditional_expression
|
|
;
|
|
%%
|
|
|