| @@ -248,6 +248,14 @@ static void asm_binary_opcode(TCCState *s1, int token) · 247 unmodified lines |
| 248 | Note: For single data transfer instructions, "0" means immediate. */ | 248 | Note: For single data transfer instructions, "0" means immediate. */ |
| 249 | #define ENCODE_IMMEDIATE_FLAG (1 << 25) | 249 | #define ENCODE_IMMEDIATE_FLAG (1 << 25) |
| 250 | | 250 | |
| | 251 | #define ENCODE_BARREL_SHIFTER_SHIFT_BY_REGISTER (1 << 4) |
| | 252 | #define ENCODE_BARREL_SHIFTER_MODE_LSL (0 << 5) |
| | 253 | #define ENCODE_BARREL_SHIFTER_MODE_LSR (1 << 5) |
| | 254 | #define ENCODE_BARREL_SHIFTER_MODE_ASR (2 << 5) |
| | 255 | #define ENCODE_BARREL_SHIFTER_MODE_ROR (3 << 5) |
| | 256 | #define ENCODE_BARREL_SHIFTER_REGISTER(register_index) ((register_index) << 8) |
| | 257 | #define ENCODE_BARREL_SHIFTER_IMMEDIATE(value) ((value) << 7) |
| | 258 | |
| 251 | static void asm_block_data_transfer_opcode(TCCState *s1, int token) | 259 | static void asm_block_data_transfer_opcode(TCCState *s1, int token) |
| 252 | { | 260 | { |
| 253 | uint32_t opcode; | 261 | uint32_t opcode; |
| @@ -355,6 +363,52 @@ static void asm_block_data_transfer_opcode(TCCState *s1, int token) · 101 unmodified lines |
| 355 | } | 363 | } |
| 356 | } | 364 | } |
| 357 | | 365 | |
| | 366 | static uint32_t asm_encode_rotation(Operand* rotation) |
| | 367 | { |
| | 368 | uint64_t amount; |
| | 369 | switch (rotation->type) { |
| | 370 | case OP_REG32: |
| | 371 | tcc_error("cannot rotate immediate value by register"); |
| | 372 | return 0; |
| | 373 | case OP_IM8: |
| | 374 | amount = rotation->e.v; |
| | 375 | if (amount >= 0 && amount < 32 && (amount & 1) == 0) |
| | 376 | return (amount >> 1) << 8; |
| | 377 | else |
| | 378 | tcc_error("rotating is only possible by a multiple of 2"); |
| | 379 | break; |
| | 380 | default: |
| | 381 | tcc_error("unknown rotation amount"); |
| | 382 | return 0; |
| | 383 | } |
| | 384 | } |
| | 385 | |
| | 386 | static uint32_t asm_encode_shift(Operand* shift) |
| | 387 | { |
| | 388 | uint64_t amount; |
| | 389 | uint32_t operands = 0; |
| | 390 | switch (shift->type) { |
| | 391 | case OP_REG32: |
| | 392 | if (shift->reg == 15) |
| | 393 | tcc_error("r15 cannot be used as a shift count"); |
| | 394 | else { |
| | 395 | operands = ENCODE_BARREL_SHIFTER_SHIFT_BY_REGISTER; |
| | 396 | operands |= ENCODE_BARREL_SHIFTER_REGISTER(shift->reg); |
| | 397 | } |
| | 398 | break; |
| | 399 | case OP_IM8: |
| | 400 | amount = shift->e.v; |
| | 401 | if (amount > 0 && amount < 32) |
| | 402 | operands = ENCODE_BARREL_SHIFTER_IMMEDIATE(amount); |
| | 403 | else |
| | 404 | tcc_error("shift count out of range"); |
| | 405 | break; |
| | 406 | default: |
| | 407 | tcc_error("unknown shift amount"); |
| | 408 | } |
| | 409 | return operands; |
| | 410 | } |
| | 411 | |
| 358 | static void asm_data_processing_opcode(TCCState *s1, int token) | 412 | static void asm_data_processing_opcode(TCCState *s1, int token) |
| 359 | { | 413 | { |
| 360 | Operand ops[3]; | 414 | Operand ops[3]; |
| @@ -486,6 +540,102 @@ static void asm_data_processing_opcode(TCCState *s1, int token) · 125 unmodified lines |
| 486 | } | 540 | } |
| 487 | } | 541 | } |
| 488 | | 542 | |
| | 543 | static void asm_shift_opcode(TCCState *s1, int token) |
| | 544 | { |
| | 545 | Operand ops[3]; |
| | 546 | int nb_ops; |
| | 547 | uint32_t opcode = 0xd << 21; // MOV |
| | 548 | uint32_t operands = 0; |
| | 549 | |
| | 550 | for (nb_ops = 0; nb_ops < sizeof(ops)/sizeof(ops[0]); ++nb_ops) { |
| | 551 | parse_operand(s1, &ops[nb_ops]); |
| | 552 | if (tok != ',') { |
| | 553 | ++nb_ops; |
| | 554 | break; |
| | 555 | } |
| | 556 | next(); // skip ',' |
| | 557 | } |
| | 558 | if (nb_ops < 2) { |
| | 559 | expect("at least two operands"); |
| | 560 | return; |
| | 561 | } |
| | 562 | |
| | 563 | if (ops[0].type != OP_REG32) |
| | 564 | expect("(destination operand) register"); |
| | 565 | else |
| | 566 | operands |= ENCODE_RD(ops[0].reg); |
| | 567 | |
| | 568 | if (nb_ops == 2) { |
| | 569 | switch (ARM_INSTRUCTION_GROUP(token)) { |
| | 570 | case TOK_ASM_rrxseq: |
| | 571 | opcode |= ENCODE_SET_CONDITION_CODES; |
| | 572 | /* fallthrough */ |
| | 573 | case TOK_ASM_rrxeq: |
| | 574 | if (ops[1].type == OP_REG32) { |
| | 575 | operands |= ops[1].reg; |
| | 576 | operands |= ENCODE_BARREL_SHIFTER_MODE_ROR; |
| | 577 | asm_emit_opcode(token, opcode | operands); |
| | 578 | } else |
| | 579 | tcc_error("(first source operand) register"); |
| | 580 | return; |
| | 581 | default: |
| | 582 | memcpy(&ops[2], &ops[1], sizeof(ops[1])); // move ops[2] |
| | 583 | memcpy(&ops[1], &ops[0], sizeof(ops[0])); // ops[1] was implicit |
| | 584 | nb_ops = 3; |
| | 585 | } |
| | 586 | } |
| | 587 | if (nb_ops != 3) { |
| | 588 | expect("two or three operands"); |
| | 589 | return; |
| | 590 | } |
| | 591 | |
| | 592 | switch (ops[1].type) { |
| | 593 | case OP_REG32: |
| | 594 | operands |= ops[1].reg; |
| | 595 | break; |
| | 596 | case OP_IM8: |
| | 597 | operands |= ENCODE_IMMEDIATE_FLAG; |
| | 598 | operands |= ops[1].e.v; |
| | 599 | break; |
| | 600 | } |
| | 601 | |
| | 602 | if (operands & ENCODE_IMMEDIATE_FLAG) |
| | 603 | operands |= asm_encode_rotation(&ops[2]); |
| | 604 | else |
| | 605 | operands |= asm_encode_shift(&ops[2]); |
| | 606 | |
| | 607 | switch (ARM_INSTRUCTION_GROUP(token)) { |
| | 608 | case TOK_ASM_lslseq: |
| | 609 | opcode |= ENCODE_SET_CONDITION_CODES; |
| | 610 | /* fallthrough */ |
| | 611 | case TOK_ASM_lsleq: |
| | 612 | operands |= ENCODE_BARREL_SHIFTER_MODE_LSL; |
| | 613 | break; |
| | 614 | case TOK_ASM_lsrseq: |
| | 615 | opcode |= ENCODE_SET_CONDITION_CODES; |
| | 616 | /* fallthrough */ |
| | 617 | case TOK_ASM_lsreq: |
| | 618 | operands |= ENCODE_BARREL_SHIFTER_MODE_LSR; |
| | 619 | break; |
| | 620 | case TOK_ASM_asrseq: |
| | 621 | opcode |= ENCODE_SET_CONDITION_CODES; |
| | 622 | /* fallthrough */ |
| | 623 | case TOK_ASM_asreq: |
| | 624 | operands |= ENCODE_BARREL_SHIFTER_MODE_ASR; |
| | 625 | break; |
| | 626 | case TOK_ASM_rorseq: |
| | 627 | opcode |= ENCODE_SET_CONDITION_CODES; |
| | 628 | /* fallthrough */ |
| | 629 | case TOK_ASM_roreq: |
| | 630 | operands |= ENCODE_BARREL_SHIFTER_MODE_ROR; |
| | 631 | break; |
| | 632 | default: |
| | 633 | expect("shift instruction"); |
| | 634 | return; |
| | 635 | } |
| | 636 | asm_emit_opcode(token, opcode | operands); |
| | 637 | } |
| | 638 | |
| 489 | static void asm_multiplication_opcode(TCCState *s1, int token) | 639 | static void asm_multiplication_opcode(TCCState *s1, int token) |
| 490 | { | 640 | { |
| 491 | Operand ops[4]; | 641 | Operand ops[4]; |
| @@ -902,6 +1052,18 @@ ST_FUNC void asm_opcode(TCCState *s1, int token) · 410 unmodified lines |
| 902 | case TOK_ASM_mvnseq: | 1052 | case TOK_ASM_mvnseq: |
| 903 | return asm_data_processing_opcode(s1, token); | 1053 | return asm_data_processing_opcode(s1, token); |
| 904 | | 1054 | |
| | 1055 | case TOK_ASM_lsleq: |
| | 1056 | case TOK_ASM_lslseq: |
| | 1057 | case TOK_ASM_lsreq: |
| | 1058 | case TOK_ASM_lsrseq: |
| | 1059 | case TOK_ASM_asreq: |
| | 1060 | case TOK_ASM_asrseq: |
| | 1061 | case TOK_ASM_roreq: |
| | 1062 | case TOK_ASM_rorseq: |
| | 1063 | case TOK_ASM_rrxseq: |
| | 1064 | case TOK_ASM_rrxeq: |
| | 1065 | return asm_shift_opcode(s1, token); |
| | 1066 | |
| 905 | case TOK_ASM_muleq: | 1067 | case TOK_ASM_muleq: |
| 906 | case TOK_ASM_mulseq: | 1068 | case TOK_ASM_mulseq: |
| 907 | case TOK_ASM_mlaeq: | 1069 | case TOK_ASM_mlaeq: |