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