1 /*
2    Copyright (C) 2021-2024 Free Software Foundation, Inc.
3 
4    This file is part of GAS, the GNU Assembler.
5 
6    GAS is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3, or (at your option)
9    any later version.
10 
11    GAS is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program; see the file COPYING3.  If not,
18    see <http://www.gnu.org/licenses/>.  */
19 %{
20 #include "as.h"
21 #include "loongarch-lex.h"
22 #include "loongarch-parse.h"
yyerror(const char * s ATTRIBUTE_UNUSED)23 static void yyerror (const char *s ATTRIBUTE_UNUSED)
24 {
25 };
26 int yylex (void);
27 
28 
29 static struct reloc_info *top, *end;
30 
31 static expressionS const_0 =
32 {
33   .X_op = O_constant,
34   .X_add_number = 0
35 };
36 
37 static int
is_const(struct reloc_info * info)38 is_const (struct reloc_info *info)
39 {
40   return (info->type == BFD_RELOC_LARCH_SOP_PUSH_ABSOLUTE
41             && info->value.X_op == O_constant);
42 }
43 
44 int
loongarch_parse_expr(const char * expr,struct reloc_info * reloc_stack_top,size_t max_reloc_num,size_t * reloc_num,offsetT * imm)45 loongarch_parse_expr (const char *expr,
46                           struct reloc_info *reloc_stack_top,
47                           size_t max_reloc_num,
48                           size_t *reloc_num,
49                           offsetT *imm)
50 {
51   int ret;
52   struct yy_buffer_state *buffstate;
53   top = reloc_stack_top;
54   end = top + max_reloc_num;
55   buffstate = yy_scan_string (expr);
56   ret = yyparse ();
57 
58   if (ret == 0)
59     {
60       if (is_const (top - 1))
61           *imm = (--top)->value.X_add_number;
62       else
63           *imm = 0;
64       *reloc_num = top - reloc_stack_top;
65     }
66   yy_delete_buffer (buffstate);
67 
68   return ret;
69 }
70 
71 static void
emit_const(offsetT imm)72 emit_const (offsetT imm)
73 {
74   if (end <= top)
75     as_fatal (_("expr too huge"));
76   top->type = BFD_RELOC_LARCH_SOP_PUSH_ABSOLUTE;
77   top->value.X_op = O_constant;
78   top->value.X_add_number = imm;
79   top++;
80 }
81 
82 static const char *
my_getExpression(expressionS * ep,const char * str)83 my_getExpression (expressionS *ep, const char *str)
84 {
85   char *save_in, *ret;
86 
87   if (*str == ':')
88     {
89       unsigned long j;
90       char *str_1 = (char *) str;
91       j = strtol (str_1, &str_1, 10);
92       get_internal_label (ep, j, *str_1 == 'f');
93       return NULL;
94     }
95   save_in = input_line_pointer;
96   input_line_pointer = (char *)str;
97   expression (ep);
98   ret = input_line_pointer;
99   input_line_pointer = save_in;
100   return ret;
101 }
102 
103 static void
emit_const_var(const char * op)104 emit_const_var (const char *op)
105 {
106   expressionS ep;
107 
108   if (end <= top)
109     as_fatal (_("expr too huge"));
110 
111   my_getExpression (&ep, op);
112 
113   if (ep.X_op != O_constant)
114     as_bad ("illegal operand: %s", op);
115 
116   top->value.X_op = O_constant;
117   top->value.X_add_number = ep.X_add_number;
118   top->type = BFD_RELOC_LARCH_SOP_PUSH_ABSOLUTE;
119   top++;
120 }
121 
122 static void
reloc(const char * op_c_str,const char * id_c_str,offsetT addend)123 reloc (const char *op_c_str, const char *id_c_str, offsetT addend)
124 {
125   expressionS id_sym_expr;
126   bfd_reloc_code_real_type btype;
127 
128   if (end <= top)
129     as_fatal (_("expr too huge"));
130 
131   /* For compatible old asm code.  */
132   if (0 == strcmp (op_c_str, "plt"))
133     btype = BFD_RELOC_LARCH_B26;
134   else
135     {
136       btype = loongarch_larch_reloc_name_lookup (NULL, op_c_str);
137       if (btype == BFD_RELOC_NONE)
138           as_fatal (_("unsupported modifier %s"), op_c_str);
139     }
140 
141   if (id_c_str)
142   {
143     my_getExpression (&id_sym_expr, id_c_str);
144     id_sym_expr.X_add_number += addend;
145   }
146   else
147   {
148     id_sym_expr.X_op = O_constant;
149     id_sym_expr.X_add_number = addend;
150   }
151 
152   top->value = id_sym_expr;
153   top->type = btype;
154   top++;
155 }
156 
157 static void
emit_unary(char op)158 emit_unary (char op)
159 {
160   struct reloc_info *s_top = top - 1;
161   if (is_const (s_top))
162     {
163       offsetT opr = s_top->value.X_add_number;
164       switch (op)
165           {
166           case '+':
167             break;
168           case '-':
169             opr = -opr;
170             break;
171           case '~':
172             opr = ~opr;
173             break;
174           case '!':
175             opr = !opr;
176             break;
177           default:
178             abort ();
179           }
180       s_top->value.X_add_number = opr;
181     }
182   else
183     {
184       if (end <= top)
185           as_fatal (_("expr too huge"));
186       switch (op)
187           {
188           case '!':
189             top->type = BFD_RELOC_LARCH_SOP_NOT;
190             break;
191           default:
192             abort ();
193           }
194       top->value = const_0;
195       top++;
196     }
197 }
198 
199 static void
emit_bin(int op)200 emit_bin (int op)
201 {
202   struct reloc_info *last_1st = top - 1, *last_2nd = top - 2;
203   if (is_const (last_1st) && is_const (last_2nd))
204     {
205       offsetT opr1 = last_2nd->value.X_add_number;
206       offsetT opr2 = last_1st->value.X_add_number;
207       switch (op)
208           {
209           case '*':
210             opr1 = opr1 * opr2;
211             break;
212           case '/':
213             opr1 = opr1 / opr2;
214             break;
215           case '%':
216             opr1 = opr1 % opr2;
217             break;
218           case '+':
219             opr1 = opr1 + opr2;
220             break;
221           case '-':
222             opr1 = opr1 - opr2;
223             break;
224           case LEFT_OP:
225             opr1 = opr1 << opr2;
226             break;
227           case RIGHT_OP:
228             /* Algorithm right shift.  */
229             opr1 = (offsetT)opr1 >> (offsetT)opr2;
230             break;
231           case '<':
232             opr1 = opr1 < opr2;
233             break;
234           case '>':
235             opr1 = opr1 > opr2;
236             break;
237           case LE_OP:
238             opr1 = opr1 <= opr2;
239             break;
240           case GE_OP:
241             opr1 = opr1 >= opr2;
242             break;
243           case EQ_OP:
244             opr1 = opr1 == opr2;
245             break;
246           case NE_OP:
247             opr1 = opr1 != opr2;
248             break;
249           case '&':
250             opr1 = opr1 & opr2;
251             break;
252           case '^':
253             opr1 = opr1 ^ opr2;
254             break;
255           case '|':
256             opr1 = opr1 | opr2;
257             break;
258           case AND_OP:
259             opr1 = opr1 && opr2;
260             break;
261           case OR_OP:
262             opr1 = opr1 || opr2;
263             break;
264           default:
265             abort ();
266           }
267       last_2nd->value.X_add_number = opr1;
268       last_1st->type = 0;
269       top--;
270     }
271   else
272     {
273       if (end <= top)
274           as_fatal (_("expr too huge"));
275       switch (op)
276           {
277           case '+':
278             top->type = BFD_RELOC_LARCH_SOP_ADD;
279             break;
280           case '-':
281             top->type = BFD_RELOC_LARCH_SOP_SUB;
282             break;
283           case LEFT_OP:
284             top->type = BFD_RELOC_LARCH_SOP_SL;
285             break;
286           case RIGHT_OP:
287             top->type = BFD_RELOC_LARCH_SOP_SR;
288             break;
289           case '&':
290             top->type = BFD_RELOC_LARCH_SOP_AND;
291             break;
292           default:
293             abort ();
294           }
295       top->value = const_0;
296       top++;
297     }
298 }
299 
300 static void
emit_if_else(void)301 emit_if_else (void)
302 {
303   struct reloc_info *last_1st = top - 1;
304   struct reloc_info *last_2nd = top - 2;
305   struct reloc_info *last_3rd = top - 3;
306   if (is_const (last_1st) && is_const (last_2nd) && is_const (last_3rd))
307     {
308       offsetT opr1 = last_3rd->value.X_add_number;
309       offsetT opr2 = last_2nd->value.X_add_number;
310       offsetT opr3 = last_1st->value.X_add_number;
311       opr1 = opr1 ? opr2 : opr3;
312       last_3rd->value.X_add_number = opr1;
313       last_2nd->type = 0;
314       last_1st->type = 0;
315       top -= 2;
316     }
317   else
318     {
319       if (end <= top)
320           as_fatal (_("expr too huge"));
321       top->type = BFD_RELOC_LARCH_SOP_IF_ELSE;
322       top->value = const_0;
323       top++;
324     }
325 }
326 
327 %}
328 
329 %union {
330 char *c_str;
331 offsetT imm;
332 }
333 
334 %token <imm> INTEGER
335 %token <c_str> IDENTIFIER
336 %type <imm> addend
337 
338 %token LEFT_OP RIGHT_OP LE_OP GE_OP EQ_OP NE_OP AND_OP OR_OP
339 %start expression
340 %%
341 
342 primary_expression
343           : INTEGER {emit_const ($1);}
344           | IDENTIFIER {emit_const_var ($1);}
345           | '(' expression ')'
346           | '%' IDENTIFIER '(' IDENTIFIER addend ')' {reloc ($2, $4, $5); free ($2); free ($4);}
347           | '%' IDENTIFIER '(' INTEGER addend ')' {reloc ($2, NULL, $4 + $5); free ($2);}
348           ;
349 
350 addend
351           : addend '-' INTEGER {$$ -= $3;}
352           | addend '+' INTEGER {$$ += $3;}
353           | {$$ = 0;}
354           ;
355 
356 unary_expression
357           : primary_expression
358           | '+' unary_expression {emit_unary ('+');}
359           | '-' unary_expression {emit_unary ('-');}
360           | '~' unary_expression {emit_unary ('~');}
361           | '!' unary_expression {emit_unary ('!');}
362           ;
363 
364 multiplicative_expression
365           : unary_expression
366           | multiplicative_expression '*' unary_expression {emit_bin ('*');}
367           | multiplicative_expression '/' unary_expression {emit_bin ('/');}
368           | multiplicative_expression '%' unary_expression {emit_bin ('%');}
369           ;
370 
371 additive_expression
372           : multiplicative_expression
373           | additive_expression '+' multiplicative_expression {emit_bin ('+');}
374           | additive_expression '-' multiplicative_expression {emit_bin ('-');}
375           ;
376 
377 shift_expression
378           : additive_expression
379           | shift_expression LEFT_OP additive_expression {emit_bin (LEFT_OP);}
380           | shift_expression RIGHT_OP additive_expression {emit_bin (RIGHT_OP);}
381           ;
382 
383 relational_expression
384           : shift_expression
385           | relational_expression '<' shift_expression {emit_bin ('<');}
386           | relational_expression '>' shift_expression {emit_bin ('>');}
387           | relational_expression LE_OP shift_expression {emit_bin (LE_OP);}
388           | relational_expression GE_OP shift_expression {emit_bin (GE_OP);}
389           ;
390 
391 equality_expression
392           : relational_expression
393           | equality_expression EQ_OP relational_expression {emit_bin (EQ_OP);}
394           | equality_expression NE_OP relational_expression {emit_bin (NE_OP);}
395           ;
396 
397 and_expression
398           : equality_expression
399           | and_expression '&' equality_expression {emit_bin ('&');}
400           ;
401 
402 exclusive_or_expression
403           : and_expression
404           | exclusive_or_expression '^' and_expression {emit_bin ('^');}
405           ;
406 
407 inclusive_or_expression
408           : exclusive_or_expression
409           | inclusive_or_expression '|' exclusive_or_expression {emit_bin ('|');}
410           ;
411 
412 logical_and_expression
413           : inclusive_or_expression
414           | logical_and_expression AND_OP inclusive_or_expression {emit_bin (AND_OP);}
415           ;
416 
417 logical_or_expression
418           : logical_and_expression
419           | logical_or_expression OR_OP logical_and_expression {emit_bin (OR_OP);}
420           ;
421 
422 conditional_expression
423           : logical_or_expression
424           | logical_or_expression '?' expression ':' conditional_expression {emit_if_else ();}
425           ;
426 
427 expression
428           : conditional_expression
429           ;
430 %%
431 
432