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