2 * ARM specific functions for TCC assembler
4 * Copyright (c) 2001, 2002 Fabrice Bellard
5 * Copyright (c) 2020 Danny Milosavljevic
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #ifdef TARGET_DEFS_ONLY
24 #define CONFIG_TCC_ASM
25 #define NB_ASM_REGS 16
27 ST_FUNC
void g(int c
);
28 ST_FUNC
void gen_le16(int c
);
29 ST_FUNC
void gen_le32(int c
);
31 /*************************************************************/
33 /*************************************************************/
45 #define OP_REG32 (1 << OPT_REG32)
46 #define OP_REG (OP_REG32)
47 #define OP_IM32 (1 << OPT_IM32)
48 #define OP_IM8 (1 << OPT_IM8)
49 #define OP_IM8N (1 << OPT_IM8N)
50 #define OP_REGSET32 (1 << OPT_REGSET32)
52 typedef struct Operand
{
61 /* Parse a text containing operand and store the result in OP */
62 static void parse_operand(TCCState
*s1
, Operand
*op
)
70 if (tok
== '{') { // regset literal
72 while (tok
!= '}' && tok
!= TOK_EOF
) {
73 reg
= asm_parse_regvar(tok
);
78 next(); // skip register name
80 if ((1 << reg
) < regset
)
81 tcc_warning("registers will be processed in ascending order by hardware--but are not specified in ascending order here");
91 // ARM instructions don't support empty regset.
92 tcc_error("empty register list is not supported");
94 op
->type
= OP_REGSET32
;
97 } else if (tok
== '#' || tok
== '$') {
99 next(); // skip '#' or '$'
104 if ((int) op
->e
.v
< 0 && (int) op
->e
.v
>= -255)
106 else if (op
->e
.v
== (uint8_t)op
->e
.v
)
110 } else if ((reg
= asm_parse_regvar(tok
)) != -1) {
111 next(); // skip register name
113 op
->reg
= (uint8_t) reg
;
118 /* XXX: make it faster ? */
119 ST_FUNC
void g(int c
)
125 if (ind1
> cur_text_section
->data_allocated
)
126 section_realloc(cur_text_section
, ind1
);
127 cur_text_section
->data
[ind
] = c
;
131 ST_FUNC
void gen_le16 (int i
)
137 ST_FUNC
void gen_le32 (int i
)
143 if (ind1
> cur_text_section
->data_allocated
)
144 section_realloc(cur_text_section
, ind1
);
145 cur_text_section
->data
[ind
++] = i
& 0xFF;
146 cur_text_section
->data
[ind
++] = (i
>> 8) & 0xFF;
147 cur_text_section
->data
[ind
++] = (i
>> 16) & 0xFF;
148 cur_text_section
->data
[ind
++] = (i
>> 24) & 0xFF;
151 ST_FUNC
void gen_expr32(ExprValue
*pe
)
156 static uint32_t condition_code_of_token(int token
) {
157 if (token
< TOK_ASM_nopeq
) {
158 expect("instruction");
161 return (token
- TOK_ASM_nopeq
) & 15;
164 static void asm_emit_opcode(int token
, uint32_t opcode
) {
165 gen_le32((condition_code_of_token(token
) << 28) | opcode
);
168 static void asm_nullary_opcode(int token
)
170 switch (ARM_INSTRUCTION_GROUP(token
)) {
172 asm_emit_opcode(token
, 0xd << 21); // mov r0, r0
175 asm_emit_opcode(token
, 0x320f002);
177 asm_emit_opcode(token
, 0x320f003);
180 expect("nullary instruction");
184 static void asm_unary_opcode(TCCState
*s1
, int token
)
187 parse_operand(s1
, &op
);
189 switch (ARM_INSTRUCTION_GROUP(token
)) {
191 if (op
.type
!= OP_IM8
)
192 expect("immediate 8-bit unsigned integer");
194 /* Note: Dummy operand (ignored by processor): ARM ref documented 0...255, ARM instruction set documented 24 bit */
195 asm_emit_opcode(token
, (0xf << 24) | op
.e
.v
);
199 expect("unary instruction");
203 static void asm_binary_opcode(TCCState
*s1
, int token
)
207 uint32_t encoded_rotation
= 0;
209 parse_operand(s1
, &ops
[0]);
214 parse_operand(s1
, &ops
[1]);
215 if (ops
[0].type
!= OP_REG32
) {
216 expect("(destination operand) register");
220 if (ops
[0].reg
== 15) {
221 tcc_error("'%s' does not support 'pc' as operand", get_tok_str(token
, NULL
));
225 if (ops
[0].reg
== 13)
226 tcc_warning("Using 'sp' as operand with '%s' is deprecated by ARM", get_tok_str(token
, NULL
));
228 if (ops
[1].type
!= OP_REG32
) {
229 switch (ARM_INSTRUCTION_GROUP(token
)) {
232 if (ops
[1].type
== OP_IM8
|| ops
[1].type
== OP_IM8N
|| ops
[1].type
== OP_IM32
) {
233 if (ops
[1].e
.v
>= 0 && ops
[1].e
.v
<= 0xFFFF) {
234 uint16_t immediate_value
= ops
[1].e
.v
;
235 switch (ARM_INSTRUCTION_GROUP(token
)) {
237 asm_emit_opcode(token
, 0x3400000 | (ops
[0].reg
<< 12) | (immediate_value
& 0xF000) << 4 | (immediate_value
& 0xFFF));
240 asm_emit_opcode(token
, 0x3000000 | (ops
[0].reg
<< 12) | (immediate_value
& 0xF000) << 4 | (immediate_value
& 0xFFF));
244 expect("(source operand) immediate 16 bit value");
246 expect("(source operand) immediate");
249 expect("(source operand) register");
254 if (ops
[1].reg
== 15) {
255 tcc_error("'%s' does not support 'pc' as operand", get_tok_str(token
, NULL
));
259 if (ops
[1].reg
== 13)
260 tcc_warning("Using 'sp' as operand with '%s' is deprecated by ARM", get_tok_str(token
, NULL
));
264 if (tok
== TOK_ASM_ror
) {
265 next(); // skip 'ror'
266 parse_operand(s1
, &rotation
);
267 if (rotation
.type
!= OP_IM8
) {
268 expect("immediate value for rotation");
271 amount
= rotation
.e
.v
;
274 encoded_rotation
= 1 << 10;
277 encoded_rotation
= 2 << 10;
280 encoded_rotation
= 3 << 10;
283 expect("'8' or '16' or '24'");
289 switch (ARM_INSTRUCTION_GROUP(token
)) {
291 if (encoded_rotation
)
292 tcc_error("clz does not support rotation");
293 asm_emit_opcode(token
, 0x16f0f10 | (ops
[0].reg
<< 12) | ops
[1].reg
);
296 asm_emit_opcode(token
, 0x6af0070 | (ops
[0].reg
<< 12) | ops
[1].reg
| encoded_rotation
);
299 asm_emit_opcode(token
, 0x6bf0070 | (ops
[0].reg
<< 12) | ops
[1].reg
| encoded_rotation
);
302 asm_emit_opcode(token
, 0x6ef0070 | (ops
[0].reg
<< 12) | ops
[1].reg
| encoded_rotation
);
305 asm_emit_opcode(token
, 0x6ff0070 | (ops
[0].reg
<< 12) | ops
[1].reg
| encoded_rotation
);
308 expect("binary instruction");
312 /* data processing and single data transfer instructions only */
313 #define ENCODE_RN(register_index) ((register_index) << 16)
314 #define ENCODE_RD(register_index) ((register_index) << 12)
315 #define ENCODE_SET_CONDITION_CODES (1 << 20)
317 /* Note: For data processing instructions, "1" means immediate.
318 Note: For single data transfer instructions, "0" means immediate. */
319 #define ENCODE_IMMEDIATE_FLAG (1 << 25)
321 #define ENCODE_BARREL_SHIFTER_SHIFT_BY_REGISTER (1 << 4)
322 #define ENCODE_BARREL_SHIFTER_MODE_LSL (0 << 5)
323 #define ENCODE_BARREL_SHIFTER_MODE_LSR (1 << 5)
324 #define ENCODE_BARREL_SHIFTER_MODE_ASR (2 << 5)
325 #define ENCODE_BARREL_SHIFTER_MODE_ROR (3 << 5)
326 #define ENCODE_BARREL_SHIFTER_REGISTER(register_index) ((register_index) << 8)
327 #define ENCODE_BARREL_SHIFTER_IMMEDIATE(value) ((value) << 7)
329 static void asm_block_data_transfer_opcode(TCCState
*s1
, int token
)
335 parse_operand(s1
, &ops
[0]);
341 next(); // skip comma
342 parse_operand(s1
, &ops
[1]);
346 expect("at least one operand");
348 } else if (ops
[nb_ops
- 1].type
!= OP_REGSET32
) {
349 expect("(last operand) register list");
353 // block data transfer: 1 0 0 P U S W L << 20 (general case):
355 // Rn: bits 19...16 base register
356 // Register List: bits 15...0
358 switch (ARM_INSTRUCTION_GROUP(token
)) {
359 case TOK_ASM_pusheq
: // TODO: Optimize 1-register case to: str ?, [sp, #-4]!
360 // Instruction: 1 I=0 P=1 U=0 S=0 W=1 L=0 << 20, op 1101
363 // Register List: bits 15...0
365 expect("exactly one operand");
367 asm_emit_opcode(token
, (0x92d << 16) | ops
[0].regset
); // TODO: base register ?
369 case TOK_ASM_popeq
: // TODO: Optimize 1-register case to: ldr ?, [sp], #4
370 // Instruction: 1 I=0 P=0 U=1 S=0 W=0 L=1 << 20, op 1101
373 // Register List: bits 15...0
375 expect("exactly one operand");
377 asm_emit_opcode(token
, (0x8bd << 16) | ops
[0].regset
); // TODO: base register ?
379 case TOK_ASM_stmdaeq
:
380 case TOK_ASM_ldmdaeq
:
383 case TOK_ASM_stmiaeq
:
384 case TOK_ASM_ldmiaeq
:
385 case TOK_ASM_stmdbeq
:
386 case TOK_ASM_ldmdbeq
:
387 case TOK_ASM_stmibeq
:
388 case TOK_ASM_ldmibeq
:
389 switch (ARM_INSTRUCTION_GROUP(token
)) {
390 case TOK_ASM_stmdaeq
: // post-decrement store
393 case TOK_ASM_ldmdaeq
: // post-decrement load
396 case TOK_ASM_stmeq
: // post-increment store
397 case TOK_ASM_stmiaeq
: // post-increment store
400 case TOK_ASM_ldmeq
: // post-increment load
401 case TOK_ASM_ldmiaeq
: // post-increment load
404 case TOK_ASM_stmdbeq
: // pre-decrement store
407 case TOK_ASM_ldmdbeq
: // pre-decrement load
410 case TOK_ASM_stmibeq
: // pre-increment store
413 case TOK_ASM_ldmibeq
: // pre-increment load
417 tcc_error("internal error: This place should not be reached (fallback in asm_block_data_transfer_opcode)");
421 // Register List: lower bits
423 expect("exactly two operands");
424 else if (ops
[0].type
!= OP_REG32
)
425 expect("(first operand) register");
428 opcode
|= 1 << 21; // writeback
429 asm_emit_opcode(token
, opcode
| ENCODE_RN(ops
[0].reg
) | ops
[1].regset
);
433 expect("block data transfer instruction");
437 /* Parses shift directive and returns the parts that would have to be set in the opcode because of it.
438 Does not encode the actual shift amount.
439 It's not an error if there is no shift directive.
441 NB_SHIFT: will be set to 1 iff SHIFT is filled. Note that for rrx, there's no need to fill SHIFT.
442 SHIFT: will be filled in with the shift operand to use, if any. */
443 static uint32_t asm_parse_optional_shift(TCCState
* s1
, int* nb_shift
, Operand
* shift
)
457 opcode
= ENCODE_BARREL_SHIFTER_MODE_LSL
;
460 opcode
= ENCODE_BARREL_SHIFTER_MODE_ASR
;
463 opcode
= ENCODE_BARREL_SHIFTER_MODE_LSR
;
466 opcode
= ENCODE_BARREL_SHIFTER_MODE_ROR
;
470 parse_operand(s1
, shift
);
475 opcode
= ENCODE_BARREL_SHIFTER_MODE_ROR
;
481 static uint32_t asm_encode_shift(Operand
* shift
)
484 uint32_t operands
= 0;
485 switch (shift
->type
) {
487 if (shift
->reg
== 15)
488 tcc_error("r15 cannot be used as a shift count");
490 operands
= ENCODE_BARREL_SHIFTER_SHIFT_BY_REGISTER
;
491 operands
|= ENCODE_BARREL_SHIFTER_REGISTER(shift
->reg
);
496 if (amount
> 0 && amount
< 32)
497 operands
= ENCODE_BARREL_SHIFTER_IMMEDIATE(amount
);
499 tcc_error("shift count out of range");
502 tcc_error("unknown shift amount");
507 static void asm_data_processing_opcode(TCCState
*s1
, int token
)
513 uint32_t operands
= 0;
515 /* modulo 16 entries per instruction for the different condition codes */
516 uint32_t opcode_idx
= (ARM_INSTRUCTION_GROUP(token
) - TOK_ASM_andeq
) >> 4;
517 uint32_t opcode_nos
= opcode_idx
>> 1; // without "s"; "OpCode" in ARM docs
519 for (nb_ops
= 0; nb_ops
< sizeof(ops
)/sizeof(ops
[0]); ) {
520 if (tok
== TOK_ASM_asl
|| tok
== TOK_ASM_lsl
|| tok
== TOK_ASM_lsr
|| tok
== TOK_ASM_asr
|| tok
== TOK_ASM_ror
|| tok
== TOK_ASM_rrx
)
522 parse_operand(s1
, &ops
[nb_ops
]);
530 operands
|= asm_parse_optional_shift(s1
, &nb_shift
, &shift
);
532 expect("at least two operands");
533 else if (nb_ops
== 2) {
534 memcpy(&ops
[2], &ops
[1], sizeof(ops
[1])); // move ops[2]
535 memcpy(&ops
[1], &ops
[0], sizeof(ops
[0])); // ops[1] was implicit
537 } else if (nb_ops
== 3) {
538 if (opcode_nos
== 0xd || opcode_nos
== 0xf || opcode_nos
== 0xa || opcode_nos
== 0xb || opcode_nos
== 0x8 || opcode_nos
== 0x9) { // mov, mvn, cmp, cmn, tst, teq
539 tcc_error("'%s' cannot be used with three operands", get_tok_str(token
, NULL
));
544 expect("two or three operands");
548 uint32_t immediate_value
;
549 uint8_t half_immediate_rotation
;
550 if (nb_shift
&& shift
.type
== OP_REG32
) {
551 if ((ops
[0].type
== OP_REG32
&& ops
[0].reg
== 15) ||
552 (ops
[1].type
== OP_REG32
&& ops
[1].reg
== 15)) {
553 tcc_error("Using the 'pc' register in data processing instructions that have a register-controlled shift is not implemented by ARM");
558 // data processing (general case):
560 // Rn: bits 19...16 (first operand)
561 // Rd: bits 15...12 (destination)
562 // Operand2: bits 11...0 (second operand); depending on I that's either a register or an immediate
564 // bits 24...21: "OpCode"--see below
566 /* operations in the token list are ordered by opcode */
567 opcode
= opcode_nos
<< 21; // drop "s"
568 if (ops
[0].type
!= OP_REG32
)
569 expect("(destination operand) register");
570 else if (opcode_nos
== 0xa || opcode_nos
== 0xb || opcode_nos
== 0x8 || opcode_nos
== 0x9) // cmp, cmn, tst, teq
571 operands
|= ENCODE_SET_CONDITION_CODES
; // force S set, otherwise it's a completely different instruction.
573 operands
|= ENCODE_RD(ops
[0].reg
);
574 if (ops
[1].type
!= OP_REG32
)
575 expect("(first source operand) register");
576 else if (!(opcode_nos
== 0xd || opcode_nos
== 0xf)) // not: mov, mvn (those have only one source operand)
577 operands
|= ENCODE_RN(ops
[1].reg
);
578 switch (ops
[2].type
) {
580 operands
|= ops
[2].reg
;
584 operands
|= ENCODE_IMMEDIATE_FLAG
;
585 immediate_value
= ops
[2].e
.v
;
586 for (half_immediate_rotation
= 0; half_immediate_rotation
< 16; ++half_immediate_rotation
) {
587 if (immediate_value
>= 0x00 && immediate_value
< 0x100)
589 // rotate left by two
590 immediate_value
= ((immediate_value
& 0x3FFFFFFF) << 2) | ((immediate_value
& 0xC0000000) >> 30);
592 if (half_immediate_rotation
>= 16) {
595 operands
|= immediate_value
;
596 operands
|= half_immediate_rotation
<< 8;
599 case OP_IM8N
: // immediate negative value
600 operands
|= ENCODE_IMMEDIATE_FLAG
;
601 immediate_value
= ops
[2].e
.v
;
602 /* Instruction swapping:
603 0001 = EOR - Rd:= Op1 EOR Op2 -> difficult
604 0011 = RSB - Rd:= Op2 - Op1 -> difficult
605 0111 = RSC - Rd:= Op2 - Op1 + C -> difficult
606 1000 = TST - CC on: Op1 AND Op2 -> difficult
607 1001 = TEQ - CC on: Op1 EOR Op2 -> difficult
608 1100 = ORR - Rd:= Op1 OR Op2 -> difficult
610 switch (opcode_nos
) {
611 case 0x0: // AND - Rd:= Op1 AND Op2
612 opcode
= 0xe << 21; // BIC
613 immediate_value
= ~immediate_value
;
615 case 0x2: // SUB - Rd:= Op1 - Op2
616 opcode
= 0x4 << 21; // ADD
617 immediate_value
= -immediate_value
;
619 case 0x4: // ADD - Rd:= Op1 + Op2
620 opcode
= 0x2 << 21; // SUB
621 immediate_value
= -immediate_value
;
623 case 0x5: // ADC - Rd:= Op1 + Op2 + C
624 opcode
= 0x6 << 21; // SBC
625 immediate_value
= ~immediate_value
;
627 case 0x6: // SBC - Rd:= Op1 - Op2 + C
628 opcode
= 0x5 << 21; // ADC
629 immediate_value
= ~immediate_value
;
631 case 0xa: // CMP - CC on: Op1 - Op2
632 opcode
= 0xb << 21; // CMN
633 immediate_value
= -immediate_value
;
635 case 0xb: // CMN - CC on: Op1 + Op2
636 opcode
= 0xa << 21; // CMP
637 immediate_value
= -immediate_value
;
639 case 0xd: // MOV - Rd:= Op2
640 opcode
= 0xf << 21; // MVN
641 immediate_value
= ~immediate_value
;
643 case 0xe: // BIC - Rd:= Op1 AND NOT Op2
644 opcode
= 0x0 << 21; // AND
645 immediate_value
= ~immediate_value
;
647 case 0xf: // MVN - Rd:= NOT Op2
648 opcode
= 0xd << 21; // MOV
649 immediate_value
= ~immediate_value
;
652 tcc_error("cannot use '%s' with a negative immediate value", get_tok_str(token
, NULL
));
654 for (half_immediate_rotation
= 0; half_immediate_rotation
< 16; ++half_immediate_rotation
) {
655 if (immediate_value
>= 0x00 && immediate_value
< 0x100)
657 // rotate left by two
658 immediate_value
= ((immediate_value
& 0x3FFFFFFF) << 2) | ((immediate_value
& 0xC0000000) >> 30);
660 if (half_immediate_rotation
>= 16) {
661 immediate_value
= ops
[2].e
.v
;
662 tcc_error("immediate value 0x%X cannot be encoded into ARM immediate", (unsigned) immediate_value
);
665 operands
|= immediate_value
;
666 operands
|= half_immediate_rotation
<< 8;
669 expect("(second source operand) register or immediate value");
673 if (operands
& ENCODE_IMMEDIATE_FLAG
)
674 tcc_error("immediate rotation not implemented");
676 operands
|= asm_encode_shift(&shift
);
679 /* S=0 and S=1 entries alternate one after another, in that order */
680 opcode
|= (opcode_idx
& 1) ? ENCODE_SET_CONDITION_CODES
: 0;
681 asm_emit_opcode(token
, opcode
| operands
);
685 static void asm_shift_opcode(TCCState
*s1
, int token
)
689 int definitely_neutral
= 0;
690 uint32_t opcode
= 0xd << 21; // MOV
691 uint32_t operands
= 0;
693 for (nb_ops
= 0; nb_ops
< sizeof(ops
)/sizeof(ops
[0]); ++nb_ops
) {
694 parse_operand(s1
, &ops
[nb_ops
]);
702 expect("at least two operands");
706 if (ops
[0].type
!= OP_REG32
) {
707 expect("(destination operand) register");
710 operands
|= ENCODE_RD(ops
[0].reg
);
713 switch (ARM_INSTRUCTION_GROUP(token
)) {
715 opcode
|= ENCODE_SET_CONDITION_CODES
;
718 if (ops
[1].type
== OP_REG32
) {
719 operands
|= ops
[1].reg
;
720 operands
|= ENCODE_BARREL_SHIFTER_MODE_ROR
;
721 asm_emit_opcode(token
, opcode
| operands
);
723 tcc_error("(first source operand) register");
726 memcpy(&ops
[2], &ops
[1], sizeof(ops
[1])); // move ops[2]
727 memcpy(&ops
[1], &ops
[0], sizeof(ops
[0])); // ops[1] was implicit
732 expect("two or three operands");
736 switch (ARM_INSTRUCTION_GROUP(token
)) {
741 opcode
|= ENCODE_SET_CONDITION_CODES
;
745 switch (ops
[1].type
) {
747 operands
|= ops
[1].reg
;
750 operands
|= ENCODE_IMMEDIATE_FLAG
;
751 operands
|= ops
[1].e
.v
;
755 switch (ops
[2].type
) {
757 if ((ops
[0].type
== OP_REG32
&& ops
[0].reg
== 15) ||
758 (ops
[1].type
== OP_REG32
&& ops
[1].reg
== 15)) {
759 tcc_error("Using the 'pc' register in data processing instructions that have a register-controlled shift is not implemented by ARM");
761 operands
|= asm_encode_shift(&ops
[2]);
765 operands
|= asm_encode_shift(&ops
[2]);
767 definitely_neutral
= 1;
771 if (!definitely_neutral
) switch (ARM_INSTRUCTION_GROUP(token
)) {
774 operands
|= ENCODE_BARREL_SHIFTER_MODE_LSL
;
778 operands
|= ENCODE_BARREL_SHIFTER_MODE_LSR
;
782 operands
|= ENCODE_BARREL_SHIFTER_MODE_ASR
;
786 operands
|= ENCODE_BARREL_SHIFTER_MODE_ROR
;
789 expect("shift instruction");
792 asm_emit_opcode(token
, opcode
| operands
);
795 static void asm_multiplication_opcode(TCCState
*s1
, int token
)
799 uint32_t opcode
= 0x90;
801 for (nb_ops
= 0; nb_ops
< sizeof(ops
)/sizeof(ops
[0]); ++nb_ops
) {
802 parse_operand(s1
, &ops
[nb_ops
]);
810 expect("at least two operands");
811 else if (nb_ops
== 2) {
812 switch (ARM_INSTRUCTION_GROUP(token
)) {
815 memcpy(&ops
[2], &ops
[0], sizeof(ops
[1])); // ARM is actually like this!
818 expect("at least three operands");
824 // multiply (special case):
831 if (ops
[0].type
== OP_REG32
)
832 opcode
|= ops
[0].reg
<< 16;
834 expect("(destination operand) register");
835 if (ops
[1].type
== OP_REG32
)
836 opcode
|= ops
[1].reg
;
838 expect("(first source operand) register");
839 if (ops
[2].type
== OP_REG32
)
840 opcode
|= ops
[2].reg
<< 8;
842 expect("(second source operand) register");
844 if (ops
[3].type
== OP_REG32
)
845 opcode
|= ops
[3].reg
<< 12;
847 expect("(third source operand) register");
850 switch (ARM_INSTRUCTION_GROUP(token
)) {
852 opcode
|= 1 << 20; // Status
856 expect("three operands");
858 asm_emit_opcode(token
, opcode
);
862 opcode
|= 1 << 20; // Status
866 expect("four operands");
868 opcode
|= 1 << 21; // Accumulate
869 asm_emit_opcode(token
, opcode
);
873 expect("known multiplication instruction");
877 static void asm_long_multiplication_opcode(TCCState
*s1
, int token
)
881 uint32_t opcode
= 0x90 | (1 << 23);
883 for (nb_ops
= 0; nb_ops
< sizeof(ops
)/sizeof(ops
[0]); ++nb_ops
) {
884 parse_operand(s1
, &ops
[nb_ops
]);
892 expect("four operands");
896 // long multiply (special case):
898 // RdLo: bits 15...12
899 // RdHi: bits 19...16
903 if (ops
[0].type
== OP_REG32
)
904 opcode
|= ops
[0].reg
<< 12;
906 expect("(destination lo accumulator) register");
907 if (ops
[1].type
== OP_REG32
)
908 opcode
|= ops
[1].reg
<< 16;
910 expect("(destination hi accumulator) register");
911 if (ops
[2].type
== OP_REG32
)
912 opcode
|= ops
[2].reg
;
914 expect("(first source operand) register");
915 if (ops
[3].type
== OP_REG32
)
916 opcode
|= ops
[3].reg
<< 8;
918 expect("(second source operand) register");
920 switch (ARM_INSTRUCTION_GROUP(token
)) {
921 case TOK_ASM_smullseq
:
922 opcode
|= 1 << 20; // Status
924 case TOK_ASM_smulleq
:
925 opcode
|= 1 << 22; // signed
926 asm_emit_opcode(token
, opcode
);
928 case TOK_ASM_umullseq
:
929 opcode
|= 1 << 20; // Status
931 case TOK_ASM_umulleq
:
932 asm_emit_opcode(token
, opcode
);
934 case TOK_ASM_smlalseq
:
935 opcode
|= 1 << 20; // Status
937 case TOK_ASM_smlaleq
:
938 opcode
|= 1 << 22; // signed
939 opcode
|= 1 << 21; // Accumulate
940 asm_emit_opcode(token
, opcode
);
942 case TOK_ASM_umlalseq
:
943 opcode
|= 1 << 20; // Status
945 case TOK_ASM_umlaleq
:
946 opcode
|= 1 << 21; // Accumulate
947 asm_emit_opcode(token
, opcode
);
950 expect("known long multiplication instruction");
954 static void asm_single_data_transfer_opcode(TCCState
*s1
, int token
)
957 Operand strex_operand
;
961 int closed_bracket
= 0;
964 // Note: ldr r0, [r4, #4] ; simple offset: r0 = *(int*)(r4+4); r4 unchanged
965 // Note: ldr r0, [r4, #4]! ; pre-indexed: r0 = *(int*)(r4+4); r4 = r4+4
966 // Note: ldr r0, [r4], #4 ; post-indexed: r0 = *(int*)(r4+0); r4 = r4+4
968 parse_operand(s1
, &ops
[0]);
969 if (ops
[0].type
== OP_REG32
)
970 opcode
|= ENCODE_RD(ops
[0].reg
);
972 expect("(destination operand) register");
976 expect("at least two arguments");
980 switch (ARM_INSTRUCTION_GROUP(token
)) {
981 case TOK_ASM_strexbeq
:
982 case TOK_ASM_strexeq
:
983 parse_operand(s1
, &strex_operand
);
984 if (strex_operand
.type
!= OP_REG32
) {
989 expect("at least three arguments");
1000 parse_operand(s1
, &ops
[1]);
1001 if (ops
[1].type
== OP_REG32
)
1002 opcode
|= ENCODE_RN(ops
[1].reg
);
1004 expect("(first source operand) register");
1010 // exclam = 1; // implicit in hardware; don't do it in software
1018 parse_operand(s1
, &ops
[2]);
1019 if (ops
[2].type
== OP_REG32
) {
1020 if (ops
[2].reg
== 15) {
1021 tcc_error("Using 'pc' for register offset in '%s' is not implemented by ARM", get_tok_str(token
, NULL
));
1026 opcode
|= asm_parse_optional_shift(s1
, &nb_shift
, &shift
);
1028 expect("shift directive, or no comma");
1032 // end of input expression in brackets--assume 0 offset
1033 ops
[2].type
= OP_IM8
;
1035 opcode
|= 1 << 24; // add offset before transfer
1037 if (!closed_bracket
) {
1042 opcode
|= 1 << 24; // add offset before transfer
1049 // single data transfer: 0 1 I P U B W L << 20 (general case):
1051 // Rd: destination operand [ok]
1052 // Rn: first source operand [ok]
1053 // Operand2: bits 11...0 [ok]
1054 // I: immediate operand? [ok]
1055 // P: Pre/post indexing is PRE: Add offset before transfer [ok]
1056 // U: Up/down is up? (*adds* offset to base) [ok]
1057 // B: Byte/word is byte? TODO
1058 // W: Write address back into base? [ok]
1059 // L: Load/store is load? [ok]
1061 opcode
|= 1 << 21; // write offset back into register
1063 if (ops
[2].type
== OP_IM32
|| ops
[2].type
== OP_IM8
|| ops
[2].type
== OP_IM8N
) {
1066 tcc_error("minus before '#' not supported for immediate values");
1068 opcode
|= 1 << 23; // up
1070 tcc_error("offset out of range for '%s'", get_tok_str(token
, NULL
));
1075 tcc_error("offset out of range for '%s'", get_tok_str(token
, NULL
));
1079 } else if (ops
[2].type
== OP_REG32
) {
1081 opcode
|= 1 << 23; // up
1082 opcode
|= ENCODE_IMMEDIATE_FLAG
; /* if set, it means it's NOT immediate */
1083 opcode
|= ops
[2].reg
;
1087 switch (ARM_INSTRUCTION_GROUP(token
)) {
1088 case TOK_ASM_strbeq
:
1089 opcode
|= 1 << 22; // B
1092 opcode
|= 1 << 26; // Load/Store
1094 opcode
|= asm_encode_shift(&shift
);
1095 asm_emit_opcode(token
, opcode
);
1097 case TOK_ASM_ldrbeq
:
1098 opcode
|= 1 << 22; // B
1101 opcode
|= 1 << 20; // L
1102 opcode
|= 1 << 26; // Load/Store
1104 opcode
|= asm_encode_shift(&shift
);
1105 asm_emit_opcode(token
, opcode
);
1107 case TOK_ASM_strexbeq
:
1108 opcode
|= 1 << 22; // B
1110 case TOK_ASM_strexeq
:
1111 if ((opcode
& 0xFFF) || nb_shift
) {
1112 tcc_error("neither offset nor shift allowed with 'strex'");
1114 } else if (opcode
& ENCODE_IMMEDIATE_FLAG
) { // if set, it means it's NOT immediate
1115 tcc_error("offset not allowed with 'strex'");
1118 if ((opcode
& (1 << 24)) == 0) { // add offset after transfer
1119 tcc_error("adding offset after transfer not allowed with 'strex'");
1123 opcode
|= 0xf90; // Used to mean: barrel shifter is enabled, barrel shift register is r15, mode is LSL
1124 opcode
|= strex_operand
.reg
;
1125 asm_emit_opcode(token
, opcode
);
1127 case TOK_ASM_ldrexbeq
:
1128 opcode
|= 1 << 22; // B
1130 case TOK_ASM_ldrexeq
:
1131 if ((opcode
& 0xFFF) || nb_shift
) {
1132 tcc_error("neither offset nor shift allowed with 'ldrex'");
1134 } else if (opcode
& ENCODE_IMMEDIATE_FLAG
) { // if set, it means it's NOT immediate
1135 tcc_error("offset not allowed with 'ldrex'");
1138 if ((opcode
& (1 << 24)) == 0) { // add offset after transfer
1139 tcc_error("adding offset after transfer not allowed with 'ldrex'");
1142 opcode
|= 1 << 20; // L
1144 opcode
|= 0xf90; // Used to mean: barrel shifter is enabled, barrel shift register is r15, mode is LSL
1145 asm_emit_opcode(token
, opcode
);
1148 expect("data transfer instruction");
1152 static void asm_misc_single_data_transfer_opcode(TCCState
*s1
, int token
)
1156 int closed_bracket
= 0;
1158 uint32_t opcode
= (1 << 7) | (1 << 4);
1161 The argument syntax is exactly the same as in arm_single_data_transfer_opcode, except that there's no STREX argument form.
1162 The main difference between this function and asm_misc_single_data_transfer_opcode is that the immediate values here must be smaller.
1163 Also, the combination (P=0, W=1) is unpredictable here.
1164 The immediate flag has moved to bit index 22--and its meaning has flipped.
1165 The immediate value itself has been split into two parts: one at bits 11...8, one at bits 3...0
1166 bit 26 (Load/Store instruction) is unset here.
1167 bits 7 and 4 are set here. */
1169 // Here: 0 0 0 P U I W L << 20
1170 // [compare single data transfer: 0 1 I P U B W L << 20]
1172 parse_operand(s1
, &ops
[0]);
1173 if (ops
[0].type
== OP_REG32
)
1174 opcode
|= ENCODE_RD(ops
[0].reg
);
1176 expect("(destination operand) register");
1180 expect("at least two arguments");
1189 parse_operand(s1
, &ops
[1]);
1190 if (ops
[1].type
== OP_REG32
)
1191 opcode
|= ENCODE_RN(ops
[1].reg
);
1193 expect("(first source operand) register");
1199 // exclam = 1; // implicit in hardware; don't do it in software
1207 parse_operand(s1
, &ops
[2]);
1209 // end of input expression in brackets--assume 0 offset
1210 ops
[2].type
= OP_IM8
;
1212 opcode
|= 1 << 24; // add offset before transfer
1214 if (!closed_bracket
) {
1219 opcode
|= 1 << 24; // add offset before transfer
1227 if ((opcode
& (1 << 24)) == 0) {
1228 tcc_error("result of '%s' would be unpredictable here", get_tok_str(token
, NULL
));
1231 opcode
|= 1 << 21; // write offset back into register
1234 if (ops
[2].type
== OP_IM32
|| ops
[2].type
== OP_IM8
|| ops
[2].type
== OP_IM8N
) {
1237 tcc_error("minus before '#' not supported for immediate values");
1239 opcode
|= 1 << 23; // up
1241 tcc_error("offset out of range for '%s'", get_tok_str(token
, NULL
));
1243 // bits 11...8: immediate hi nibble
1244 // bits 3...0: immediate lo nibble
1245 opcode
|= (v
& 0xF0) << 4;
1250 tcc_error("offset out of range for '%s'", get_tok_str(token
, NULL
));
1253 // bits 11...8: immediate hi nibble
1254 // bits 3...0: immediate lo nibble
1255 opcode
|= (v
& 0xF0) << 4;
1259 opcode
|= 1 << 22; // not ENCODE_IMMEDIATE_FLAG;
1260 } else if (ops
[2].type
== OP_REG32
) {
1262 opcode
|= 1 << 23; // up
1263 opcode
|= ops
[2].reg
;
1267 switch (ARM_INSTRUCTION_GROUP(token
)) {
1268 case TOK_ASM_ldrsheq
:
1269 opcode
|= 1 << 5; // halfword, not byte
1271 case TOK_ASM_ldrsbeq
:
1272 opcode
|= 1 << 6; // sign extend
1273 opcode
|= 1 << 20; // L
1274 asm_emit_opcode(token
, opcode
);
1276 case TOK_ASM_ldrheq
:
1277 opcode
|= 1 << 5; // halfword, not byte
1278 opcode
|= 1 << 20; // L
1279 asm_emit_opcode(token
, opcode
);
1281 case TOK_ASM_strheq
:
1282 opcode
|= 1 << 5; // halfword, not byte
1283 asm_emit_opcode(token
, opcode
);
1288 /* Note: almost dupe of encbranch in arm-gen.c */
1289 static uint32_t encbranchoffset(int pos
, int addr
, int fail
)
1293 if(addr
>=0x7fffff || addr
<-0x800000) {
1295 tcc_error("branch offset is too far");
1298 return /*not 0x0A000000|*/(addr
&0xffffff);
1301 static void asm_branch_opcode(TCCState
*s1
, int token
)
1308 switch (ARM_INSTRUCTION_GROUP(token
)) {
1312 esym
= elfsym(e
.sym
);
1313 if (!esym
|| esym
->st_shndx
!= cur_text_section
->sh_num
) {
1314 tcc_error("invalid branch target");
1317 jmp_disp
= encbranchoffset(ind
, e
.v
+ esym
->st_value
, 1);
1320 parse_operand(s1
, &op
);
1323 switch (ARM_INSTRUCTION_GROUP(token
)) {
1325 asm_emit_opcode(token
, (0xa << 24) | (jmp_disp
& 0xffffff));
1328 asm_emit_opcode(token
, (0xb << 24) | (jmp_disp
& 0xffffff));
1331 if (op
.type
!= OP_REG32
)
1334 asm_emit_opcode(token
, (0x12fff1 << 4) | op
.reg
);
1337 if (op
.type
!= OP_REG32
)
1340 asm_emit_opcode(token
, (0x12fff3 << 4) | op
.reg
);
1343 expect("branch instruction");
1347 ST_FUNC
void asm_opcode(TCCState
*s1
, int token
)
1349 while (token
== TOK_LINEFEED
) {
1353 if (token
== TOK_EOF
)
1355 if (token
< TOK_ASM_nopeq
) {
1356 expect("instruction");
1360 switch (ARM_INSTRUCTION_GROUP(token
)) {
1361 case TOK_ASM_pusheq
:
1363 case TOK_ASM_stmdaeq
:
1364 case TOK_ASM_ldmdaeq
:
1367 case TOK_ASM_stmiaeq
:
1368 case TOK_ASM_ldmiaeq
:
1369 case TOK_ASM_stmdbeq
:
1370 case TOK_ASM_ldmdbeq
:
1371 case TOK_ASM_stmibeq
:
1372 case TOK_ASM_ldmibeq
:
1373 return asm_block_data_transfer_opcode(s1
, token
);
1377 return asm_nullary_opcode(token
);
1379 return asm_unary_opcode(s1
, token
);
1384 return asm_branch_opcode(s1
, token
);
1386 case TOK_ASM_sxtbeq
:
1387 case TOK_ASM_sxtheq
:
1388 case TOK_ASM_uxtbeq
:
1389 case TOK_ASM_uxtheq
:
1390 case TOK_ASM_movteq
:
1391 case TOK_ASM_movweq
:
1392 return asm_binary_opcode(s1
, token
);
1395 case TOK_ASM_ldrbeq
:
1397 case TOK_ASM_strbeq
:
1398 case TOK_ASM_ldrexeq
:
1399 case TOK_ASM_ldrexbeq
:
1400 case TOK_ASM_strexeq
:
1401 case TOK_ASM_strexbeq
:
1402 return asm_single_data_transfer_opcode(s1
, token
);
1404 case TOK_ASM_ldrheq
:
1405 case TOK_ASM_ldrsheq
:
1406 case TOK_ASM_ldrsbeq
:
1407 case TOK_ASM_strheq
:
1408 return asm_misc_single_data_transfer_opcode(s1
, token
);
1426 case TOK_ASM_andseq
:
1427 case TOK_ASM_eorseq
:
1428 case TOK_ASM_subseq
:
1429 case TOK_ASM_rsbseq
:
1430 case TOK_ASM_addseq
:
1431 case TOK_ASM_adcseq
:
1432 case TOK_ASM_sbcseq
:
1433 case TOK_ASM_rscseq
:
1434 // case TOK_ASM_tstseq:
1435 // case TOK_ASM_teqseq:
1436 // case TOK_ASM_cmpseq:
1437 // case TOK_ASM_cmnseq:
1438 case TOK_ASM_orrseq
:
1439 case TOK_ASM_movseq
:
1440 case TOK_ASM_bicseq
:
1441 case TOK_ASM_mvnseq
:
1442 return asm_data_processing_opcode(s1
, token
);
1445 case TOK_ASM_lslseq
:
1447 case TOK_ASM_lsrseq
:
1449 case TOK_ASM_asrseq
:
1451 case TOK_ASM_rorseq
:
1452 case TOK_ASM_rrxseq
:
1454 return asm_shift_opcode(s1
, token
);
1457 case TOK_ASM_mulseq
:
1459 case TOK_ASM_mlaseq
:
1460 return asm_multiplication_opcode(s1
, token
);
1462 case TOK_ASM_smulleq
:
1463 case TOK_ASM_smullseq
:
1464 case TOK_ASM_umulleq
:
1465 case TOK_ASM_umullseq
:
1466 case TOK_ASM_smlaleq
:
1467 case TOK_ASM_smlalseq
:
1468 case TOK_ASM_umlaleq
:
1469 case TOK_ASM_umlalseq
:
1470 return asm_long_multiplication_opcode(s1
, token
);
1472 expect("known instruction");
1476 ST_FUNC
void subst_asm_operand(CString
*add_str
, SValue
*sv
, int modifier
)
1478 int r
, reg
, size
, val
;
1482 if ((r
& VT_VALMASK
) == VT_CONST
) {
1483 if (!(r
& VT_LVAL
) && modifier
!= 'c' && modifier
!= 'n' &&
1485 cstr_ccat(add_str
, '#');
1487 const char *name
= get_tok_str(sv
->sym
->v
, NULL
);
1488 if (sv
->sym
->v
>= SYM_FIRST_ANOM
) {
1489 /* In case of anonymous symbols ("L.42", used
1490 for static data labels) we can't find them
1491 in the C symbol table when later looking up
1492 this name. So enter them now into the asm label
1493 list when we still know the symbol. */
1494 get_asm_sym(tok_alloc(name
, strlen(name
))->tok
, sv
->sym
);
1496 if (tcc_state
->leading_underscore
)
1497 cstr_ccat(add_str
, '_');
1498 cstr_cat(add_str
, name
, -1);
1499 if ((uint32_t) sv
->c
.i
== 0)
1501 cstr_ccat(add_str
, '+');
1504 if (modifier
== 'n')
1506 snprintf(buf
, sizeof(buf
), "%d", (int) sv
->c
.i
);
1507 cstr_cat(add_str
, buf
, -1);
1509 } else if ((r
& VT_VALMASK
) == VT_LOCAL
) {
1510 snprintf(buf
, sizeof(buf
), "[fp,#%d]", (int) sv
->c
.i
);
1511 cstr_cat(add_str
, buf
, -1);
1512 } else if (r
& VT_LVAL
) {
1513 reg
= r
& VT_VALMASK
;
1514 if (reg
>= VT_CONST
)
1515 tcc_internal_error("");
1516 snprintf(buf
, sizeof(buf
), "[%s]",
1517 get_tok_str(TOK_ASM_r0
+ reg
, NULL
));
1518 cstr_cat(add_str
, buf
, -1);
1521 reg
= r
& VT_VALMASK
;
1522 if (reg
>= VT_CONST
)
1523 tcc_internal_error("");
1525 /* choose register operand size */
1526 if ((sv
->type
.t
& VT_BTYPE
) == VT_BYTE
||
1527 (sv
->type
.t
& VT_BTYPE
) == VT_BOOL
)
1529 else if ((sv
->type
.t
& VT_BTYPE
) == VT_SHORT
)
1534 if (modifier
== 'b') {
1536 } else if (modifier
== 'w') {
1538 } else if (modifier
== 'k') {
1544 reg
= TOK_ASM_r0
+ reg
;
1547 snprintf(buf
, sizeof(buf
), "%s", get_tok_str(reg
, NULL
));
1548 cstr_cat(add_str
, buf
, -1);
1552 /* generate prolog and epilog code for asm statement */
1553 ST_FUNC
void asm_gen_code(ASMOperand
*operands
, int nb_operands
,
1554 int nb_outputs
, int is_output
,
1555 uint8_t *clobber_regs
,
1558 uint8_t regs_allocated
[NB_ASM_REGS
];
1561 uint32_t saved_regset
= 0;
1563 // TODO: Check non-E ABI.
1564 // Note: Technically, r13 (sp) is also callee-saved--but that does not matter yet
1565 static uint8_t reg_saved
[] = { 4, 5, 6, 7, 8, 9 /* Note: sometimes special reg "sb" */ , 10, 11 };
1567 /* mark all used registers */
1568 memcpy(regs_allocated
, clobber_regs
, sizeof(regs_allocated
));
1569 for(i
= 0; i
< nb_operands
;i
++) {
1572 regs_allocated
[op
->reg
] = 1;
1574 for(i
= 0; i
< sizeof(reg_saved
)/sizeof(reg_saved
[0]); i
++) {
1576 if (regs_allocated
[reg
])
1577 saved_regset
|= 1 << reg
;
1580 if (!is_output
) { // prolog
1581 /* generate reg save code */
1583 gen_le32(0xe92d0000 | saved_regset
); // push {...}
1585 /* generate load code */
1586 for(i
= 0; i
< nb_operands
; i
++) {
1589 if ((op
->vt
->r
& VT_VALMASK
) == VT_LLOCAL
&&
1591 /* memory reference case (for both input and
1595 sv
.r
= (sv
.r
& ~VT_VALMASK
) | VT_LOCAL
| VT_LVAL
;
1598 } else if (i
>= nb_outputs
|| op
->is_rw
) { // not write-only
1599 /* load value in register */
1600 load(op
->reg
, op
->vt
);
1602 tcc_error("long long not implemented");
1607 /* generate save code */
1608 for(i
= 0 ; i
< nb_outputs
; i
++) {
1611 if ((op
->vt
->r
& VT_VALMASK
) == VT_LLOCAL
) {
1612 if (!op
->is_memory
) {
1615 sv
.r
= (sv
.r
& ~VT_VALMASK
) | VT_LOCAL
;
1620 sv
.r
= (sv
.r
& ~VT_VALMASK
) | out_reg
;
1621 store(op
->reg
, &sv
);
1624 store(op
->reg
, op
->vt
);
1626 tcc_error("long long not implemented");
1631 /* generate reg restore code */
1633 gen_le32(0xe8bd0000 | saved_regset
); // pop {...}
1637 /* return the constraint priority (we allocate first the lowest
1638 numbered constraints) */
1639 static inline int constraint_priority(const char *str
)
1641 int priority
, c
, pr
;
1643 /* we take the lowest priority */
1651 case 'l': // in ARM mode, that's an alias for 'r' [ARM].
1652 case 'r': // register [general]
1653 case 'p': // valid memory address for load,store [general]
1656 case 'M': // integer constant for shifts [ARM]
1657 case 'I': // integer valid for data processing instruction immediate
1658 case 'J': // integer in range -4095...4095
1660 case 'i': // immediate integer operand, including symbolic constants [general]
1661 case 'm': // memory operand [general]
1662 case 'g': // general-purpose-register, memory, immediate integer [general]
1666 tcc_error("unknown constraint '%c'", c
);
1675 static const char *skip_constraint_modifiers(const char *p
)
1677 /* Constraint modifier:
1678 = Operand is written to by this instruction
1679 + Operand is both read and written to by this instruction
1680 % Instruction is commutative for this operand and the following operand.
1682 Per-alternative constraint modifier:
1683 & Operand is clobbered before the instruction is done using the input operands
1685 while (*p
== '=' || *p
== '&' || *p
== '+' || *p
== '%')
1690 #define REG_OUT_MASK 0x01
1691 #define REG_IN_MASK 0x02
1693 #define is_reg_allocated(reg) (regs_allocated[reg] & reg_mask)
1695 ST_FUNC
void asm_compute_constraints(ASMOperand
*operands
,
1696 int nb_operands
, int nb_outputs
,
1697 const uint8_t *clobber_regs
,
1700 /* overall format: modifier, then ,-seperated list of alternatives; all operands for a single instruction must have the same number of alternatives */
1701 /* TODO: Simple constraints
1703 o memory operand that is offsetable
1704 V memory but not offsetable
1705 < memory operand with autodecrement addressing is allowed. Restrictions apply.
1706 > memory operand with autoincrement addressing is allowed. Restrictions apply.
1707 n immediate integer operand with a known numeric value
1708 E immediate floating operand (const_double) is allowed, but only if target=host
1709 F immediate floating operand (const_double or const_vector) is allowed
1710 s immediate integer operand whose value is not an explicit integer
1711 X any operand whatsoever
1712 0...9 (postfix); (can also be more than 1 digit number); an operand that matches the specified operand number is allowed
1715 /* TODO: ARM constraints:
1716 k the stack pointer register
1717 G the floating-point constant 0.0
1718 Q memory reference where the exact address is in a single register ("m" is preferable for asm statements)
1719 R an item in the constant pool
1720 S symbol in the text segment of the current file
1721 [ Uv memory reference suitable for VFP load/store insns (reg+constant offset)]
1722 [ Uy memory reference suitable for iWMMXt load/store instructions]
1723 Uq memory reference suitable for the ARMv4 ldrsb instruction
1726 int sorted_op
[MAX_ASM_OPERANDS
];
1727 int i
, j
, k
, p1
, p2
, tmp
, reg
, c
, reg_mask
;
1729 uint8_t regs_allocated
[NB_ASM_REGS
];
1732 for (i
= 0; i
< nb_operands
; i
++) {
1734 op
->input_index
= -1;
1740 /* compute constraint priority and evaluate references to output
1741 constraints if input constraints */
1742 for (i
= 0; i
< nb_operands
; i
++) {
1744 str
= op
->constraint
;
1745 str
= skip_constraint_modifiers(str
);
1746 if (isnum(*str
) || *str
== '[') {
1747 /* this is a reference to another constraint */
1748 k
= find_constraint(operands
, nb_operands
, str
, NULL
);
1749 if ((unsigned) k
>= i
|| i
< nb_outputs
)
1750 tcc_error("invalid reference in constraint %d ('%s')",
1753 if (operands
[k
].input_index
>= 0)
1754 tcc_error("cannot reference twice the same operand");
1755 operands
[k
].input_index
= i
;
1757 } else if ((op
->vt
->r
& VT_VALMASK
) == VT_LOCAL
1759 && (reg
= op
->vt
->sym
->r
& VT_VALMASK
) < VT_CONST
) {
1763 op
->priority
= constraint_priority(str
);
1767 /* sort operands according to their priority */
1768 for (i
= 0; i
< nb_operands
; i
++)
1770 for (i
= 0; i
< nb_operands
- 1; i
++) {
1771 for (j
= i
+ 1; j
< nb_operands
; j
++) {
1772 p1
= operands
[sorted_op
[i
]].priority
;
1773 p2
= operands
[sorted_op
[j
]].priority
;
1776 sorted_op
[i
] = sorted_op
[j
];
1782 for (i
= 0; i
< NB_ASM_REGS
; i
++) {
1783 if (clobber_regs
[i
])
1784 regs_allocated
[i
] = REG_IN_MASK
| REG_OUT_MASK
;
1786 regs_allocated
[i
] = 0;
1788 /* sp cannot be used */
1789 regs_allocated
[13] = REG_IN_MASK
| REG_OUT_MASK
;
1790 /* fp cannot be used yet */
1791 regs_allocated
[11] = REG_IN_MASK
| REG_OUT_MASK
;
1793 /* allocate registers and generate corresponding asm moves */
1794 for (i
= 0; i
< nb_operands
; i
++) {
1797 str
= op
->constraint
;
1798 /* no need to allocate references */
1799 if (op
->ref_index
>= 0)
1801 /* select if register is used for output, input or both */
1802 if (op
->input_index
>= 0) {
1803 reg_mask
= REG_IN_MASK
| REG_OUT_MASK
;
1804 } else if (j
< nb_outputs
) {
1805 reg_mask
= REG_OUT_MASK
;
1807 reg_mask
= REG_IN_MASK
;
1810 if (is_reg_allocated(op
->reg
))
1812 ("asm regvar requests register that's taken already");
1819 case '=': // Operand is written-to
1821 case '+': // Operand is both READ and written-to
1824 case '&': // Operand is clobbered before the instruction is done using the input operands
1825 if (j
>= nb_outputs
)
1826 tcc_error("'%c' modifier can only be applied to outputs",
1828 reg_mask
= REG_IN_MASK
| REG_OUT_MASK
;
1830 case 'l': // In non-thumb mode, alias for 'r'--otherwise r0-r7 [ARM]
1831 case 'r': // general-purpose register
1832 case 'p': // loadable/storable address
1833 /* any general register */
1834 for (reg
= 0; reg
<= 8; reg
++) {
1835 if (!is_reg_allocated(reg
))
1840 /* now we can reload in the register */
1843 regs_allocated
[reg
] |= reg_mask
;
1845 case 'I': // integer that is valid as an data processing instruction immediate (0...255, rotated by a multiple of two)
1846 case 'J': // integer in the range -4095 to 4095 [ARM]
1847 case 'K': // integer that satisfies constraint I when inverted (one's complement)
1848 case 'L': // integer that satisfies constraint I when inverted (two's complement)
1849 case 'i': // immediate integer operand, including symbolic constants
1850 if (!((op
->vt
->r
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
))
1853 case 'M': // integer in the range 0 to 32
1855 ((op
->vt
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) ==
1859 case 'm': // memory operand
1861 /* nothing special to do because the operand is already in
1862 memory, except if the pointer itself is stored in a
1863 memory variable (VT_LLOCAL case) */
1864 /* XXX: fix constant case */
1865 /* if it is a reference to a memory zone, it must lie
1866 in a register, so we reserve the register in the
1867 input registers and a load will be generated
1869 if (j
< nb_outputs
|| c
== 'm') {
1870 if ((op
->vt
->r
& VT_VALMASK
) == VT_LLOCAL
) {
1871 /* any general register */
1872 for (reg
= 0; reg
<= 8; reg
++) {
1873 if (!(regs_allocated
[reg
] & REG_IN_MASK
))
1878 /* now we can reload in the register */
1879 regs_allocated
[reg
] |= REG_IN_MASK
;
1886 tcc_error("asm constraint %d ('%s') could not be satisfied",
1890 /* if a reference is present for that operand, we assign it too */
1891 if (op
->input_index
>= 0) {
1892 operands
[op
->input_index
].reg
= op
->reg
;
1893 operands
[op
->input_index
].is_llong
= op
->is_llong
;
1897 /* compute out_reg. It is used to store outputs registers to memory
1898 locations references by pointers (VT_LLOCAL case) */
1900 for (i
= 0; i
< nb_operands
; i
++) {
1903 (op
->vt
->r
& VT_VALMASK
) == VT_LLOCAL
&& !op
->is_memory
) {
1904 for (reg
= 0; reg
<= 8; reg
++) {
1905 if (!(regs_allocated
[reg
] & REG_OUT_MASK
))
1908 tcc_error("could not find free output register for reloading");
1915 /* print sorted constraints */
1917 for (i
= 0; i
< nb_operands
; i
++) {
1920 printf("%%%d [%s]: \"%s\" r=0x%04x reg=%d\n",
1922 op
->id
? get_tok_str(op
->id
, NULL
) : "",
1923 op
->constraint
, op
->vt
->r
, op
->reg
);
1926 printf("out_reg=%d\n", *pout_reg
);
1930 ST_FUNC
void asm_clobber(uint8_t *clobber_regs
, const char *str
)
1935 if (!strcmp(str
, "memory") ||
1936 !strcmp(str
, "cc") ||
1937 !strcmp(str
, "flags"))
1939 ts
= tok_alloc(str
, strlen(str
));
1940 reg
= asm_parse_regvar(ts
->tok
);
1942 tcc_error("invalid clobber register '%s'", str
);
1944 clobber_regs
[reg
] = 1;
1947 /* If T refers to a register then return the register number and type.
1948 Otherwise return -1. */
1949 ST_FUNC
int asm_parse_regvar (int t
)
1951 if (t
>= TOK_ASM_r0
&& t
<= TOK_ASM_pc
) { /* register name */
1954 return TOK_ASM_r11
- TOK_ASM_r0
;
1956 return TOK_ASM_r12
- TOK_ASM_r0
;
1958 return TOK_ASM_r13
- TOK_ASM_r0
;
1960 return TOK_ASM_r14
- TOK_ASM_r0
;
1962 return TOK_ASM_r15
- TOK_ASM_r0
;
1964 return t
- TOK_ASM_r0
;
1970 /*************************************************************/
1971 #endif /* ndef TARGET_DEFS_ONLY */