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");
426 else if (!op0_exclam
)
427 tcc_error("first operand of '%s' should have an exclamation mark", get_tok_str(token
, NULL
));
429 asm_emit_opcode(token
, opcode
| ENCODE_RN(ops
[0].reg
) | ops
[1].regset
);
432 expect("block data transfer instruction");
436 /* Parses shift directive and returns the parts that would have to be set in the opcode because of it.
437 Does not encode the actual shift amount.
438 It's not an error if there is no shift directive.
440 NB_SHIFT: will be set to 1 iff SHIFT is filled. Note that for rrx, there's no need to fill SHIFT.
441 SHIFT: will be filled in with the shift operand to use, if any. */
442 static uint32_t asm_parse_optional_shift(TCCState
* s1
, int* nb_shift
, Operand
* shift
)
456 opcode
= ENCODE_BARREL_SHIFTER_MODE_LSL
;
459 opcode
= ENCODE_BARREL_SHIFTER_MODE_ASR
;
462 opcode
= ENCODE_BARREL_SHIFTER_MODE_LSR
;
465 opcode
= ENCODE_BARREL_SHIFTER_MODE_ROR
;
469 parse_operand(s1
, shift
);
474 opcode
= ENCODE_BARREL_SHIFTER_MODE_ROR
;
480 static uint32_t asm_encode_shift(Operand
* shift
)
483 uint32_t operands
= 0;
484 switch (shift
->type
) {
486 if (shift
->reg
== 15)
487 tcc_error("r15 cannot be used as a shift count");
489 operands
= ENCODE_BARREL_SHIFTER_SHIFT_BY_REGISTER
;
490 operands
|= ENCODE_BARREL_SHIFTER_REGISTER(shift
->reg
);
495 if (amount
> 0 && amount
< 32)
496 operands
= ENCODE_BARREL_SHIFTER_IMMEDIATE(amount
);
498 tcc_error("shift count out of range");
501 tcc_error("unknown shift amount");
506 static void asm_data_processing_opcode(TCCState
*s1
, int token
)
512 uint32_t operands
= 0;
514 /* modulo 16 entries per instruction for the different condition codes */
515 uint32_t opcode_idx
= (ARM_INSTRUCTION_GROUP(token
) - TOK_ASM_andeq
) >> 4;
516 uint32_t opcode_nos
= opcode_idx
>> 1; // without "s"; "OpCode" in ARM docs
518 for (nb_ops
= 0; nb_ops
< sizeof(ops
)/sizeof(ops
[0]); ) {
519 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
)
521 parse_operand(s1
, &ops
[nb_ops
]);
529 operands
|= asm_parse_optional_shift(s1
, &nb_shift
, &shift
);
531 expect("at least two operands");
532 else if (nb_ops
== 2) {
533 memcpy(&ops
[2], &ops
[1], sizeof(ops
[1])); // move ops[2]
534 memcpy(&ops
[1], &ops
[0], sizeof(ops
[0])); // ops[1] was implicit
536 } else if (nb_ops
== 3) {
537 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
538 tcc_error("'%s' cannot be used with three operands", get_tok_str(token
, NULL
));
543 expect("two or three operands");
547 uint32_t immediate_value
;
548 uint8_t half_immediate_rotation
;
549 if (nb_shift
&& shift
.type
== OP_REG32
) {
550 if ((ops
[0].type
== OP_REG32
&& ops
[0].reg
== 15) ||
551 (ops
[1].type
== OP_REG32
&& ops
[1].reg
== 15)) {
552 tcc_error("Using the 'pc' register in data processing instructions that have a register-controlled shift is not implemented by ARM");
557 // data processing (general case):
559 // Rn: bits 19...16 (first operand)
560 // Rd: bits 15...12 (destination)
561 // Operand2: bits 11...0 (second operand); depending on I that's either a register or an immediate
563 // bits 24...21: "OpCode"--see below
565 /* operations in the token list are ordered by opcode */
566 opcode
= opcode_nos
<< 21; // drop "s"
567 if (ops
[0].type
!= OP_REG32
)
568 expect("(destination operand) register");
569 else if (opcode_nos
== 0xa || opcode_nos
== 0xb || opcode_nos
== 0x8 || opcode_nos
== 0x9) // cmp, cmn, tst, teq
570 operands
|= ENCODE_SET_CONDITION_CODES
; // force S set, otherwise it's a completely different instruction.
572 operands
|= ENCODE_RD(ops
[0].reg
);
573 if (ops
[1].type
!= OP_REG32
)
574 expect("(first source operand) register");
575 else if (!(opcode_nos
== 0xd || opcode_nos
== 0xf)) // not: mov, mvn (those have only one source operand)
576 operands
|= ENCODE_RN(ops
[1].reg
);
577 switch (ops
[2].type
) {
579 operands
|= ops
[2].reg
;
583 operands
|= ENCODE_IMMEDIATE_FLAG
;
584 immediate_value
= ops
[2].e
.v
;
585 for (half_immediate_rotation
= 0; half_immediate_rotation
< 16; ++half_immediate_rotation
) {
586 if (immediate_value
>= 0x00 && immediate_value
< 0x100)
588 // rotate left by two
589 immediate_value
= ((immediate_value
& 0x3FFFFFFF) << 2) | ((immediate_value
& 0xC0000000) >> 30);
591 if (half_immediate_rotation
>= 16) {
594 operands
|= immediate_value
;
595 operands
|= half_immediate_rotation
<< 8;
598 case OP_IM8N
: // immediate negative value
599 operands
|= ENCODE_IMMEDIATE_FLAG
;
600 immediate_value
= ops
[2].e
.v
;
601 /* Instruction swapping:
602 0001 = EOR - Rd:= Op1 EOR Op2 -> difficult
603 0011 = RSB - Rd:= Op2 - Op1 -> difficult
604 0111 = RSC - Rd:= Op2 - Op1 + C -> difficult
605 1000 = TST - CC on: Op1 AND Op2 -> difficult
606 1001 = TEQ - CC on: Op1 EOR Op2 -> difficult
607 1100 = ORR - Rd:= Op1 OR Op2 -> difficult
609 switch (opcode_nos
) {
610 case 0x0: // AND - Rd:= Op1 AND Op2
611 opcode
= 0xe << 21; // BIC
612 immediate_value
= ~immediate_value
;
614 case 0x2: // SUB - Rd:= Op1 - Op2
615 opcode
= 0x4 << 21; // ADD
616 immediate_value
= -immediate_value
;
618 case 0x4: // ADD - Rd:= Op1 + Op2
619 opcode
= 0x2 << 21; // SUB
620 immediate_value
= -immediate_value
;
622 case 0x5: // ADC - Rd:= Op1 + Op2 + C
623 opcode
= 0x6 << 21; // SBC
624 immediate_value
= ~immediate_value
;
626 case 0x6: // SBC - Rd:= Op1 - Op2 + C
627 opcode
= 0x5 << 21; // ADC
628 immediate_value
= ~immediate_value
;
630 case 0xa: // CMP - CC on: Op1 - Op2
631 opcode
= 0xb << 21; // CMN
632 immediate_value
= -immediate_value
;
634 case 0xb: // CMN - CC on: Op1 + Op2
635 opcode
= 0xa << 21; // CMP
636 immediate_value
= -immediate_value
;
638 case 0xd: // MOV - Rd:= Op2
639 opcode
= 0xf << 21; // MVN
640 immediate_value
= ~immediate_value
;
642 case 0xe: // BIC - Rd:= Op1 AND NOT Op2
643 opcode
= 0x0 << 21; // AND
644 immediate_value
= ~immediate_value
;
646 case 0xf: // MVN - Rd:= NOT Op2
647 opcode
= 0xd << 21; // MOV
648 immediate_value
= ~immediate_value
;
651 tcc_error("cannot use '%s' with a negative immediate value", get_tok_str(token
, NULL
));
653 for (half_immediate_rotation
= 0; half_immediate_rotation
< 16; ++half_immediate_rotation
) {
654 if (immediate_value
>= 0x00 && immediate_value
< 0x100)
656 // rotate left by two
657 immediate_value
= ((immediate_value
& 0x3FFFFFFF) << 2) | ((immediate_value
& 0xC0000000) >> 30);
659 if (half_immediate_rotation
>= 16) {
660 immediate_value
= ops
[2].e
.v
;
661 tcc_error("immediate value 0x%X cannot be encoded into ARM immediate", (unsigned) immediate_value
);
664 operands
|= immediate_value
;
665 operands
|= half_immediate_rotation
<< 8;
668 expect("(second source operand) register or immediate value");
672 if (operands
& ENCODE_IMMEDIATE_FLAG
)
673 tcc_error("immediate rotation not implemented");
675 operands
|= asm_encode_shift(&shift
);
678 /* S=0 and S=1 entries alternate one after another, in that order */
679 opcode
|= (opcode_idx
& 1) ? ENCODE_SET_CONDITION_CODES
: 0;
680 asm_emit_opcode(token
, opcode
| operands
);
684 static void asm_shift_opcode(TCCState
*s1
, int token
)
688 int definitely_neutral
= 0;
689 uint32_t opcode
= 0xd << 21; // MOV
690 uint32_t operands
= 0;
692 for (nb_ops
= 0; nb_ops
< sizeof(ops
)/sizeof(ops
[0]); ++nb_ops
) {
693 parse_operand(s1
, &ops
[nb_ops
]);
701 expect("at least two operands");
705 if (ops
[0].type
!= OP_REG32
) {
706 expect("(destination operand) register");
709 operands
|= ENCODE_RD(ops
[0].reg
);
712 switch (ARM_INSTRUCTION_GROUP(token
)) {
714 opcode
|= ENCODE_SET_CONDITION_CODES
;
717 if (ops
[1].type
== OP_REG32
) {
718 operands
|= ops
[1].reg
;
719 operands
|= ENCODE_BARREL_SHIFTER_MODE_ROR
;
720 asm_emit_opcode(token
, opcode
| operands
);
722 tcc_error("(first source operand) register");
725 memcpy(&ops
[2], &ops
[1], sizeof(ops
[1])); // move ops[2]
726 memcpy(&ops
[1], &ops
[0], sizeof(ops
[0])); // ops[1] was implicit
731 expect("two or three operands");
735 switch (ARM_INSTRUCTION_GROUP(token
)) {
740 opcode
|= ENCODE_SET_CONDITION_CODES
;
744 switch (ops
[1].type
) {
746 operands
|= ops
[1].reg
;
749 operands
|= ENCODE_IMMEDIATE_FLAG
;
750 operands
|= ops
[1].e
.v
;
754 switch (ops
[2].type
) {
756 if ((ops
[0].type
== OP_REG32
&& ops
[0].reg
== 15) ||
757 (ops
[1].type
== OP_REG32
&& ops
[1].reg
== 15)) {
758 tcc_error("Using the 'pc' register in data processing instructions that have a register-controlled shift is not implemented by ARM");
760 operands
|= asm_encode_shift(&ops
[2]);
764 operands
|= asm_encode_shift(&ops
[2]);
766 definitely_neutral
= 1;
770 if (!definitely_neutral
) switch (ARM_INSTRUCTION_GROUP(token
)) {
773 operands
|= ENCODE_BARREL_SHIFTER_MODE_LSL
;
777 operands
|= ENCODE_BARREL_SHIFTER_MODE_LSR
;
781 operands
|= ENCODE_BARREL_SHIFTER_MODE_ASR
;
785 operands
|= ENCODE_BARREL_SHIFTER_MODE_ROR
;
788 expect("shift instruction");
791 asm_emit_opcode(token
, opcode
| operands
);
794 static void asm_multiplication_opcode(TCCState
*s1
, int token
)
798 uint32_t opcode
= 0x90;
800 for (nb_ops
= 0; nb_ops
< sizeof(ops
)/sizeof(ops
[0]); ++nb_ops
) {
801 parse_operand(s1
, &ops
[nb_ops
]);
809 expect("at least two operands");
810 else if (nb_ops
== 2) {
811 switch (ARM_INSTRUCTION_GROUP(token
)) {
814 memcpy(&ops
[2], &ops
[0], sizeof(ops
[1])); // ARM is actually like this!
817 expect("at least three operands");
823 // multiply (special case):
830 if (ops
[0].type
== OP_REG32
)
831 opcode
|= ops
[0].reg
<< 16;
833 expect("(destination operand) register");
834 if (ops
[1].type
== OP_REG32
)
835 opcode
|= ops
[1].reg
;
837 expect("(first source operand) register");
838 if (ops
[2].type
== OP_REG32
)
839 opcode
|= ops
[2].reg
<< 8;
841 expect("(second source operand) register");
843 if (ops
[3].type
== OP_REG32
)
844 opcode
|= ops
[3].reg
<< 12;
846 expect("(third source operand) register");
849 switch (ARM_INSTRUCTION_GROUP(token
)) {
851 opcode
|= 1 << 20; // Status
855 expect("three operands");
857 asm_emit_opcode(token
, opcode
);
861 opcode
|= 1 << 20; // Status
865 expect("four operands");
867 opcode
|= 1 << 21; // Accumulate
868 asm_emit_opcode(token
, opcode
);
872 expect("known multiplication instruction");
876 static void asm_long_multiplication_opcode(TCCState
*s1
, int token
)
880 uint32_t opcode
= 0x90 | (1 << 23);
882 for (nb_ops
= 0; nb_ops
< sizeof(ops
)/sizeof(ops
[0]); ++nb_ops
) {
883 parse_operand(s1
, &ops
[nb_ops
]);
891 expect("four operands");
895 // long multiply (special case):
897 // RdLo: bits 15...12
898 // RdHi: bits 19...16
902 if (ops
[0].type
== OP_REG32
)
903 opcode
|= ops
[0].reg
<< 12;
905 expect("(destination lo accumulator) register");
906 if (ops
[1].type
== OP_REG32
)
907 opcode
|= ops
[1].reg
<< 16;
909 expect("(destination hi accumulator) register");
910 if (ops
[2].type
== OP_REG32
)
911 opcode
|= ops
[2].reg
;
913 expect("(first source operand) register");
914 if (ops
[3].type
== OP_REG32
)
915 opcode
|= ops
[3].reg
<< 8;
917 expect("(second source operand) register");
919 switch (ARM_INSTRUCTION_GROUP(token
)) {
920 case TOK_ASM_smullseq
:
921 opcode
|= 1 << 20; // Status
923 case TOK_ASM_smulleq
:
924 opcode
|= 1 << 22; // signed
925 asm_emit_opcode(token
, opcode
);
927 case TOK_ASM_umullseq
:
928 opcode
|= 1 << 20; // Status
930 case TOK_ASM_umulleq
:
931 asm_emit_opcode(token
, opcode
);
933 case TOK_ASM_smlalseq
:
934 opcode
|= 1 << 20; // Status
936 case TOK_ASM_smlaleq
:
937 opcode
|= 1 << 22; // signed
938 opcode
|= 1 << 21; // Accumulate
939 asm_emit_opcode(token
, opcode
);
941 case TOK_ASM_umlalseq
:
942 opcode
|= 1 << 20; // Status
944 case TOK_ASM_umlaleq
:
945 opcode
|= 1 << 21; // Accumulate
946 asm_emit_opcode(token
, opcode
);
949 expect("known long multiplication instruction");
953 static void asm_single_data_transfer_opcode(TCCState
*s1
, int token
)
956 Operand strex_operand
;
960 int closed_bracket
= 0;
963 // Note: ldr r0, [r4, #4] ; simple offset: r0 = *(int*)(r4+4); r4 unchanged
964 // Note: ldr r0, [r4, #4]! ; pre-indexed: r0 = *(int*)(r4+4); r4 = r4+4
965 // Note: ldr r0, [r4], #4 ; post-indexed: r0 = *(int*)(r4+0); r4 = r4+4
967 parse_operand(s1
, &ops
[0]);
968 if (ops
[0].type
== OP_REG32
)
969 opcode
|= ENCODE_RD(ops
[0].reg
);
971 expect("(destination operand) register");
975 expect("at least two arguments");
979 switch (ARM_INSTRUCTION_GROUP(token
)) {
980 case TOK_ASM_strexbeq
:
981 case TOK_ASM_strexeq
:
982 parse_operand(s1
, &strex_operand
);
983 if (strex_operand
.type
!= OP_REG32
) {
988 expect("at least three arguments");
999 parse_operand(s1
, &ops
[1]);
1000 if (ops
[1].type
== OP_REG32
)
1001 opcode
|= ENCODE_RN(ops
[1].reg
);
1003 expect("(first source operand) register");
1009 // exclam = 1; // implicit in hardware; don't do it in software
1017 parse_operand(s1
, &ops
[2]);
1018 if (ops
[2].type
== OP_REG32
) {
1019 if (ops
[2].reg
== 15) {
1020 tcc_error("Using 'pc' for register offset in '%s' is not implemented by ARM", get_tok_str(token
, NULL
));
1025 opcode
|= asm_parse_optional_shift(s1
, &nb_shift
, &shift
);
1027 expect("shift directive, or no comma");
1031 // end of input expression in brackets--assume 0 offset
1032 ops
[2].type
= OP_IM8
;
1034 opcode
|= 1 << 24; // add offset before transfer
1036 if (!closed_bracket
) {
1041 opcode
|= 1 << 24; // add offset before transfer
1048 // single data transfer: 0 1 I P U B W L << 20 (general case):
1050 // Rd: destination operand [ok]
1051 // Rn: first source operand [ok]
1052 // Operand2: bits 11...0 [ok]
1053 // I: immediate operand? [ok]
1054 // P: Pre/post indexing is PRE: Add offset before transfer [ok]
1055 // U: Up/down is up? (*adds* offset to base) [ok]
1056 // B: Byte/word is byte? TODO
1057 // W: Write address back into base? [ok]
1058 // L: Load/store is load? [ok]
1060 opcode
|= 1 << 21; // write offset back into register
1062 if (ops
[2].type
== OP_IM32
|| ops
[2].type
== OP_IM8
|| ops
[2].type
== OP_IM8N
) {
1065 tcc_error("minus before '#' not supported for immediate values");
1067 opcode
|= 1 << 23; // up
1069 tcc_error("offset out of range for '%s'", get_tok_str(token
, NULL
));
1074 tcc_error("offset out of range for '%s'", get_tok_str(token
, NULL
));
1078 } else if (ops
[2].type
== OP_REG32
) {
1080 opcode
|= 1 << 23; // up
1081 opcode
|= ENCODE_IMMEDIATE_FLAG
; /* if set, it means it's NOT immediate */
1082 opcode
|= ops
[2].reg
;
1086 switch (ARM_INSTRUCTION_GROUP(token
)) {
1087 case TOK_ASM_strbeq
:
1088 opcode
|= 1 << 22; // B
1091 opcode
|= 1 << 26; // Load/Store
1093 opcode
|= asm_encode_shift(&shift
);
1094 asm_emit_opcode(token
, opcode
);
1096 case TOK_ASM_ldrbeq
:
1097 opcode
|= 1 << 22; // B
1100 opcode
|= 1 << 20; // L
1101 opcode
|= 1 << 26; // Load/Store
1103 opcode
|= asm_encode_shift(&shift
);
1104 asm_emit_opcode(token
, opcode
);
1106 case TOK_ASM_strexbeq
:
1107 opcode
|= 1 << 22; // B
1109 case TOK_ASM_strexeq
:
1110 if ((opcode
& 0xFFF) || nb_shift
) {
1111 tcc_error("neither offset nor shift allowed with 'strex'");
1113 } else if (opcode
& ENCODE_IMMEDIATE_FLAG
) { // if set, it means it's NOT immediate
1114 tcc_error("offset not allowed with 'strex'");
1117 if ((opcode
& (1 << 24)) == 0) { // add offset after transfer
1118 tcc_error("adding offset after transfer not allowed with 'strex'");
1122 opcode
|= 0xf90; // Used to mean: barrel shifter is enabled, barrel shift register is r15, mode is LSL
1123 opcode
|= strex_operand
.reg
;
1124 asm_emit_opcode(token
, opcode
);
1126 case TOK_ASM_ldrexbeq
:
1127 opcode
|= 1 << 22; // B
1129 case TOK_ASM_ldrexeq
:
1130 if ((opcode
& 0xFFF) || nb_shift
) {
1131 tcc_error("neither offset nor shift allowed with 'ldrex'");
1133 } else if (opcode
& ENCODE_IMMEDIATE_FLAG
) { // if set, it means it's NOT immediate
1134 tcc_error("offset not allowed with 'ldrex'");
1137 if ((opcode
& (1 << 24)) == 0) { // add offset after transfer
1138 tcc_error("adding offset after transfer not allowed with 'ldrex'");
1141 opcode
|= 1 << 20; // L
1143 opcode
|= 0xf90; // Used to mean: barrel shifter is enabled, barrel shift register is r15, mode is LSL
1144 asm_emit_opcode(token
, opcode
);
1147 expect("data transfer instruction");
1151 static void asm_misc_single_data_transfer_opcode(TCCState
*s1
, int token
)
1155 int closed_bracket
= 0;
1157 uint32_t opcode
= (1 << 7) | (1 << 4);
1160 The argument syntax is exactly the same as in arm_single_data_transfer_opcode, except that there's no STREX argument form.
1161 The main difference between this function and asm_misc_single_data_transfer_opcode is that the immediate values here must be smaller.
1162 Also, the combination (P=0, W=1) is unpredictable here.
1163 The immediate flag has moved to bit index 22--and its meaning has flipped.
1164 The immediate value itself has been split into two parts: one at bits 11...8, one at bits 3...0
1165 bit 26 (Load/Store instruction) is unset here.
1166 bits 7 and 4 are set here. */
1168 // Here: 0 0 0 P U I W L << 20
1169 // [compare single data transfer: 0 1 I P U B W L << 20]
1171 parse_operand(s1
, &ops
[0]);
1172 if (ops
[0].type
== OP_REG32
)
1173 opcode
|= ENCODE_RD(ops
[0].reg
);
1175 expect("(destination operand) register");
1179 expect("at least two arguments");
1188 parse_operand(s1
, &ops
[1]);
1189 if (ops
[1].type
== OP_REG32
)
1190 opcode
|= ENCODE_RN(ops
[1].reg
);
1192 expect("(first source operand) register");
1198 // exclam = 1; // implicit in hardware; don't do it in software
1206 parse_operand(s1
, &ops
[2]);
1208 // end of input expression in brackets--assume 0 offset
1209 ops
[2].type
= OP_IM8
;
1211 opcode
|= 1 << 24; // add offset before transfer
1213 if (!closed_bracket
) {
1218 opcode
|= 1 << 24; // add offset before transfer
1226 if ((opcode
& (1 << 24)) == 0) {
1227 tcc_error("result of '%s' would be unpredictable here", get_tok_str(token
, NULL
));
1230 opcode
|= 1 << 21; // write offset back into register
1233 if (ops
[2].type
== OP_IM32
|| ops
[2].type
== OP_IM8
|| ops
[2].type
== OP_IM8N
) {
1236 tcc_error("minus before '#' not supported for immediate values");
1238 opcode
|= 1 << 23; // up
1240 tcc_error("offset out of range for '%s'", get_tok_str(token
, NULL
));
1242 // bits 11...8: immediate hi nibble
1243 // bits 3...0: immediate lo nibble
1244 opcode
|= (v
& 0xF0) << 4;
1249 tcc_error("offset out of range for '%s'", get_tok_str(token
, NULL
));
1252 // bits 11...8: immediate hi nibble
1253 // bits 3...0: immediate lo nibble
1254 opcode
|= (v
& 0xF0) << 4;
1258 opcode
|= 1 << 22; // not ENCODE_IMMEDIATE_FLAG;
1259 } else if (ops
[2].type
== OP_REG32
) {
1261 opcode
|= 1 << 23; // up
1262 opcode
|= ops
[2].reg
;
1266 switch (ARM_INSTRUCTION_GROUP(token
)) {
1267 case TOK_ASM_ldrsheq
:
1268 opcode
|= 1 << 5; // halfword, not byte
1270 case TOK_ASM_ldrsbeq
:
1271 opcode
|= 1 << 6; // sign extend
1272 opcode
|= 1 << 20; // L
1273 asm_emit_opcode(token
, opcode
);
1275 case TOK_ASM_ldrheq
:
1276 opcode
|= 1 << 5; // halfword, not byte
1277 opcode
|= 1 << 20; // L
1278 asm_emit_opcode(token
, opcode
);
1280 case TOK_ASM_strheq
:
1281 opcode
|= 1 << 5; // halfword, not byte
1282 asm_emit_opcode(token
, opcode
);
1287 /* Note: almost dupe of encbranch in arm-gen.c */
1288 static uint32_t encbranchoffset(int pos
, int addr
, int fail
)
1292 if(addr
>=0x7fffff || addr
<-0x800000) {
1294 tcc_error("branch offset is too far");
1297 return /*not 0x0A000000|*/(addr
&0xffffff);
1300 static void asm_branch_opcode(TCCState
*s1
, int token
)
1307 switch (ARM_INSTRUCTION_GROUP(token
)) {
1311 esym
= elfsym(e
.sym
);
1312 if (!esym
|| esym
->st_shndx
!= cur_text_section
->sh_num
) {
1313 tcc_error("invalid branch target");
1316 jmp_disp
= encbranchoffset(ind
, e
.v
+ esym
->st_value
, 1);
1319 parse_operand(s1
, &op
);
1322 switch (ARM_INSTRUCTION_GROUP(token
)) {
1324 asm_emit_opcode(token
, (0xa << 24) | (jmp_disp
& 0xffffff));
1327 asm_emit_opcode(token
, (0xb << 24) | (jmp_disp
& 0xffffff));
1330 if (op
.type
!= OP_REG32
)
1333 asm_emit_opcode(token
, (0x12fff1 << 4) | op
.reg
);
1336 if (op
.type
!= OP_REG32
)
1339 asm_emit_opcode(token
, (0x12fff3 << 4) | op
.reg
);
1342 expect("branch instruction");
1346 ST_FUNC
void asm_opcode(TCCState
*s1
, int token
)
1348 while (token
== TOK_LINEFEED
) {
1352 if (token
== TOK_EOF
)
1354 if (token
< TOK_ASM_nopeq
) {
1355 expect("instruction");
1359 switch (ARM_INSTRUCTION_GROUP(token
)) {
1360 case TOK_ASM_pusheq
:
1362 case TOK_ASM_stmdaeq
:
1363 case TOK_ASM_ldmdaeq
:
1366 case TOK_ASM_stmiaeq
:
1367 case TOK_ASM_ldmiaeq
:
1368 case TOK_ASM_stmdbeq
:
1369 case TOK_ASM_ldmdbeq
:
1370 case TOK_ASM_stmibeq
:
1371 case TOK_ASM_ldmibeq
:
1372 return asm_block_data_transfer_opcode(s1
, token
);
1376 return asm_nullary_opcode(token
);
1378 return asm_unary_opcode(s1
, token
);
1383 return asm_branch_opcode(s1
, token
);
1385 case TOK_ASM_sxtbeq
:
1386 case TOK_ASM_sxtheq
:
1387 case TOK_ASM_uxtbeq
:
1388 case TOK_ASM_uxtheq
:
1389 case TOK_ASM_movteq
:
1390 case TOK_ASM_movweq
:
1391 return asm_binary_opcode(s1
, token
);
1394 case TOK_ASM_ldrbeq
:
1396 case TOK_ASM_strbeq
:
1397 case TOK_ASM_ldrexeq
:
1398 case TOK_ASM_ldrexbeq
:
1399 case TOK_ASM_strexeq
:
1400 case TOK_ASM_strexbeq
:
1401 return asm_single_data_transfer_opcode(s1
, token
);
1403 case TOK_ASM_ldrheq
:
1404 case TOK_ASM_ldrsheq
:
1405 case TOK_ASM_ldrsbeq
:
1406 case TOK_ASM_strheq
:
1407 return asm_misc_single_data_transfer_opcode(s1
, token
);
1425 case TOK_ASM_andseq
:
1426 case TOK_ASM_eorseq
:
1427 case TOK_ASM_subseq
:
1428 case TOK_ASM_rsbseq
:
1429 case TOK_ASM_addseq
:
1430 case TOK_ASM_adcseq
:
1431 case TOK_ASM_sbcseq
:
1432 case TOK_ASM_rscseq
:
1433 // case TOK_ASM_tstseq:
1434 // case TOK_ASM_teqseq:
1435 // case TOK_ASM_cmpseq:
1436 // case TOK_ASM_cmnseq:
1437 case TOK_ASM_orrseq
:
1438 case TOK_ASM_movseq
:
1439 case TOK_ASM_bicseq
:
1440 case TOK_ASM_mvnseq
:
1441 return asm_data_processing_opcode(s1
, token
);
1444 case TOK_ASM_lslseq
:
1446 case TOK_ASM_lsrseq
:
1448 case TOK_ASM_asrseq
:
1450 case TOK_ASM_rorseq
:
1451 case TOK_ASM_rrxseq
:
1453 return asm_shift_opcode(s1
, token
);
1456 case TOK_ASM_mulseq
:
1458 case TOK_ASM_mlaseq
:
1459 return asm_multiplication_opcode(s1
, token
);
1461 case TOK_ASM_smulleq
:
1462 case TOK_ASM_smullseq
:
1463 case TOK_ASM_umulleq
:
1464 case TOK_ASM_umullseq
:
1465 case TOK_ASM_smlaleq
:
1466 case TOK_ASM_smlalseq
:
1467 case TOK_ASM_umlaleq
:
1468 case TOK_ASM_umlalseq
:
1469 return asm_long_multiplication_opcode(s1
, token
);
1471 expect("known instruction");
1475 ST_FUNC
void subst_asm_operand(CString
*add_str
, SValue
*sv
, int modifier
)
1477 int r
, reg
, size
, val
;
1481 if ((r
& VT_VALMASK
) == VT_CONST
) {
1482 if (!(r
& VT_LVAL
) && modifier
!= 'c' && modifier
!= 'n' &&
1484 cstr_ccat(add_str
, '#');
1486 const char *name
= get_tok_str(sv
->sym
->v
, NULL
);
1487 if (sv
->sym
->v
>= SYM_FIRST_ANOM
) {
1488 /* In case of anonymous symbols ("L.42", used
1489 for static data labels) we can't find them
1490 in the C symbol table when later looking up
1491 this name. So enter them now into the asm label
1492 list when we still know the symbol. */
1493 get_asm_sym(tok_alloc(name
, strlen(name
))->tok
, sv
->sym
);
1495 if (tcc_state
->leading_underscore
)
1496 cstr_ccat(add_str
, '_');
1497 cstr_cat(add_str
, name
, -1);
1498 if ((uint32_t) sv
->c
.i
== 0)
1500 cstr_ccat(add_str
, '+');
1503 if (modifier
== 'n')
1505 snprintf(buf
, sizeof(buf
), "%d", (int) sv
->c
.i
);
1506 cstr_cat(add_str
, buf
, -1);
1508 } else if ((r
& VT_VALMASK
) == VT_LOCAL
) {
1509 snprintf(buf
, sizeof(buf
), "[fp,#%d]", (int) sv
->c
.i
);
1510 cstr_cat(add_str
, buf
, -1);
1511 } else if (r
& VT_LVAL
) {
1512 reg
= r
& VT_VALMASK
;
1513 if (reg
>= VT_CONST
)
1514 tcc_internal_error("");
1515 snprintf(buf
, sizeof(buf
), "[%s]",
1516 get_tok_str(TOK_ASM_r0
+ reg
, NULL
));
1517 cstr_cat(add_str
, buf
, -1);
1520 reg
= r
& VT_VALMASK
;
1521 if (reg
>= VT_CONST
)
1522 tcc_internal_error("");
1524 /* choose register operand size */
1525 if ((sv
->type
.t
& VT_BTYPE
) == VT_BYTE
||
1526 (sv
->type
.t
& VT_BTYPE
) == VT_BOOL
)
1528 else if ((sv
->type
.t
& VT_BTYPE
) == VT_SHORT
)
1533 if (modifier
== 'b') {
1535 } else if (modifier
== 'w') {
1537 } else if (modifier
== 'k') {
1543 reg
= TOK_ASM_r0
+ reg
;
1546 snprintf(buf
, sizeof(buf
), "%s", get_tok_str(reg
, NULL
));
1547 cstr_cat(add_str
, buf
, -1);
1551 /* generate prolog and epilog code for asm statement */
1552 ST_FUNC
void asm_gen_code(ASMOperand
*operands
, int nb_operands
,
1553 int nb_outputs
, int is_output
,
1554 uint8_t *clobber_regs
,
1557 uint8_t regs_allocated
[NB_ASM_REGS
];
1560 uint32_t saved_regset
= 0;
1562 // TODO: Check non-E ABI.
1563 // Note: Technically, r13 (sp) is also callee-saved--but that does not matter yet
1564 static uint8_t reg_saved
[] = { 4, 5, 6, 7, 8, 9 /* Note: sometimes special reg "sb" */ , 10, 11 };
1566 /* mark all used registers */
1567 memcpy(regs_allocated
, clobber_regs
, sizeof(regs_allocated
));
1568 for(i
= 0; i
< nb_operands
;i
++) {
1571 regs_allocated
[op
->reg
] = 1;
1573 for(i
= 0; i
< sizeof(reg_saved
)/sizeof(reg_saved
[0]); i
++) {
1575 if (regs_allocated
[reg
])
1576 saved_regset
|= 1 << reg
;
1579 if (!is_output
) { // prolog
1580 /* generate reg save code */
1582 gen_le32(0xe92d0000 | saved_regset
); // push {...}
1584 /* generate load code */
1585 for(i
= 0; i
< nb_operands
; i
++) {
1588 if ((op
->vt
->r
& VT_VALMASK
) == VT_LLOCAL
&&
1590 /* memory reference case (for both input and
1594 sv
.r
= (sv
.r
& ~VT_VALMASK
) | VT_LOCAL
| VT_LVAL
;
1597 } else if (i
>= nb_outputs
|| op
->is_rw
) { // not write-only
1598 /* load value in register */
1599 load(op
->reg
, op
->vt
);
1601 tcc_error("long long not implemented");
1606 /* generate save code */
1607 for(i
= 0 ; i
< nb_outputs
; i
++) {
1610 if ((op
->vt
->r
& VT_VALMASK
) == VT_LLOCAL
) {
1611 if (!op
->is_memory
) {
1614 sv
.r
= (sv
.r
& ~VT_VALMASK
) | VT_LOCAL
;
1619 sv
.r
= (sv
.r
& ~VT_VALMASK
) | out_reg
;
1620 store(op
->reg
, &sv
);
1623 store(op
->reg
, op
->vt
);
1625 tcc_error("long long not implemented");
1630 /* generate reg restore code */
1632 gen_le32(0xe8bd0000 | saved_regset
); // pop {...}
1636 /* return the constraint priority (we allocate first the lowest
1637 numbered constraints) */
1638 static inline int constraint_priority(const char *str
)
1640 int priority
, c
, pr
;
1642 /* we take the lowest priority */
1650 case 'l': // in ARM mode, that's an alias for 'r' [ARM].
1651 case 'r': // register [general]
1652 case 'p': // valid memory address for load,store [general]
1655 case 'M': // integer constant for shifts [ARM]
1656 case 'I': // integer valid for data processing instruction immediate
1657 case 'J': // integer in range -4095...4095
1659 case 'i': // immediate integer operand, including symbolic constants [general]
1660 case 'm': // memory operand [general]
1661 case 'g': // general-purpose-register, memory, immediate integer [general]
1665 tcc_error("unknown constraint '%c'", c
);
1674 static const char *skip_constraint_modifiers(const char *p
)
1676 /* Constraint modifier:
1677 = Operand is written to by this instruction
1678 + Operand is both read and written to by this instruction
1679 % Instruction is commutative for this operand and the following operand.
1681 Per-alternative constraint modifier:
1682 & Operand is clobbered before the instruction is done using the input operands
1684 while (*p
== '=' || *p
== '&' || *p
== '+' || *p
== '%')
1689 #define REG_OUT_MASK 0x01
1690 #define REG_IN_MASK 0x02
1692 #define is_reg_allocated(reg) (regs_allocated[reg] & reg_mask)
1694 ST_FUNC
void asm_compute_constraints(ASMOperand
*operands
,
1695 int nb_operands
, int nb_outputs
,
1696 const uint8_t *clobber_regs
,
1699 /* overall format: modifier, then ,-seperated list of alternatives; all operands for a single instruction must have the same number of alternatives */
1700 /* TODO: Simple constraints
1702 o memory operand that is offsetable
1703 V memory but not offsetable
1704 < memory operand with autodecrement addressing is allowed. Restrictions apply.
1705 > memory operand with autoincrement addressing is allowed. Restrictions apply.
1706 n immediate integer operand with a known numeric value
1707 E immediate floating operand (const_double) is allowed, but only if target=host
1708 F immediate floating operand (const_double or const_vector) is allowed
1709 s immediate integer operand whose value is not an explicit integer
1710 X any operand whatsoever
1711 0...9 (postfix); (can also be more than 1 digit number); an operand that matches the specified operand number is allowed
1714 /* TODO: ARM constraints:
1715 k the stack pointer register
1716 G the floating-point constant 0.0
1717 Q memory reference where the exact address is in a single register ("m" is preferable for asm statements)
1718 R an item in the constant pool
1719 S symbol in the text segment of the current file
1720 [ Uv memory reference suitable for VFP load/store insns (reg+constant offset)]
1721 [ Uy memory reference suitable for iWMMXt load/store instructions]
1722 Uq memory reference suitable for the ARMv4 ldrsb instruction
1725 int sorted_op
[MAX_ASM_OPERANDS
];
1726 int i
, j
, k
, p1
, p2
, tmp
, reg
, c
, reg_mask
;
1728 uint8_t regs_allocated
[NB_ASM_REGS
];
1731 for (i
= 0; i
< nb_operands
; i
++) {
1733 op
->input_index
= -1;
1739 /* compute constraint priority and evaluate references to output
1740 constraints if input constraints */
1741 for (i
= 0; i
< nb_operands
; i
++) {
1743 str
= op
->constraint
;
1744 str
= skip_constraint_modifiers(str
);
1745 if (isnum(*str
) || *str
== '[') {
1746 /* this is a reference to another constraint */
1747 k
= find_constraint(operands
, nb_operands
, str
, NULL
);
1748 if ((unsigned) k
>= i
|| i
< nb_outputs
)
1749 tcc_error("invalid reference in constraint %d ('%s')",
1752 if (operands
[k
].input_index
>= 0)
1753 tcc_error("cannot reference twice the same operand");
1754 operands
[k
].input_index
= i
;
1756 } else if ((op
->vt
->r
& VT_VALMASK
) == VT_LOCAL
1758 && (reg
= op
->vt
->sym
->r
& VT_VALMASK
) < VT_CONST
) {
1762 op
->priority
= constraint_priority(str
);
1766 /* sort operands according to their priority */
1767 for (i
= 0; i
< nb_operands
; i
++)
1769 for (i
= 0; i
< nb_operands
- 1; i
++) {
1770 for (j
= i
+ 1; j
< nb_operands
; j
++) {
1771 p1
= operands
[sorted_op
[i
]].priority
;
1772 p2
= operands
[sorted_op
[j
]].priority
;
1775 sorted_op
[i
] = sorted_op
[j
];
1781 for (i
= 0; i
< NB_ASM_REGS
; i
++) {
1782 if (clobber_regs
[i
])
1783 regs_allocated
[i
] = REG_IN_MASK
| REG_OUT_MASK
;
1785 regs_allocated
[i
] = 0;
1787 /* sp cannot be used */
1788 regs_allocated
[13] = REG_IN_MASK
| REG_OUT_MASK
;
1789 /* fp cannot be used yet */
1790 regs_allocated
[11] = REG_IN_MASK
| REG_OUT_MASK
;
1792 /* allocate registers and generate corresponding asm moves */
1793 for (i
= 0; i
< nb_operands
; i
++) {
1796 str
= op
->constraint
;
1797 /* no need to allocate references */
1798 if (op
->ref_index
>= 0)
1800 /* select if register is used for output, input or both */
1801 if (op
->input_index
>= 0) {
1802 reg_mask
= REG_IN_MASK
| REG_OUT_MASK
;
1803 } else if (j
< nb_outputs
) {
1804 reg_mask
= REG_OUT_MASK
;
1806 reg_mask
= REG_IN_MASK
;
1809 if (is_reg_allocated(op
->reg
))
1811 ("asm regvar requests register that's taken already");
1818 case '=': // Operand is written-to
1820 case '+': // Operand is both READ and written-to
1823 case '&': // Operand is clobbered before the instruction is done using the input operands
1824 if (j
>= nb_outputs
)
1825 tcc_error("'%c' modifier can only be applied to outputs",
1827 reg_mask
= REG_IN_MASK
| REG_OUT_MASK
;
1829 case 'l': // In non-thumb mode, alias for 'r'--otherwise r0-r7 [ARM]
1830 case 'r': // general-purpose register
1831 case 'p': // loadable/storable address
1832 /* any general register */
1833 for (reg
= 0; reg
<= 8; reg
++) {
1834 if (!is_reg_allocated(reg
))
1839 /* now we can reload in the register */
1842 regs_allocated
[reg
] |= reg_mask
;
1844 case 'I': // integer that is valid as an data processing instruction immediate (0...255, rotated by a multiple of two)
1845 case 'J': // integer in the range -4095 to 4095 [ARM]
1846 case 'K': // integer that satisfies constraint I when inverted (one's complement)
1847 case 'L': // integer that satisfies constraint I when inverted (two's complement)
1848 case 'i': // immediate integer operand, including symbolic constants
1849 if (!((op
->vt
->r
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
))
1852 case 'M': // integer in the range 0 to 32
1854 ((op
->vt
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) ==
1858 case 'm': // memory operand
1860 /* nothing special to do because the operand is already in
1861 memory, except if the pointer itself is stored in a
1862 memory variable (VT_LLOCAL case) */
1863 /* XXX: fix constant case */
1864 /* if it is a reference to a memory zone, it must lie
1865 in a register, so we reserve the register in the
1866 input registers and a load will be generated
1868 if (j
< nb_outputs
|| c
== 'm') {
1869 if ((op
->vt
->r
& VT_VALMASK
) == VT_LLOCAL
) {
1870 /* any general register */
1871 for (reg
= 0; reg
<= 8; reg
++) {
1872 if (!(regs_allocated
[reg
] & REG_IN_MASK
))
1877 /* now we can reload in the register */
1878 regs_allocated
[reg
] |= REG_IN_MASK
;
1885 tcc_error("asm constraint %d ('%s') could not be satisfied",
1889 /* if a reference is present for that operand, we assign it too */
1890 if (op
->input_index
>= 0) {
1891 operands
[op
->input_index
].reg
= op
->reg
;
1892 operands
[op
->input_index
].is_llong
= op
->is_llong
;
1896 /* compute out_reg. It is used to store outputs registers to memory
1897 locations references by pointers (VT_LLOCAL case) */
1899 for (i
= 0; i
< nb_operands
; i
++) {
1902 (op
->vt
->r
& VT_VALMASK
) == VT_LLOCAL
&& !op
->is_memory
) {
1903 for (reg
= 0; reg
<= 8; reg
++) {
1904 if (!(regs_allocated
[reg
] & REG_OUT_MASK
))
1907 tcc_error("could not find free output register for reloading");
1914 /* print sorted constraints */
1916 for (i
= 0; i
< nb_operands
; i
++) {
1919 printf("%%%d [%s]: \"%s\" r=0x%04x reg=%d\n",
1921 op
->id
? get_tok_str(op
->id
, NULL
) : "",
1922 op
->constraint
, op
->vt
->r
, op
->reg
);
1925 printf("out_reg=%d\n", *pout_reg
);
1929 ST_FUNC
void asm_clobber(uint8_t *clobber_regs
, const char *str
)
1934 if (!strcmp(str
, "memory") ||
1935 !strcmp(str
, "cc") ||
1936 !strcmp(str
, "flags"))
1938 ts
= tok_alloc(str
, strlen(str
));
1939 reg
= asm_parse_regvar(ts
->tok
);
1941 tcc_error("invalid clobber register '%s'", str
);
1943 clobber_regs
[reg
] = 1;
1946 /* If T refers to a register then return the register number and type.
1947 Otherwise return -1. */
1948 ST_FUNC
int asm_parse_regvar (int t
)
1950 if (t
>= TOK_ASM_r0
&& t
<= TOK_ASM_pc
) { /* register name */
1953 return TOK_ASM_r11
- TOK_ASM_r0
;
1955 return TOK_ASM_r12
- TOK_ASM_r0
;
1957 return TOK_ASM_r13
- TOK_ASM_r0
;
1959 return TOK_ASM_r14
- TOK_ASM_r0
;
1961 return TOK_ASM_r15
- TOK_ASM_r0
;
1963 return t
- TOK_ASM_r0
;
1969 /*************************************************************/
1970 #endif /* ndef TARGET_DEFS_ONLY */