xref: /netbsd-src/external/gpl3/binutils/dist/gas/config/loongarch-parse.y (revision c64d4171c6f912972428361000d29636c687d68b)
1 /*
2    Copyright (C) 2021-2022 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"
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
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
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
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 *
83 my_getExpression (expressionS *ep, const char *str)
84 {
85   char *save_in, *ret;
86   if (*str == ':')
87     {
88       unsigned long j;
89       char *str_1 = (char *) str;
90       str_1++;
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
104 reloc (const char *op_c_str, const char *id_c_str, offsetT addend)
105 {
106   expressionS id_sym_expr;
107 
108   if (end <= top)
109     as_fatal (_("expr too huge"));
110 
111   if (id_c_str)
112     {
113       my_getExpression (&id_sym_expr, id_c_str);
114       id_sym_expr.X_add_number += addend;
115     }
116   else
117     {
118       id_sym_expr.X_op = O_constant;
119       id_sym_expr.X_add_number = addend;
120     }
121 
122   if (strcmp (op_c_str, "abs") == 0)
123     {
124       top->value = id_sym_expr;
125       top->type = BFD_RELOC_LARCH_SOP_PUSH_ABSOLUTE;
126       top++;
127     }
128   else if (strcmp (op_c_str, "pcrel") == 0)
129     {
130       top->value = id_sym_expr;
131       top->type = BFD_RELOC_LARCH_SOP_PUSH_PCREL;
132       top++;
133     }
134   else if (strcmp (op_c_str, "gprel") == 0)
135     {
136       top->value = id_sym_expr;
137       top->type = BFD_RELOC_LARCH_SOP_PUSH_GPREL;
138       top++;
139     }
140   else if (strcmp (op_c_str, "tprel") == 0)
141     {
142       top->value = id_sym_expr;
143       top->type = BFD_RELOC_LARCH_SOP_PUSH_TLS_TPREL;
144       top++;
145     }
146   else if (strcmp (op_c_str, "tlsgot") == 0)
147     {
148       top->value = id_sym_expr;
149       top->type = BFD_RELOC_LARCH_SOP_PUSH_TLS_GOT;
150       top++;
151     }
152   else if (strcmp (op_c_str, "tlsgd") == 0)
153     {
154       top->value = id_sym_expr;
155       top->type = BFD_RELOC_LARCH_SOP_PUSH_TLS_GD;
156       top++;
157     }
158   else if (strcmp (op_c_str, "plt") == 0)
159     {
160       top->value = id_sym_expr;
161       top->type = BFD_RELOC_LARCH_SOP_PUSH_PLT_PCREL;
162       top++;
163     }
164   else
165     as_fatal (_("unknown reloc hint: %s"), op_c_str);
166 }
167 
168 static void
169 emit_unary (char op)
170 {
171   struct reloc_info *s_top = top - 1;
172   if (is_const (s_top))
173     {
174       offsetT opr = s_top->value.X_add_number;
175       switch (op)
176 	{
177 	case '+':
178 	  break;
179 	case '-':
180 	  opr = -opr;
181 	  break;
182 	case '~':
183 	  opr = ~opr;
184 	  break;
185 	case '!':
186 	  opr = !opr;
187 	  break;
188 	default:
189 	  abort ();
190 	}
191       s_top->value.X_add_number = opr;
192     }
193   else
194     {
195       if (end <= top)
196 	as_fatal (_("expr too huge"));
197       switch (op)
198 	{
199 	case '!':
200 	  top->type = BFD_RELOC_LARCH_SOP_NOT;
201 	  break;
202 	default:
203 	  abort ();
204 	}
205       top->value = const_0;
206       top++;
207     }
208 }
209 
210 static void
211 emit_bin (int op)
212 {
213   struct reloc_info *last_1st = top - 1, *last_2nd = top - 2;
214   if (is_const (last_1st) && is_const (last_2nd))
215     {
216       offsetT opr1 = last_2nd->value.X_add_number;
217       offsetT opr2 = last_1st->value.X_add_number;
218       switch (op)
219 	{
220 	case '*':
221 	  opr1 = opr1 * opr2;
222 	  break;
223 	case '/':
224 	  opr1 = opr1 / opr2;
225 	  break;
226 	case '%':
227 	  opr1 = opr1 % opr2;
228 	  break;
229 	case '+':
230 	  opr1 = opr1 + opr2;
231 	  break;
232 	case '-':
233 	  opr1 = opr1 - opr2;
234 	  break;
235 	case LEFT_OP:
236 	  opr1 = opr1 << opr2;
237 	  break;
238 	case RIGHT_OP:
239 	  /* Algorithm right shift.  */
240 	  opr1 = (offsetT)opr1 >> (offsetT)opr2;
241 	  break;
242 	case '<':
243 	  opr1 = opr1 < opr2;
244 	  break;
245 	case '>':
246 	  opr1 = opr1 > opr2;
247 	  break;
248 	case LE_OP:
249 	  opr1 = opr1 <= opr2;
250 	  break;
251 	case GE_OP:
252 	  opr1 = opr1 >= opr2;
253 	  break;
254 	case EQ_OP:
255 	  opr1 = opr1 == opr2;
256 	  break;
257 	case NE_OP:
258 	  opr1 = opr1 != opr2;
259 	  break;
260 	case '&':
261 	  opr1 = opr1 & opr2;
262 	  break;
263 	case '^':
264 	  opr1 = opr1 ^ opr2;
265 	  break;
266 	case '|':
267 	  opr1 = opr1 | opr2;
268 	  break;
269 	case AND_OP:
270 	  opr1 = opr1 && opr2;
271 	  break;
272 	case OR_OP:
273 	  opr1 = opr1 || opr2;
274 	  break;
275 	default:
276 	  abort ();
277 	}
278       last_2nd->value.X_add_number = opr1;
279       last_1st->type = 0;
280       top--;
281     }
282   else
283     {
284       if (end <= top)
285 	as_fatal (_("expr too huge"));
286       switch (op)
287 	{
288 	case '+':
289 	  top->type = BFD_RELOC_LARCH_SOP_ADD;
290 	  break;
291 	case '-':
292 	  top->type = BFD_RELOC_LARCH_SOP_SUB;
293 	  break;
294 	case LEFT_OP:
295 	  top->type = BFD_RELOC_LARCH_SOP_SL;
296 	  break;
297 	case RIGHT_OP:
298 	  top->type = BFD_RELOC_LARCH_SOP_SR;
299 	  break;
300 	case '&':
301 	  top->type = BFD_RELOC_LARCH_SOP_AND;
302 	  break;
303 	default:
304 	  abort ();
305 	}
306       top->value = const_0;
307       top++;
308     }
309 }
310 
311 static void
312 emit_if_else (void)
313 {
314   struct reloc_info *last_1st = top - 1;
315   struct reloc_info *last_2nd = top - 2;
316   struct reloc_info *last_3rd = top - 3;
317   if (is_const (last_1st) && is_const (last_2nd) && is_const (last_3rd))
318     {
319       offsetT opr1 = last_3rd->value.X_add_number;
320       offsetT opr2 = last_2nd->value.X_add_number;
321       offsetT opr3 = last_1st->value.X_add_number;
322       opr1 = opr1 ? opr2 : opr3;
323       last_3rd->value.X_add_number = opr1;
324       last_2nd->type = 0;
325       last_1st->type = 0;
326       top -= 2;
327     }
328   else
329     {
330       if (end <= top)
331 	as_fatal (_("expr too huge"));
332       top->type = BFD_RELOC_LARCH_SOP_IF_ELSE;
333       top->value = const_0;
334       top++;
335     }
336 }
337 
338 %}
339 
340 %union {
341 char *c_str;
342 offsetT imm;
343 }
344 
345 %token <imm> INTEGER
346 %token <c_str> IDENTIFIER
347 %type <imm> addend
348 
349 %token LEFT_OP RIGHT_OP LE_OP GE_OP EQ_OP NE_OP AND_OP OR_OP
350 %start expression
351 %%
352 
353 primary_expression
354 	: INTEGER {emit_const ($1);}
355 	| '(' expression ')'
356 	| '%' IDENTIFIER '(' IDENTIFIER addend ')' {reloc ($2, $4, $5); free ($2); free ($4);}
357 	| '%' IDENTIFIER '(' INTEGER addend ')' {reloc ($2, NULL, $4 + $5); free ($2);}
358 	;
359 
360 addend
361 	: addend '-' INTEGER {$$ -= $3;}
362 	| addend '+' INTEGER {$$ += $3;}
363 	| {$$ = 0;}
364 	;
365 
366 unary_expression
367 	: primary_expression
368 	| '+' unary_expression {emit_unary ('+');}
369 	| '-' unary_expression {emit_unary ('-');}
370 	| '~' unary_expression {emit_unary ('~');}
371 	| '!' unary_expression {emit_unary ('!');}
372 	;
373 
374 multiplicative_expression
375 	: unary_expression
376 	| multiplicative_expression '*' unary_expression {emit_bin ('*');}
377 	| multiplicative_expression '/' unary_expression {emit_bin ('/');}
378 	| multiplicative_expression '%' unary_expression {emit_bin ('%');}
379 	;
380 
381 additive_expression
382 	: multiplicative_expression
383 	| additive_expression '+' multiplicative_expression {emit_bin ('+');}
384 	| additive_expression '-' multiplicative_expression {emit_bin ('-');}
385 	;
386 
387 shift_expression
388 	: additive_expression
389 	| shift_expression LEFT_OP additive_expression {emit_bin (LEFT_OP);}
390 	| shift_expression RIGHT_OP additive_expression {emit_bin (RIGHT_OP);}
391 	;
392 
393 relational_expression
394 	: shift_expression
395 	| relational_expression '<' shift_expression {emit_bin ('<');}
396 	| relational_expression '>' shift_expression {emit_bin ('>');}
397 	| relational_expression LE_OP shift_expression {emit_bin (LE_OP);}
398 	| relational_expression GE_OP shift_expression {emit_bin (GE_OP);}
399 	;
400 
401 equality_expression
402 	: relational_expression
403 	| equality_expression EQ_OP relational_expression {emit_bin (EQ_OP);}
404 	| equality_expression NE_OP relational_expression {emit_bin (NE_OP);}
405 	;
406 
407 and_expression
408 	: equality_expression
409 	| and_expression '&' equality_expression {emit_bin ('&');}
410 	;
411 
412 exclusive_or_expression
413 	: and_expression
414 	| exclusive_or_expression '^' and_expression {emit_bin ('^');}
415 	;
416 
417 inclusive_or_expression
418 	: exclusive_or_expression
419 	| inclusive_or_expression '|' exclusive_or_expression {emit_bin ('|');}
420 	;
421 
422 logical_and_expression
423 	: inclusive_or_expression
424 	| logical_and_expression AND_OP inclusive_or_expression {emit_bin (AND_OP);}
425 	;
426 
427 logical_or_expression
428 	: logical_and_expression
429 	| logical_or_expression OR_OP logical_and_expression {emit_bin (OR_OP);}
430 	;
431 
432 conditional_expression
433 	: logical_or_expression
434 	| logical_or_expression '?' expression ':' conditional_expression {emit_if_else ();}
435 	;
436 
437 expression
438 	: conditional_expression
439 	;
440 %%
441 
442