| 1 | %{ |
| 2 | /* |
| 3 | * Copyright(c) 2019-2023 rev.ng Labs Srl. All Rights Reserved. |
| 4 | * |
| 5 | * This program is distributed in the hope that it will be useful, |
| 6 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 7 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 8 | * GNU General Public License for more details. |
| 9 | * |
| 10 | * You should have received a copy of the GNU General Public License |
| 11 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
| 12 | */ |
| 13 | |
| 14 | #include "idef-parser.h" |
| 15 | #include "parser-helpers.h" |
| 16 | #include "idef-parser.tab.h" |
| 17 | #include "idef-parser.yy.h" |
| 18 | |
| 19 | /* Uncomment this to disable yyasserts */ |
| 20 | /* #define NDEBUG */ |
| 21 | |
| 22 | #define ERR_LINE_CONTEXT 40 |
| 23 | |
| 24 | %} |
| 25 | |
| 26 | %lex-param {void *scanner} |
| 27 | %parse-param {void *scanner} |
| 28 | %parse-param {Context *c} |
| 29 | |
| 30 | %define parse.error verbose |
| 31 | %define parse.lac full |
| 32 | %define api.pure full |
| 33 | |
| 34 | %locations |
| 35 | |
| 36 | %union { |
| 37 | GString *string; |
| 38 | HexValue rvalue; |
| 39 | HexSat sat; |
| 40 | HexCast cast; |
| 41 | HexExtract extract; |
| 42 | HexMpy mpy; |
| 43 | HexSignedness signedness; |
| 44 | int index; |
| 45 | } |
| 46 | |
| 47 | /* Tokens */ |
| 48 | %start input |
| 49 | |
| 50 | %expect 1 |
| 51 | |
| 52 | %token IN INAME VAR |
| 53 | %token ABS CROUND ROUND CIRCADD COUNTONES INC DEC ANDA ORA XORA PLUSPLUS ASL |
| 54 | %token ASR LSR EQ NEQ LTE GTE MIN MAX ANDL FOR ICIRC IF MUN FSCR FCHK SXT |
| 55 | %token ZXT CONSTEXT LOCNT BREV SIGN LOAD STORE PC LPCFG |
| 56 | %token LOAD_CANCEL STORE_CANCEL CANCEL IDENTITY ROTL INSBITS SETBITS EXTRANGE |
| 57 | %token CAST4_8U FAIL CARRY_FROM_ADD ADDSAT64 LSBNEW |
| 58 | %token TYPE_SIZE_T TYPE_INT TYPE_SIGNED TYPE_UNSIGNED TYPE_LONG |
| 59 | |
| 60 | %token <rvalue> REG IMM PRED |
| 61 | %token <index> ELSE |
| 62 | %token <mpy> MPY |
| 63 | %token <sat> SAT |
| 64 | %token <cast> CAST DEPOSIT SETHALF |
| 65 | %token <extract> EXTRACT |
| 66 | %type <string> INAME |
| 67 | %type <rvalue> rvalue lvalue VAR assign_statement var var_decl var_type |
| 68 | %type <rvalue> FAIL |
| 69 | %type <rvalue> TYPE_SIGNED TYPE_UNSIGNED TYPE_INT TYPE_LONG TYPE_SIZE_T |
| 70 | %type <index> if_stmt IF |
| 71 | %type <signedness> SIGN |
| 72 | |
| 73 | /* Operator Precedences */ |
| 74 | %left MIN MAX |
| 75 | %left '(' |
| 76 | %left ',' |
| 77 | %left '=' |
| 78 | %right CIRCADD |
| 79 | %right INC DEC ANDA ORA XORA |
| 80 | %left '?' ':' |
| 81 | %left ANDL |
| 82 | %left '|' |
| 83 | %left '^' ANDOR |
| 84 | %left '&' |
| 85 | %left EQ NEQ |
| 86 | %left '<' '>' LTE GTE |
| 87 | %left ASL ASR LSR |
| 88 | %right ABS |
| 89 | %left '-' '+' |
| 90 | %left '*' '/' '%' MPY |
| 91 | %right '~' '!' |
| 92 | %left '[' |
| 93 | %right CAST |
| 94 | %right LOCNT BREV |
| 95 | |
| 96 | /* Bison Grammar */ |
| 97 | %% |
| 98 | |
| 99 | /* Input file containing the description of each hexagon instruction */ |
| 100 | input : instructions |
| 101 | { |
| 102 | /* Suppress warning about unused yynerrs */ |
| 103 | (void) yynerrs; |
| 104 | YYACCEPT; |
| 105 | } |
| 106 | ; |
| 107 | |
| 108 | instructions : instruction instructions |
| 109 | | %empty |
| 110 | ; |
| 111 | |
| 112 | instruction : INAME |
| 113 | { |
| 114 | gen_inst(c, $1); |
| 115 | } |
| 116 | arguments |
| 117 | { |
| 118 | EMIT_SIG(c, ")"); |
| 119 | EMIT_HEAD(c, "{\n"); |
| 120 | } |
| 121 | code |
| 122 | { |
| 123 | gen_inst_code(c, &@1); |
| 124 | } |
| 125 | | error /* Recover gracefully after instruction compilation error */ |
| 126 | { |
| 127 | free_instruction(c); |
| 128 | } |
| 129 | ; |
| 130 | |
| 131 | arguments : '(' ')' |
| 132 | | '(' argument_list ')'; |
| 133 | |
| 134 | argument_list : argument_decl ',' argument_list |
| 135 | | argument_decl |
| 136 | ; |
| 137 | |
| 138 | var : VAR |
| 139 | { |
| 140 | track_string(c, $1.var.name); |
| 141 | $$ = $1; |
| 142 | } |
| 143 | ; |
| 144 | |
| 145 | /* |
| 146 | * Here the integer types are defined from valid combinations of |
| 147 | * `signed`, `unsigned`, `int`, and `long` tokens. The `signed` |
| 148 | * and `unsigned` tokens are here assumed to always be placed |
| 149 | * first in the type declaration, which is not the case in |
| 150 | * normal C. Similarly, `int` is assumed to always be placed |
| 151 | * last in the type. |
| 152 | */ |
| 153 | type_int : TYPE_INT |
| 154 | | TYPE_SIGNED |
| 155 | | TYPE_SIGNED TYPE_INT; |
| 156 | type_uint : TYPE_UNSIGNED |
| 157 | | TYPE_UNSIGNED TYPE_INT; |
| 158 | type_ulonglong : TYPE_UNSIGNED TYPE_LONG TYPE_LONG |
| 159 | | TYPE_UNSIGNED TYPE_LONG TYPE_LONG TYPE_INT; |
| 160 | |
| 161 | /* |
| 162 | * Here the various valid int types defined above specify |
| 163 | * their `signedness` and `bit_width`. The LP64 convention |
| 164 | * is assumed where longs are 64-bit, long longs are then |
| 165 | * assumed to also be 64-bit. |
| 166 | */ |
| 167 | var_type : TYPE_SIZE_T |
| 168 | { |
| 169 | yyassert(c, &@1, $1.bit_width <= 64, |
| 170 | "Variables with size > 64-bit are not supported!"); |
| 171 | $$ = $1; |
| 172 | } |
| 173 | | type_int |
| 174 | { |
| 175 | $$.signedness = SIGNED; |
| 176 | $$.bit_width = 32; |
| 177 | } |
| 178 | | type_uint |
| 179 | { |
| 180 | $$.signedness = UNSIGNED; |
| 181 | $$.bit_width = 32; |
| 182 | } |
| 183 | | type_ulonglong |
| 184 | { |
| 185 | $$.signedness = UNSIGNED; |
| 186 | $$.bit_width = 64; |
| 187 | } |
| 188 | ; |
| 189 | |
| 190 | /* Rule to capture declarations of VARs */ |
| 191 | var_decl : var_type IMM |
| 192 | { |
| 193 | /* |
| 194 | * Rule to capture "int i;" declarations since "i" is special |
| 195 | * and assumed to be always be IMM. Moreover, "i" is only |
| 196 | * assumed to be used in for-loops. |
| 197 | * |
| 198 | * Therefore we want to NOP these declarations. |
| 199 | */ |
| 200 | yyassert(c, &@2, $2.imm.type == I, |
| 201 | "Variable declaration with immedaties only allowed" |
| 202 | " for the loop induction variable \"i\""); |
| 203 | $$ = $2; |
| 204 | } |
| 205 | | var_type var |
| 206 | { |
| 207 | /* |
| 208 | * Allocate new variable, this checks that it hasn't already |
| 209 | * been declared. |
| 210 | */ |
| 211 | gen_varid_allocate(c, &@1, &$2, $1.bit_width, $1.signedness); |
| 212 | /* Copy var for variable name */ |
| 213 | $$ = $2; |
| 214 | /* Copy type info from var_type */ |
| 215 | $$.signedness = $1.signedness; |
| 216 | $$.bit_width = $1.bit_width; |
| 217 | } |
| 218 | ; |
| 219 | |
| 220 | /* Return the modified registers list */ |
| 221 | code : '{' statements '}' |
| 222 | { |
| 223 | c->inst.code_begin = c->input_buffer + @2.first_column - 1; |
| 224 | c->inst.code_end = c->input_buffer + @2.last_column - 1; |
| 225 | } |
| 226 | | '{' |
| 227 | { |
| 228 | /* Nop */ |
| 229 | } |
| 230 | '}' |
| 231 | ; |
| 232 | |
| 233 | argument_decl : REG |
| 234 | { |
| 235 | emit_arg(c, &@1, &$1); |
| 236 | } |
| 237 | | PRED |
| 238 | { |
| 239 | emit_arg(c, &@1, &$1); |
| 240 | /* Enqueue predicate into initialization list */ |
| 241 | g_array_append_val(c->inst.init_list, $1); |
| 242 | } |
| 243 | | IN REG |
| 244 | { |
| 245 | emit_arg(c, &@2, &$2); |
| 246 | } |
| 247 | | IN PRED |
| 248 | { |
| 249 | emit_arg(c, &@2, &$2); |
| 250 | } |
| 251 | | IMM |
| 252 | { |
| 253 | EMIT_SIG(c, ", int %ciV", $1.imm.id); |
| 254 | } |
| 255 | ; |
| 256 | |
| 257 | code_block : '{' statements '}' |
| 258 | | '{' '}' |
| 259 | ; |
| 260 | |
| 261 | /* A list of one or more statements */ |
| 262 | statements : statements statement |
| 263 | | statement |
| 264 | ; |
| 265 | |
| 266 | /* Statements can be assignment (rvalue ';'), control or memory statements */ |
| 267 | statement : control_statement |
| 268 | | var_decl ';' |
| 269 | | rvalue ';' |
| 270 | | code_block |
| 271 | | ';' |
| 272 | ; |
| 273 | |
| 274 | assign_statement : lvalue '=' rvalue |
| 275 | { |
| 276 | @1.last_column = @3.last_column; |
| 277 | gen_assign(c, &@1, &$1, &$3); |
| 278 | $$ = $1; |
| 279 | } |
| 280 | | var_decl '=' rvalue |
| 281 | { |
| 282 | @1.last_column = @3.last_column; |
| 283 | gen_assign(c, &@1, &$1, &$3); |
| 284 | $$ = $1; |
| 285 | } |
| 286 | | lvalue INC rvalue |
| 287 | { |
| 288 | @1.last_column = @3.last_column; |
| 289 | HexValue tmp = gen_bin_op(c, &@1, ADD_OP, &$1, &$3); |
| 290 | gen_assign(c, &@1, &$1, &tmp); |
| 291 | $$ = $1; |
| 292 | } |
| 293 | | lvalue DEC rvalue |
| 294 | { |
| 295 | @1.last_column = @3.last_column; |
| 296 | HexValue tmp = gen_bin_op(c, &@1, SUB_OP, &$1, &$3); |
| 297 | gen_assign(c, &@1, &$1, &tmp); |
| 298 | $$ = $1; |
| 299 | } |
| 300 | | lvalue ANDA rvalue |
| 301 | { |
| 302 | @1.last_column = @3.last_column; |
| 303 | HexValue tmp = gen_bin_op(c, &@1, ANDB_OP, &$1, &$3); |
| 304 | gen_assign(c, &@1, &$1, &tmp); |
| 305 | $$ = $1; |
| 306 | } |
| 307 | | lvalue ORA rvalue |
| 308 | { |
| 309 | @1.last_column = @3.last_column; |
| 310 | HexValue tmp = gen_bin_op(c, &@1, ORB_OP, &$1, &$3); |
| 311 | gen_assign(c, &@1, &$1, &tmp); |
| 312 | $$ = $1; |
| 313 | } |
| 314 | | lvalue XORA rvalue |
| 315 | { |
| 316 | @1.last_column = @3.last_column; |
| 317 | HexValue tmp = gen_bin_op(c, &@1, XORB_OP, &$1, &$3); |
| 318 | gen_assign(c, &@1, &$1, &tmp); |
| 319 | $$ = $1; |
| 320 | } |
| 321 | | PRED '=' rvalue |
| 322 | { |
| 323 | @1.last_column = @3.last_column; |
| 324 | gen_pred_assign(c, &@1, &$1, &$3); |
| 325 | } |
| 326 | | IMM '=' rvalue |
| 327 | { |
| 328 | @1.last_column = @3.last_column; |
| 329 | yyassert(c, &@1, $3.type == IMMEDIATE, |
| 330 | "Cannot assign non-immediate to immediate!"); |
| 331 | yyassert(c, &@1, $1.imm.type == VARIABLE, |
| 332 | "Cannot assign to non-variable!"); |
| 333 | /* Assign to the function argument */ |
| 334 | OUT(c, &@1, &$1, " = ", &$3, ";\n"); |
| 335 | $$ = $1; |
| 336 | } |
| 337 | | LOAD '(' IMM ',' IMM ',' SIGN ',' var ',' lvalue ')' |
| 338 | { |
| 339 | @1.last_column = @12.last_column; |
| 340 | yyassert(c, &@1, !is_inside_ternary(c), |
| 341 | "Assignment side-effect not modeled!"); |
| 342 | yyassert(c, &@1, $3.imm.value == 1, |
| 343 | "LOAD of arrays not supported!"); |
| 344 | gen_load(c, &@1, &$5, $7, &$9, &$11); |
| 345 | } |
| 346 | | STORE '(' IMM ',' IMM ',' var ',' rvalue ')' |
| 347 | /* Store primitive */ |
| 348 | { |
| 349 | @1.last_column = @10.last_column; |
| 350 | yyassert(c, &@1, !is_inside_ternary(c), |
| 351 | "Assignment side-effect not modeled!"); |
| 352 | yyassert(c, &@1, $3.imm.value == 1, |
| 353 | "STORE of arrays not supported!"); |
| 354 | gen_store(c, &@1, &$5, &$7, &$9); |
| 355 | } |
| 356 | | LPCFG '=' rvalue |
| 357 | { |
| 358 | @1.last_column = @3.last_column; |
| 359 | yyassert(c, &@1, !is_inside_ternary(c), |
| 360 | "Assignment side-effect not modeled!"); |
| 361 | $3 = gen_rvalue_truncate(c, &@1, &$3); |
| 362 | $3 = rvalue_materialize(c, &@1, &$3); |
| 363 | OUT(c, &@1, "gen_set_usr_field(ctx, USR_LPCFG, ", &$3, ");\n"); |
| 364 | } |
| 365 | | DEPOSIT '(' rvalue ',' rvalue ',' rvalue ')' |
| 366 | { |
| 367 | @1.last_column = @8.last_column; |
| 368 | yyassert(c, &@1, !is_inside_ternary(c), |
| 369 | "Assignment side-effect not modeled!"); |
| 370 | gen_deposit_op(c, &@1, &$5, &$7, &$3, &$1); |
| 371 | } |
| 372 | | SETHALF '(' rvalue ',' lvalue ',' rvalue ')' |
| 373 | { |
| 374 | @1.last_column = @8.last_column; |
| 375 | yyassert(c, &@1, !is_inside_ternary(c), |
| 376 | "Assignment side-effect not modeled!"); |
| 377 | gen_sethalf(c, &@1, &$1, &$3, &$5, &$7); |
| 378 | } |
| 379 | | SETBITS '(' rvalue ',' rvalue ',' rvalue ',' rvalue ')' |
| 380 | { |
| 381 | @1.last_column = @10.last_column; |
| 382 | yyassert(c, &@1, !is_inside_ternary(c), |
| 383 | "Assignment side-effect not modeled!"); |
| 384 | gen_setbits(c, &@1, &$3, &$5, &$7, &$9); |
| 385 | } |
| 386 | | INSBITS '(' lvalue ',' rvalue ',' rvalue ',' rvalue ')' |
| 387 | { |
| 388 | @1.last_column = @10.last_column; |
| 389 | yyassert(c, &@1, !is_inside_ternary(c), |
| 390 | "Assignment side-effect not modeled!"); |
| 391 | gen_rdeposit_op(c, &@1, &$3, &$9, &$7, &$5); |
| 392 | } |
| 393 | | IDENTITY '(' rvalue ')' |
| 394 | { |
| 395 | @1.last_column = @4.last_column; |
| 396 | $$ = $3; |
| 397 | } |
| 398 | ; |
| 399 | |
| 400 | control_statement : frame_check |
| 401 | | cancel_statement |
| 402 | | if_statement |
| 403 | | for_statement |
| 404 | ; |
| 405 | |
| 406 | frame_check : FCHK '(' rvalue ',' rvalue ')' ';' |
| 407 | { |
| 408 | gen_framecheck(c, &@1, &$3, &$5); |
| 409 | } |
| 410 | ; |
| 411 | |
| 412 | cancel_statement : LOAD_CANCEL |
| 413 | { |
| 414 | gen_load_cancel(c, &@1); |
| 415 | } |
| 416 | | STORE_CANCEL |
| 417 | { |
| 418 | gen_cancel(c, &@1); |
| 419 | } |
| 420 | | CANCEL |
| 421 | ; |
| 422 | |
| 423 | if_statement : if_stmt |
| 424 | { |
| 425 | /* Fix else label */ |
| 426 | OUT(c, &@1, "gen_set_label(if_label_", &$1, ");\n"); |
| 427 | } |
| 428 | | if_stmt ELSE |
| 429 | { |
| 430 | @1.last_column = @2.last_column; |
| 431 | $2 = gen_if_else(c, &@1, $1); |
| 432 | } |
| 433 | statement |
| 434 | { |
| 435 | OUT(c, &@1, "gen_set_label(if_label_", &$2, ");\n"); |
| 436 | } |
| 437 | ; |
| 438 | |
| 439 | for_statement : FOR '(' IMM '=' IMM ';' IMM '<' IMM ';' IMM PLUSPLUS ')' |
| 440 | { |
| 441 | yyassert(c, &@3, |
| 442 | $3.imm.type == I && |
| 443 | $7.imm.type == I && |
| 444 | $11.imm.type == I, |
| 445 | "Loop induction variable must be \"i\""); |
| 446 | @1.last_column = @13.last_column; |
| 447 | OUT(c, &@1, "for (int ", &$3, " = ", &$5, "; ", |
| 448 | &$7, " < ", &$9); |
| 449 | OUT(c, &@1, "; ", &$11, "++) {\n"); |
| 450 | } |
| 451 | code_block |
| 452 | { |
| 453 | OUT(c, &@1, "}\n"); |
| 454 | } |
| 455 | ; |
| 456 | |
| 457 | if_stmt : IF '(' rvalue ')' |
| 458 | { |
| 459 | @1.last_column = @3.last_column; |
| 460 | $1 = gen_if_cond(c, &@1, &$3); |
| 461 | } |
| 462 | statement |
| 463 | { |
| 464 | $$ = $1; |
| 465 | } |
| 466 | ; |
| 467 | |
| 468 | rvalue : FAIL |
| 469 | { |
| 470 | yyassert(c, &@1, false, "Encountered a FAIL token as rvalue.\n"); |
| 471 | } |
| 472 | | assign_statement |
| 473 | | REG |
| 474 | { |
| 475 | $$ = $1; |
| 476 | } |
| 477 | | IMM |
| 478 | { |
| 479 | $$ = $1; |
| 480 | } |
| 481 | | PRED |
| 482 | { |
| 483 | $$ = gen_rvalue_pred(c, &@1, &$1); |
| 484 | } |
| 485 | | PC |
| 486 | { |
| 487 | /* Read PC from the CR */ |
| 488 | HexValue rvalue; |
| 489 | memset(&rvalue, 0, sizeof(HexValue)); |
| 490 | rvalue.type = IMMEDIATE; |
| 491 | rvalue.imm.type = IMM_PC; |
| 492 | rvalue.bit_width = 32; |
| 493 | rvalue.signedness = UNSIGNED; |
| 494 | $$ = rvalue; |
| 495 | } |
| 496 | | CONSTEXT |
| 497 | { |
| 498 | HexValue rvalue; |
| 499 | memset(&rvalue, 0, sizeof(HexValue)); |
| 500 | rvalue.type = IMMEDIATE; |
| 501 | rvalue.imm.type = IMM_CONSTEXT; |
| 502 | rvalue.signedness = UNSIGNED; |
| 503 | rvalue.is_dotnew = false; |
| 504 | $$ = rvalue; |
| 505 | } |
| 506 | | var |
| 507 | { |
| 508 | $$ = gen_rvalue_var(c, &@1, &$1); |
| 509 | } |
| 510 | | MPY '(' rvalue ',' rvalue ')' |
| 511 | { |
| 512 | @1.last_column = @6.last_column; |
| 513 | $$ = gen_rvalue_mpy(c, &@1, &$1, &$3, &$5); |
| 514 | } |
| 515 | | rvalue '+' rvalue |
| 516 | { |
| 517 | @1.last_column = @3.last_column; |
| 518 | $$ = gen_bin_op(c, &@1, ADD_OP, &$1, &$3); |
| 519 | } |
| 520 | | rvalue '-' rvalue |
| 521 | { |
| 522 | @1.last_column = @3.last_column; |
| 523 | $$ = gen_bin_op(c, &@1, SUB_OP, &$1, &$3); |
| 524 | } |
| 525 | | rvalue '*' rvalue |
| 526 | { |
| 527 | @1.last_column = @3.last_column; |
| 528 | $$ = gen_bin_op(c, &@1, MUL_OP, &$1, &$3); |
| 529 | } |
| 530 | | rvalue ASL rvalue |
| 531 | { |
| 532 | @1.last_column = @3.last_column; |
| 533 | $$ = gen_bin_op(c, &@1, ASL_OP, &$1, &$3); |
| 534 | } |
| 535 | | rvalue ASR rvalue |
| 536 | { |
| 537 | @1.last_column = @3.last_column; |
| 538 | assert_signedness(c, &@1, $1.signedness); |
| 539 | if ($1.signedness == UNSIGNED) { |
| 540 | $$ = gen_bin_op(c, &@1, LSR_OP, &$1, &$3); |
| 541 | } else if ($1.signedness == SIGNED) { |
| 542 | $$ = gen_bin_op(c, &@1, ASR_OP, &$1, &$3); |
| 543 | } |
| 544 | } |
| 545 | | rvalue LSR rvalue |
| 546 | { |
| 547 | @1.last_column = @3.last_column; |
| 548 | $$ = gen_bin_op(c, &@1, LSR_OP, &$1, &$3); |
| 549 | } |
| 550 | | rvalue '&' rvalue |
| 551 | { |
| 552 | @1.last_column = @3.last_column; |
| 553 | $$ = gen_bin_op(c, &@1, ANDB_OP, &$1, &$3); |
| 554 | } |
| 555 | | rvalue '|' rvalue |
| 556 | { |
| 557 | @1.last_column = @3.last_column; |
| 558 | $$ = gen_bin_op(c, &@1, ORB_OP, &$1, &$3); |
| 559 | } |
| 560 | | rvalue '^' rvalue |
| 561 | { |
| 562 | @1.last_column = @3.last_column; |
| 563 | $$ = gen_bin_op(c, &@1, XORB_OP, &$1, &$3); |
| 564 | } |
| 565 | | rvalue ANDL rvalue |
| 566 | { |
| 567 | @1.last_column = @3.last_column; |
| 568 | $$ = gen_bin_op(c, &@1, ANDL_OP, &$1, &$3); |
| 569 | } |
| 570 | | MIN '(' rvalue ',' rvalue ')' |
| 571 | { |
| 572 | @1.last_column = @3.last_column; |
| 573 | $$ = gen_bin_op(c, &@1, MINI_OP, &$3, &$5); |
| 574 | } |
| 575 | | MAX '(' rvalue ',' rvalue ')' |
| 576 | { |
| 577 | @1.last_column = @3.last_column; |
| 578 | $$ = gen_bin_op(c, &@1, MAXI_OP, &$3, &$5); |
| 579 | } |
| 580 | | '~' rvalue |
| 581 | { |
| 582 | @1.last_column = @2.last_column; |
| 583 | $$ = gen_rvalue_not(c, &@1, &$2); |
| 584 | } |
| 585 | | '!' rvalue |
| 586 | { |
| 587 | @1.last_column = @2.last_column; |
| 588 | $$ = gen_rvalue_notl(c, &@1, &$2); |
| 589 | } |
| 590 | | SAT '(' IMM ',' rvalue ')' |
| 591 | { |
| 592 | @1.last_column = @6.last_column; |
| 593 | $$ = gen_rvalue_sat(c, &@1, &$1, &$3, &$5); |
| 594 | } |
| 595 | | CAST rvalue |
| 596 | { |
| 597 | @1.last_column = @2.last_column; |
| 598 | $$ = gen_cast_op(c, &@1, &$2, $1.bit_width, $1.signedness); |
| 599 | } |
| 600 | | rvalue EQ rvalue |
| 601 | { |
| 602 | @1.last_column = @3.last_column; |
| 603 | $$ = gen_bin_cmp(c, &@1, TCG_COND_EQ, &$1, &$3); |
| 604 | } |
| 605 | | rvalue NEQ rvalue |
| 606 | { |
| 607 | @1.last_column = @3.last_column; |
| 608 | $$ = gen_bin_cmp(c, &@1, TCG_COND_NE, &$1, &$3); |
| 609 | } |
| 610 | | rvalue '<' rvalue |
| 611 | { |
| 612 | @1.last_column = @3.last_column; |
| 613 | |
| 614 | assert_signedness(c, &@1, $1.signedness); |
| 615 | assert_signedness(c, &@1, $3.signedness); |
| 616 | if ($1.signedness == UNSIGNED || $3.signedness == UNSIGNED) { |
| 617 | $$ = gen_bin_cmp(c, &@1, TCG_COND_LTU, &$1, &$3); |
| 618 | } else { |
| 619 | $$ = gen_bin_cmp(c, &@1, TCG_COND_LT, &$1, &$3); |
| 620 | } |
| 621 | } |
| 622 | | rvalue '>' rvalue |
| 623 | { |
| 624 | @1.last_column = @3.last_column; |
| 625 | |
| 626 | assert_signedness(c, &@1, $1.signedness); |
| 627 | assert_signedness(c, &@1, $3.signedness); |
| 628 | if ($1.signedness == UNSIGNED || $3.signedness == UNSIGNED) { |
| 629 | $$ = gen_bin_cmp(c, &@1, TCG_COND_GTU, &$1, &$3); |
| 630 | } else { |
| 631 | $$ = gen_bin_cmp(c, &@1, TCG_COND_GT, &$1, &$3); |
| 632 | } |
| 633 | } |
| 634 | | rvalue LTE rvalue |
| 635 | { |
| 636 | @1.last_column = @3.last_column; |
| 637 | |
| 638 | assert_signedness(c, &@1, $1.signedness); |
| 639 | assert_signedness(c, &@1, $3.signedness); |
| 640 | if ($1.signedness == UNSIGNED || $3.signedness == UNSIGNED) { |
| 641 | $$ = gen_bin_cmp(c, &@1, TCG_COND_LEU, &$1, &$3); |
| 642 | } else { |
| 643 | $$ = gen_bin_cmp(c, &@1, TCG_COND_LE, &$1, &$3); |
| 644 | } |
| 645 | } |
| 646 | | rvalue GTE rvalue |
| 647 | { |
| 648 | @1.last_column = @3.last_column; |
| 649 | |
| 650 | assert_signedness(c, &@1, $1.signedness); |
| 651 | assert_signedness(c, &@1, $3.signedness); |
| 652 | if ($1.signedness == UNSIGNED || $3.signedness == UNSIGNED) { |
| 653 | $$ = gen_bin_cmp(c, &@1, TCG_COND_GEU, &$1, &$3); |
| 654 | } else { |
| 655 | $$ = gen_bin_cmp(c, &@1, TCG_COND_GE, &$1, &$3); |
| 656 | } |
| 657 | } |
| 658 | | rvalue '?' |
| 659 | { |
| 660 | Ternary t = { 0 }; |
| 661 | t.state = IN_LEFT; |
| 662 | t.cond = $1; |
| 663 | g_array_append_val(c->ternary, t); |
| 664 | } |
| 665 | rvalue ':' |
| 666 | { |
| 667 | Ternary *t = &g_array_index(c->ternary, Ternary, |
| 668 | c->ternary->len - 1); |
| 669 | t->state = IN_RIGHT; |
| 670 | } |
| 671 | rvalue |
| 672 | { |
| 673 | @1.last_column = @5.last_column; |
| 674 | $$ = gen_rvalue_ternary(c, &@1, &$1, &$4, &$7); |
| 675 | } |
| 676 | | FSCR '(' rvalue ')' |
| 677 | { |
| 678 | @1.last_column = @4.last_column; |
| 679 | $$ = gen_rvalue_fscr(c, &@1, &$3); |
| 680 | } |
| 681 | | SXT '(' rvalue ',' IMM ',' rvalue ')' |
| 682 | { |
| 683 | @1.last_column = @8.last_column; |
| 684 | yyassert(c, &@1, $5.type == IMMEDIATE && |
| 685 | $5.imm.type == VALUE, |
| 686 | "SXT expects immediate values\n"); |
| 687 | $$ = gen_extend_op(c, &@1, &$3, 64, &$7, SIGNED); |
| 688 | } |
| 689 | | ZXT '(' rvalue ',' IMM ',' rvalue ')' |
| 690 | { |
| 691 | @1.last_column = @8.last_column; |
| 692 | yyassert(c, &@1, $5.type == IMMEDIATE && |
| 693 | $5.imm.type == VALUE, |
| 694 | "ZXT expects immediate values\n"); |
| 695 | $$ = gen_extend_op(c, &@1, &$3, 64, &$7, UNSIGNED); |
| 696 | } |
| 697 | | '(' rvalue ')' |
| 698 | { |
| 699 | $$ = $2; |
| 700 | } |
| 701 | | ABS rvalue |
| 702 | { |
| 703 | @1.last_column = @2.last_column; |
| 704 | $$ = gen_rvalue_abs(c, &@1, &$2); |
| 705 | } |
| 706 | | CROUND '(' rvalue ',' rvalue ')' |
| 707 | { |
| 708 | @1.last_column = @6.last_column; |
| 709 | $$ = gen_convround_n(c, &@1, &$3, &$5); |
| 710 | } |
| 711 | | CROUND '(' rvalue ')' |
| 712 | { |
| 713 | @1.last_column = @4.last_column; |
| 714 | $$ = gen_convround(c, &@1, &$3); |
| 715 | } |
| 716 | | ROUND '(' rvalue ',' rvalue ')' |
| 717 | { |
| 718 | @1.last_column = @6.last_column; |
| 719 | $$ = gen_round(c, &@1, &$3, &$5); |
| 720 | } |
| 721 | | '-' rvalue |
| 722 | { |
| 723 | @1.last_column = @2.last_column; |
| 724 | $$ = gen_rvalue_neg(c, &@1, &$2); |
| 725 | } |
| 726 | | ICIRC '(' rvalue ')' ASL IMM |
| 727 | { |
| 728 | @1.last_column = @6.last_column; |
| 729 | $$ = gen_tmp(c, &@1, 32, UNSIGNED); |
| 730 | OUT(c, &@1, "gen_read_ireg(", &$$, ", ", &$3, ", ", &$6, ");\n"); |
| 731 | } |
| 732 | | CIRCADD '(' rvalue ',' rvalue ',' rvalue ')' |
| 733 | { |
| 734 | @1.last_column = @8.last_column; |
| 735 | gen_circ_op(c, &@1, &$3, &$5, &$7); |
| 736 | } |
| 737 | | LOCNT '(' rvalue ')' |
| 738 | { |
| 739 | @1.last_column = @4.last_column; |
| 740 | /* Leading ones count */ |
| 741 | $$ = gen_locnt_op(c, &@1, &$3); |
| 742 | } |
| 743 | | COUNTONES '(' rvalue ')' |
| 744 | { |
| 745 | @1.last_column = @4.last_column; |
| 746 | /* Ones count */ |
| 747 | $$ = gen_ctpop_op(c, &@1, &$3); |
| 748 | } |
| 749 | | EXTRACT '(' rvalue ',' rvalue ')' |
| 750 | { |
| 751 | @1.last_column = @6.last_column; |
| 752 | $$ = gen_extract_op(c, &@1, &$5, &$3, &$1); |
| 753 | } |
| 754 | | EXTRANGE '(' rvalue ',' rvalue ',' rvalue ')' |
| 755 | { |
| 756 | @1.last_column = @8.last_column; |
| 757 | yyassert(c, &@1, $5.type == IMMEDIATE && |
| 758 | $5.imm.type == VALUE && |
| 759 | $7.type == IMMEDIATE && |
| 760 | $7.imm.type == VALUE, |
| 761 | "Range extract needs immediate values!\n"); |
| 762 | $$ = gen_rextract_op(c, |
| 763 | &@1, |
| 764 | &$3, |
| 765 | $7.imm.value, |
| 766 | $5.imm.value - $7.imm.value + 1); |
| 767 | } |
| 768 | | CAST4_8U '(' rvalue ')' |
| 769 | { |
| 770 | @1.last_column = @4.last_column; |
| 771 | $$ = gen_rvalue_truncate(c, &@1, &$3); |
| 772 | $$.signedness = UNSIGNED; |
| 773 | $$ = rvalue_materialize(c, &@1, &$$); |
| 774 | $$ = gen_rvalue_extend(c, &@1, &$$); |
| 775 | } |
| 776 | | BREV '(' rvalue ')' |
| 777 | { |
| 778 | @1.last_column = @4.last_column; |
| 779 | $$ = gen_rvalue_brev(c, &@1, &$3); |
| 780 | } |
| 781 | | ROTL '(' rvalue ',' rvalue ')' |
| 782 | { |
| 783 | @1.last_column = @6.last_column; |
| 784 | $$ = gen_rotl(c, &@1, &$3, &$5); |
| 785 | } |
| 786 | | ADDSAT64 '(' rvalue ',' rvalue ',' rvalue ')' |
| 787 | { |
| 788 | @1.last_column = @8.last_column; |
| 789 | gen_addsat64(c, &@1, &$3, &$5, &$7); |
| 790 | } |
| 791 | | CARRY_FROM_ADD '(' rvalue ',' rvalue ',' rvalue ')' |
| 792 | { |
| 793 | @1.last_column = @8.last_column; |
| 794 | $$ = gen_carry_from_add(c, &@1, &$3, &$5, &$7); |
| 795 | } |
| 796 | | LSBNEW '(' rvalue ')' |
| 797 | { |
| 798 | @1.last_column = @4.last_column; |
| 799 | HexValue one = gen_imm_value(c, &@1, 1, 32, UNSIGNED); |
| 800 | $$ = gen_bin_op(c, &@1, ANDB_OP, &$3, &one); |
| 801 | } |
| 802 | ; |
| 803 | |
| 804 | lvalue : FAIL |
| 805 | { |
| 806 | yyassert(c, &@1, false, "Encountered a FAIL token as lvalue.\n"); |
| 807 | } |
| 808 | | REG |
| 809 | { |
| 810 | $$ = $1; |
| 811 | } |
| 812 | | var |
| 813 | { |
| 814 | $$ = $1; |
| 815 | } |
| 816 | ; |
| 817 | |
| 818 | %% |
| 819 | |
| 820 | int main(int argc, char **argv) |
| 821 | { |
| 822 | if (argc != 5) { |
| 823 | fprintf(stderr, |
| 824 | "Semantics: Hexagon ISA to tinycode generator compiler\n\n"); |
| 825 | fprintf(stderr, |
| 826 | "Usage: ./semantics IDEFS EMITTER_C EMITTER_H " |
| 827 | "ENABLED_INSTRUCTIONS_LIST\n"); |
| 828 | return 1; |
| 829 | } |
| 830 | |
| 831 | enum { |
| 832 | ARG_INDEX_ARGV0 = 0, |
| 833 | ARG_INDEX_IDEFS, |
| 834 | ARG_INDEX_EMITTER_C, |
| 835 | ARG_INDEX_EMITTER_H, |
| 836 | ARG_INDEX_ENABLED_INSTRUCTIONS_LIST |
| 837 | }; |
| 838 | |
| 839 | FILE *enabled_file = fopen(argv[ARG_INDEX_ENABLED_INSTRUCTIONS_LIST], "w"); |
| 840 | |
| 841 | FILE *output_file = fopen(argv[ARG_INDEX_EMITTER_C], "w"); |
| 842 | fputs("#include \"qemu/osdep.h\"\n", output_file); |
| 843 | fputs("#include \"qemu/log.h\"\n", output_file); |
| 844 | fputs("#include \"cpu.h\"\n", output_file); |
| 845 | fputs("#include \"internal.h\"\n", output_file); |
| 846 | fputs("#include \"tcg/tcg.h\"\n", output_file); |
| 847 | fputs("#include \"tcg/tcg-op.h\"\n", output_file); |
| 848 | fputs("#include \"exec/helper-gen.h\"\n", output_file); |
| 849 | fputs("#include \"insn.h\"\n", output_file); |
| 850 | fputs("#include \"opcodes.h\"\n", output_file); |
| 851 | fputs("#include \"translate.h\"\n", output_file); |
| 852 | fputs("#define QEMU_GENERATE\n", output_file); |
| 853 | fputs("#include \"genptr.h\"\n", output_file); |
| 854 | fputs("#include \"macros.h\"\n", output_file); |
| 855 | fprintf(output_file, "#include \"%s\"\n", argv[ARG_INDEX_EMITTER_H]); |
| 856 | |
| 857 | FILE *defines_file = fopen(argv[ARG_INDEX_EMITTER_H], "w"); |
| 858 | assert(defines_file != NULL); |
| 859 | fputs("#ifndef HEX_EMITTER_H\n", defines_file); |
| 860 | fputs("#define HEX_EMITTER_H\n", defines_file); |
| 861 | fputs("\n", defines_file); |
| 862 | fputs("#include \"insn.h\"\n\n", defines_file); |
| 863 | |
| 864 | /* Parser input file */ |
| 865 | Context context = { 0 }; |
| 866 | context.defines_file = defines_file; |
| 867 | context.output_file = output_file; |
| 868 | context.enabled_file = enabled_file; |
| 869 | /* Initialize buffers */ |
| 870 | context.out_str = g_string_new(NULL); |
| 871 | context.signature_str = g_string_new(NULL); |
| 872 | context.header_str = g_string_new(NULL); |
| 873 | context.ternary = g_array_new(FALSE, TRUE, sizeof(Ternary)); |
| 874 | /* Read input file */ |
| 875 | FILE *input_file = fopen(argv[ARG_INDEX_IDEFS], "rb"); |
| 876 | fseek(input_file, 0L, SEEK_END); |
| 877 | long input_size = ftell(input_file); |
| 878 | context.input_buffer = (char *) calloc(input_size + 1, sizeof(char)); |
| 879 | fseek(input_file, 0L, SEEK_SET); |
| 880 | size_t read_chars = fread(context.input_buffer, |
| 881 | sizeof(char), |
| 882 | input_size, |
| 883 | input_file); |
| 884 | if (read_chars != (size_t) input_size) { |
| 885 | fprintf(stderr, "Error: an error occurred while reading input file!\n"); |
| 886 | return -1; |
| 887 | } |
| 888 | yylex_init(&context.scanner); |
| 889 | YY_BUFFER_STATE buffer; |
| 890 | buffer = yy_scan_string(context.input_buffer, context.scanner); |
| 891 | /* Start the parsing procedure */ |
| 892 | yyparse(context.scanner, &context); |
| 893 | if (context.implemented_insn != context.total_insn) { |
| 894 | fprintf(stderr, |
| 895 | "Warning: %d/%d meta instructions have been implemented!\n", |
| 896 | context.implemented_insn, |
| 897 | context.total_insn); |
| 898 | } |
| 899 | fputs("#endif " START_COMMENT " HEX_EMITTER_h " END_COMMENT "\n", |
| 900 | defines_file); |
| 901 | /* Cleanup */ |
| 902 | yy_delete_buffer(buffer, context.scanner); |
| 903 | yylex_destroy(context.scanner); |
| 904 | free(context.input_buffer); |
| 905 | g_string_free(context.out_str, TRUE); |
| 906 | g_string_free(context.signature_str, TRUE); |
| 907 | g_string_free(context.header_str, TRUE); |
| 908 | g_array_free(context.ternary, TRUE); |
| 909 | fclose(output_file); |
| 910 | fclose(input_file); |
| 911 | fclose(defines_file); |
| 912 | fclose(enabled_file); |
| 913 | |
| 914 | return 0; |
| 915 | } |