tcc.h: Extend search path for include, lib and crt.
[tinycc.git] / arm-asm.c
bloba4f974f6529ce69da6da264e17306c3ede976995
1 /*
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 /*************************************************************/
32 #else
33 /*************************************************************/
35 #define USING_GLOBALS
36 #include "tcc.h"
38 enum {
39 OPT_REG32,
40 OPT_REGSET32,
41 OPT_IM8,
42 OPT_IM8N,
43 OPT_IM32,
44 OPT_VREG32,
45 OPT_VREG64,
47 #define OP_REG32 (1 << OPT_REG32)
48 #define OP_VREG32 (1 << OPT_VREG32)
49 #define OP_VREG64 (1 << OPT_VREG64)
50 #define OP_REG (OP_REG32 | OP_VREG32 | OP_VREG64)
51 #define OP_IM32 (1 << OPT_IM32)
52 #define OP_IM8 (1 << OPT_IM8)
53 #define OP_IM8N (1 << OPT_IM8N)
54 #define OP_REGSET32 (1 << OPT_REGSET32)
56 typedef struct Operand {
57 uint32_t type;
58 union {
59 uint8_t reg;
60 uint16_t regset;
61 ExprValue e;
63 } Operand;
65 /* Read the VFP register referred to by token T.
66 If OK, returns its number.
67 If not OK, returns -1. */
68 static int asm_parse_vfp_regvar(int t, int double_precision)
70 if (double_precision) {
71 if (t >= TOK_ASM_d0 && t <= TOK_ASM_d15)
72 return t - TOK_ASM_d0;
73 } else {
74 if (t >= TOK_ASM_s0 && t <= TOK_ASM_s31)
75 return t - TOK_ASM_s0;
77 return -1;
80 __attribute__((unused))
81 static int asm_parse_vfp_status_regvar(int t)
83 switch (t) {
84 case TOK_ASM_fpsid:
85 return 0;
86 case TOK_ASM_fpscr:
87 return 1;
88 case TOK_ASM_fpexc:
89 return 8;
90 default:
91 return -1;
95 /* Parse a text containing operand and store the result in OP */
96 static void parse_operand(TCCState *s1, Operand *op)
98 ExprValue e;
99 int8_t reg;
100 uint16_t regset = 0;
102 op->type = 0;
104 if (tok == '{') { // regset literal
105 next(); // skip '{'
106 while (tok != '}' && tok != TOK_EOF) {
107 reg = asm_parse_regvar(tok);
108 if (reg == -1) {
109 expect("register");
110 return;
111 } else
112 next(); // skip register name
114 if ((1 << reg) < regset)
115 tcc_warning("registers will be processed in ascending order by hardware--but are not specified in ascending order here");
116 regset |= 1 << reg;
117 if (tok != ',')
118 break;
119 next(); // skip ','
121 if (tok != '}')
122 expect("'}'");
123 next(); // skip '}'
124 if (regset == 0) {
125 // ARM instructions don't support empty regset.
126 tcc_error("empty register list is not supported");
127 } else {
128 op->type = OP_REGSET32;
129 op->regset = regset;
131 return;
132 } else if ((reg = asm_parse_regvar(tok)) != -1) {
133 next(); // skip register name
134 op->type = OP_REG32;
135 op->reg = (uint8_t) reg;
136 return;
137 } else if ((reg = asm_parse_vfp_regvar(tok, 0)) != -1) {
138 next(); // skip register name
139 op->type = OP_VREG32;
140 op->reg = (uint8_t) reg;
141 return;
142 } else if ((reg = asm_parse_vfp_regvar(tok, 1)) != -1) {
143 next(); // skip register name
144 op->type = OP_VREG64;
145 op->reg = (uint8_t) reg;
146 return;
147 } else if (tok == '#' || tok == '$') {
148 /* constant value */
149 next(); // skip '#' or '$'
151 asm_expr(s1, &e);
152 op->type = OP_IM32;
153 op->e = e;
154 if (!op->e.sym) {
155 if ((int) op->e.v < 0 && (int) op->e.v >= -255)
156 op->type = OP_IM8N;
157 else if (op->e.v == (uint8_t)op->e.v)
158 op->type = OP_IM8;
159 } else
160 expect("operand");
163 /* XXX: make it faster ? */
164 ST_FUNC void g(int c)
166 int ind1;
167 if (nocode_wanted)
168 return;
169 ind1 = ind + 1;
170 if (ind1 > cur_text_section->data_allocated)
171 section_realloc(cur_text_section, ind1);
172 cur_text_section->data[ind] = c;
173 ind = ind1;
176 ST_FUNC void gen_le16 (int i)
178 g(i);
179 g(i>>8);
182 ST_FUNC void gen_le32 (int i)
184 int ind1;
185 if (nocode_wanted)
186 return;
187 ind1 = ind + 4;
188 if (ind1 > cur_text_section->data_allocated)
189 section_realloc(cur_text_section, ind1);
190 cur_text_section->data[ind++] = i & 0xFF;
191 cur_text_section->data[ind++] = (i >> 8) & 0xFF;
192 cur_text_section->data[ind++] = (i >> 16) & 0xFF;
193 cur_text_section->data[ind++] = (i >> 24) & 0xFF;
196 ST_FUNC void gen_expr32(ExprValue *pe)
198 gen_le32(pe->v);
201 static uint32_t condition_code_of_token(int token) {
202 if (token < TOK_ASM_nopeq) {
203 expect("condition-enabled instruction");
204 return 0;
205 } else
206 return (token - TOK_ASM_nopeq) & 15;
209 static void asm_emit_opcode(int token, uint32_t opcode) {
210 gen_le32((condition_code_of_token(token) << 28) | opcode);
213 static void asm_emit_unconditional_opcode(uint32_t opcode) {
214 gen_le32(opcode);
217 static void asm_emit_coprocessor_opcode(uint32_t high_nibble, uint8_t cp_number, uint8_t cp_opcode, uint8_t cp_destination_register, uint8_t cp_n_operand_register, uint8_t cp_m_operand_register, uint8_t cp_opcode2, int inter_processor_transfer)
219 uint32_t opcode = 0xe000000;
220 if (inter_processor_transfer)
221 opcode |= 1 << 4;
222 //assert(cp_opcode < 16);
223 opcode |= cp_opcode << 20;
224 //assert(cp_n_operand_register < 16);
225 opcode |= cp_n_operand_register << 16;
226 //assert(cp_destination_register < 16);
227 opcode |= cp_destination_register << 12;
228 //assert(cp_number < 16);
229 opcode |= cp_number << 8;
230 //assert(cp_information < 8);
231 opcode |= cp_opcode2 << 5;
232 //assert(cp_m_operand_register < 16);
233 opcode |= cp_m_operand_register;
234 asm_emit_unconditional_opcode((high_nibble << 28) | opcode);
237 static void asm_nullary_opcode(int token)
239 switch (ARM_INSTRUCTION_GROUP(token)) {
240 case TOK_ASM_nopeq:
241 asm_emit_opcode(token, 0xd << 21); // mov r0, r0
242 break;
243 case TOK_ASM_wfeeq:
244 asm_emit_opcode(token, 0x320f002);
245 case TOK_ASM_wfieq:
246 asm_emit_opcode(token, 0x320f003);
247 break;
248 default:
249 expect("nullary instruction");
253 static void asm_unary_opcode(TCCState *s1, int token)
255 Operand op;
256 parse_operand(s1, &op);
258 switch (ARM_INSTRUCTION_GROUP(token)) {
259 case TOK_ASM_swieq:
260 case TOK_ASM_svceq:
261 if (op.type != OP_IM8)
262 expect("immediate 8-bit unsigned integer");
263 else {
264 /* Note: Dummy operand (ignored by processor): ARM ref documented 0...255, ARM instruction set documented 24 bit */
265 asm_emit_opcode(token, (0xf << 24) | op.e.v);
267 break;
268 default:
269 expect("unary instruction");
273 static void asm_binary_opcode(TCCState *s1, int token)
275 Operand ops[2];
276 Operand rotation;
277 uint32_t encoded_rotation = 0;
278 uint64_t amount;
279 parse_operand(s1, &ops[0]);
280 if (tok == ',')
281 next();
282 else
283 expect("','");
284 parse_operand(s1, &ops[1]);
285 if (ops[0].type != OP_REG32) {
286 expect("(destination operand) register");
287 return;
290 if (ops[0].reg == 15) {
291 tcc_error("'%s' does not support 'pc' as operand", get_tok_str(token, NULL));
292 return;
295 if (ops[0].reg == 13)
296 tcc_warning("Using 'sp' as operand with '%s' is deprecated by ARM", get_tok_str(token, NULL));
298 if (ops[1].type != OP_REG32) {
299 switch (ARM_INSTRUCTION_GROUP(token)) {
300 case TOK_ASM_movteq:
301 case TOK_ASM_movweq:
302 if (ops[1].type == OP_IM8 || ops[1].type == OP_IM8N || ops[1].type == OP_IM32) {
303 if (ops[1].e.v >= 0 && ops[1].e.v <= 0xFFFF) {
304 uint16_t immediate_value = ops[1].e.v;
305 switch (ARM_INSTRUCTION_GROUP(token)) {
306 case TOK_ASM_movteq:
307 asm_emit_opcode(token, 0x3400000 | (ops[0].reg << 12) | (immediate_value & 0xF000) << 4 | (immediate_value & 0xFFF));
308 break;
309 case TOK_ASM_movweq:
310 asm_emit_opcode(token, 0x3000000 | (ops[0].reg << 12) | (immediate_value & 0xF000) << 4 | (immediate_value & 0xFFF));
311 break;
313 } else
314 expect("(source operand) immediate 16 bit value");
315 } else
316 expect("(source operand) immediate");
317 break;
318 default:
319 expect("(source operand) register");
321 return;
324 if (ops[1].reg == 15) {
325 tcc_error("'%s' does not support 'pc' as operand", get_tok_str(token, NULL));
326 return;
329 if (ops[1].reg == 13)
330 tcc_warning("Using 'sp' as operand with '%s' is deprecated by ARM", get_tok_str(token, NULL));
332 if (tok == ',') {
333 next(); // skip ','
334 if (tok == TOK_ASM_ror) {
335 next(); // skip 'ror'
336 parse_operand(s1, &rotation);
337 if (rotation.type != OP_IM8) {
338 expect("immediate value for rotation");
339 return;
340 } else {
341 amount = rotation.e.v;
342 switch (amount) {
343 case 8:
344 encoded_rotation = 1 << 10;
345 break;
346 case 16:
347 encoded_rotation = 2 << 10;
348 break;
349 case 24:
350 encoded_rotation = 3 << 10;
351 break;
352 default:
353 expect("'8' or '16' or '24'");
354 return;
359 switch (ARM_INSTRUCTION_GROUP(token)) {
360 case TOK_ASM_clzeq:
361 if (encoded_rotation)
362 tcc_error("clz does not support rotation");
363 asm_emit_opcode(token, 0x16f0f10 | (ops[0].reg << 12) | ops[1].reg);
364 break;
365 case TOK_ASM_sxtbeq:
366 asm_emit_opcode(token, 0x6af0070 | (ops[0].reg << 12) | ops[1].reg | encoded_rotation);
367 break;
368 case TOK_ASM_sxtheq:
369 asm_emit_opcode(token, 0x6bf0070 | (ops[0].reg << 12) | ops[1].reg | encoded_rotation);
370 break;
371 case TOK_ASM_uxtbeq:
372 asm_emit_opcode(token, 0x6ef0070 | (ops[0].reg << 12) | ops[1].reg | encoded_rotation);
373 break;
374 case TOK_ASM_uxtheq:
375 asm_emit_opcode(token, 0x6ff0070 | (ops[0].reg << 12) | ops[1].reg | encoded_rotation);
376 break;
377 default:
378 expect("binary instruction");
382 static void asm_coprocessor_opcode(TCCState *s1, int token) {
383 uint8_t coprocessor;
384 Operand opcode1;
385 Operand opcode2;
386 uint8_t registers[3];
387 unsigned int i;
388 uint8_t high_nibble;
389 uint8_t mrc = 0;
391 if (tok >= TOK_ASM_p0 && tok <= TOK_ASM_p15) {
392 coprocessor = tok - TOK_ASM_p0;
393 next();
394 } else {
395 expect("'p<number>'");
396 return;
399 if (tok == ',')
400 next();
401 else
402 expect("','");
404 parse_operand(s1, &opcode1);
405 if (opcode1.type != OP_IM8 || opcode1.e.v > 15) {
406 tcc_error("opcode1 of instruction '%s' must be an immediate value between 0 and 15", get_tok_str(token, NULL));
407 return;
410 for (i = 0; i < 3; ++i) {
411 if (tok == ',')
412 next();
413 else
414 expect("','");
415 if (i == 0 && token != TOK_ASM_cdp2 && (ARM_INSTRUCTION_GROUP(token) == TOK_ASM_mrceq || ARM_INSTRUCTION_GROUP(token) == TOK_ASM_mcreq)) {
416 if (tok >= TOK_ASM_r0 && tok <= TOK_ASM_r15) {
417 registers[i] = tok - TOK_ASM_r0;
418 next();
419 } else {
420 expect("'r<number>'");
421 return;
423 } else {
424 if (tok >= TOK_ASM_c0 && tok <= TOK_ASM_c15) {
425 registers[i] = tok - TOK_ASM_c0;
426 next();
427 } else {
428 expect("'c<number>'");
429 return;
433 if (tok == ',') {
434 next();
435 parse_operand(s1, &opcode2);
436 } else {
437 opcode2.type = OP_IM8;
438 opcode2.e.v = 0;
440 if (opcode2.type != OP_IM8 || opcode2.e.v > 15) {
441 tcc_error("opcode2 of instruction '%s' must be an immediate value between 0 and 15", get_tok_str(token, NULL));
442 return;
445 if (token == TOK_ASM_cdp2) {
446 high_nibble = 0xF;
447 asm_emit_coprocessor_opcode(high_nibble, coprocessor, opcode1.e.v, registers[0], registers[1], registers[2], opcode2.e.v, 0);
448 return;
449 } else
450 high_nibble = condition_code_of_token(token);
452 switch (ARM_INSTRUCTION_GROUP(token)) {
453 case TOK_ASM_cdpeq:
454 asm_emit_coprocessor_opcode(high_nibble, coprocessor, opcode1.e.v, registers[0], registers[1], registers[2], opcode2.e.v, 0);
455 break;
456 case TOK_ASM_mrceq:
457 // opcode1 encoding changes! highest and lowest bit gone.
458 mrc = 1;
459 /* fallthrough */
460 case TOK_ASM_mcreq:
461 // opcode1 encoding changes! highest and lowest bit gone.
462 if (opcode1.e.v > 7) {
463 tcc_error("opcode1 of instruction '%s' must be an immediate value between 0 and 7", get_tok_str(token, NULL));
464 return;
466 asm_emit_coprocessor_opcode(high_nibble, coprocessor, (opcode1.e.v << 1) | mrc, registers[0], registers[1], registers[2], opcode2.e.v, 1);
467 break;
468 default:
469 expect("known instruction");
473 /* data processing and single data transfer instructions only */
474 #define ENCODE_RN(register_index) ((register_index) << 16)
475 #define ENCODE_RD(register_index) ((register_index) << 12)
476 #define ENCODE_SET_CONDITION_CODES (1 << 20)
478 /* Note: For data processing instructions, "1" means immediate.
479 Note: For single data transfer instructions, "0" means immediate. */
480 #define ENCODE_IMMEDIATE_FLAG (1 << 25)
482 #define ENCODE_BARREL_SHIFTER_SHIFT_BY_REGISTER (1 << 4)
483 #define ENCODE_BARREL_SHIFTER_MODE_LSL (0 << 5)
484 #define ENCODE_BARREL_SHIFTER_MODE_LSR (1 << 5)
485 #define ENCODE_BARREL_SHIFTER_MODE_ASR (2 << 5)
486 #define ENCODE_BARREL_SHIFTER_MODE_ROR (3 << 5)
487 #define ENCODE_BARREL_SHIFTER_REGISTER(register_index) ((register_index) << 8)
488 #define ENCODE_BARREL_SHIFTER_IMMEDIATE(value) ((value) << 7)
490 static void asm_block_data_transfer_opcode(TCCState *s1, int token)
492 uint32_t opcode;
493 int op0_exclam = 0;
494 Operand ops[2];
495 int nb_ops = 1;
496 parse_operand(s1, &ops[0]);
497 if (tok == '!') {
498 op0_exclam = 1;
499 next(); // skip '!'
501 if (tok == ',') {
502 next(); // skip comma
503 parse_operand(s1, &ops[1]);
504 ++nb_ops;
506 if (nb_ops < 1) {
507 expect("at least one operand");
508 return;
509 } else if (ops[nb_ops - 1].type != OP_REGSET32) {
510 expect("(last operand) register list");
511 return;
514 // block data transfer: 1 0 0 P U S W L << 20 (general case):
515 // operands:
516 // Rn: bits 19...16 base register
517 // Register List: bits 15...0
519 switch (ARM_INSTRUCTION_GROUP(token)) {
520 case TOK_ASM_pusheq: // TODO: Optimize 1-register case to: str ?, [sp, #-4]!
521 // Instruction: 1 I=0 P=1 U=0 S=0 W=1 L=0 << 20, op 1101
522 // operands:
523 // Rn: base register
524 // Register List: bits 15...0
525 if (nb_ops != 1)
526 expect("exactly one operand");
527 else
528 asm_emit_opcode(token, (0x92d << 16) | ops[0].regset); // TODO: base register ?
529 break;
530 case TOK_ASM_popeq: // TODO: Optimize 1-register case to: ldr ?, [sp], #4
531 // Instruction: 1 I=0 P=0 U=1 S=0 W=0 L=1 << 20, op 1101
532 // operands:
533 // Rn: base register
534 // Register List: bits 15...0
535 if (nb_ops != 1)
536 expect("exactly one operand");
537 else
538 asm_emit_opcode(token, (0x8bd << 16) | ops[0].regset); // TODO: base register ?
539 break;
540 case TOK_ASM_stmdaeq:
541 case TOK_ASM_ldmdaeq:
542 case TOK_ASM_stmeq:
543 case TOK_ASM_ldmeq:
544 case TOK_ASM_stmiaeq:
545 case TOK_ASM_ldmiaeq:
546 case TOK_ASM_stmdbeq:
547 case TOK_ASM_ldmdbeq:
548 case TOK_ASM_stmibeq:
549 case TOK_ASM_ldmibeq:
550 switch (ARM_INSTRUCTION_GROUP(token)) {
551 case TOK_ASM_stmdaeq: // post-decrement store
552 opcode = 0x80 << 20;
553 break;
554 case TOK_ASM_ldmdaeq: // post-decrement load
555 opcode = 0x81 << 20;
556 break;
557 case TOK_ASM_stmeq: // post-increment store
558 case TOK_ASM_stmiaeq: // post-increment store
559 opcode = 0x88 << 20;
560 break;
561 case TOK_ASM_ldmeq: // post-increment load
562 case TOK_ASM_ldmiaeq: // post-increment load
563 opcode = 0x89 << 20;
564 break;
565 case TOK_ASM_stmdbeq: // pre-decrement store
566 opcode = 0x90 << 20;
567 break;
568 case TOK_ASM_ldmdbeq: // pre-decrement load
569 opcode = 0x91 << 20;
570 break;
571 case TOK_ASM_stmibeq: // pre-increment store
572 opcode = 0x98 << 20;
573 break;
574 case TOK_ASM_ldmibeq: // pre-increment load
575 opcode = 0x99 << 20;
576 break;
577 default:
578 tcc_error("internal error: This place should not be reached (fallback in asm_block_data_transfer_opcode)");
580 // operands:
581 // Rn: first operand
582 // Register List: lower bits
583 if (nb_ops != 2)
584 expect("exactly two operands");
585 else if (ops[0].type != OP_REG32)
586 expect("(first operand) register");
587 else {
588 if (op0_exclam)
589 opcode |= 1 << 21; // writeback
590 asm_emit_opcode(token, opcode | ENCODE_RN(ops[0].reg) | ops[1].regset);
592 break;
593 default:
594 expect("block data transfer instruction");
598 /* Parses shift directive and returns the parts that would have to be set in the opcode because of it.
599 Does not encode the actual shift amount.
600 It's not an error if there is no shift directive.
602 NB_SHIFT: will be set to 1 iff SHIFT is filled. Note that for rrx, there's no need to fill SHIFT.
603 SHIFT: will be filled in with the shift operand to use, if any. */
604 static uint32_t asm_parse_optional_shift(TCCState* s1, int* nb_shift, Operand* shift)
606 uint32_t opcode = 0;
607 *nb_shift = 0;
608 switch (tok) {
609 case TOK_ASM_asl:
610 case TOK_ASM_lsl:
611 case TOK_ASM_asr:
612 case TOK_ASM_lsr:
613 case TOK_ASM_ror:
614 switch (tok) {
615 case TOK_ASM_asl:
616 /* fallthrough */
617 case TOK_ASM_lsl:
618 opcode = ENCODE_BARREL_SHIFTER_MODE_LSL;
619 break;
620 case TOK_ASM_asr:
621 opcode = ENCODE_BARREL_SHIFTER_MODE_ASR;
622 break;
623 case TOK_ASM_lsr:
624 opcode = ENCODE_BARREL_SHIFTER_MODE_LSR;
625 break;
626 case TOK_ASM_ror:
627 opcode = ENCODE_BARREL_SHIFTER_MODE_ROR;
628 break;
630 next();
631 parse_operand(s1, shift);
632 *nb_shift = 1;
633 break;
634 case TOK_ASM_rrx:
635 next();
636 opcode = ENCODE_BARREL_SHIFTER_MODE_ROR;
637 break;
639 return opcode;
642 static uint32_t asm_encode_shift(Operand* shift)
644 uint64_t amount;
645 uint32_t operands = 0;
646 switch (shift->type) {
647 case OP_REG32:
648 if (shift->reg == 15)
649 tcc_error("r15 cannot be used as a shift count");
650 else {
651 operands = ENCODE_BARREL_SHIFTER_SHIFT_BY_REGISTER;
652 operands |= ENCODE_BARREL_SHIFTER_REGISTER(shift->reg);
654 break;
655 case OP_IM8:
656 amount = shift->e.v;
657 if (amount > 0 && amount < 32)
658 operands = ENCODE_BARREL_SHIFTER_IMMEDIATE(amount);
659 else
660 tcc_error("shift count out of range");
661 break;
662 default:
663 tcc_error("unknown shift amount");
665 return operands;
668 static void asm_data_processing_opcode(TCCState *s1, int token)
670 Operand ops[3];
671 int nb_ops;
672 Operand shift = {0};
673 int nb_shift = 0;
674 uint32_t operands = 0;
676 /* modulo 16 entries per instruction for the different condition codes */
677 uint32_t opcode_idx = (ARM_INSTRUCTION_GROUP(token) - TOK_ASM_andeq) >> 4;
678 uint32_t opcode_nos = opcode_idx >> 1; // without "s"; "OpCode" in ARM docs
680 for (nb_ops = 0; nb_ops < sizeof(ops)/sizeof(ops[0]); ) {
681 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)
682 break;
683 parse_operand(s1, &ops[nb_ops]);
684 ++nb_ops;
685 if (tok != ',')
686 break;
687 next(); // skip ','
689 if (tok == ',')
690 next();
691 operands |= asm_parse_optional_shift(s1, &nb_shift, &shift);
692 if (nb_ops < 2)
693 expect("at least two operands");
694 else if (nb_ops == 2) {
695 memcpy(&ops[2], &ops[1], sizeof(ops[1])); // move ops[2]
696 memcpy(&ops[1], &ops[0], sizeof(ops[0])); // ops[1] was implicit
697 nb_ops = 3;
698 } else if (nb_ops == 3) {
699 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
700 tcc_error("'%s' cannot be used with three operands", get_tok_str(token, NULL));
701 return;
704 if (nb_ops != 3) {
705 expect("two or three operands");
706 return;
707 } else {
708 uint32_t opcode = 0;
709 uint32_t immediate_value;
710 uint8_t half_immediate_rotation;
711 if (nb_shift && shift.type == OP_REG32) {
712 if ((ops[0].type == OP_REG32 && ops[0].reg == 15) ||
713 (ops[1].type == OP_REG32 && ops[1].reg == 15)) {
714 tcc_error("Using the 'pc' register in data processing instructions that have a register-controlled shift is not implemented by ARM");
715 return;
719 // data processing (general case):
720 // operands:
721 // Rn: bits 19...16 (first operand)
722 // Rd: bits 15...12 (destination)
723 // Operand2: bits 11...0 (second operand); depending on I that's either a register or an immediate
724 // operator:
725 // bits 24...21: "OpCode"--see below
727 /* operations in the token list are ordered by opcode */
728 opcode = opcode_nos << 21; // drop "s"
729 if (ops[0].type != OP_REG32)
730 expect("(destination operand) register");
731 else if (opcode_nos == 0xa || opcode_nos == 0xb || opcode_nos == 0x8 || opcode_nos == 0x9) // cmp, cmn, tst, teq
732 operands |= ENCODE_SET_CONDITION_CODES; // force S set, otherwise it's a completely different instruction.
733 else
734 operands |= ENCODE_RD(ops[0].reg);
735 if (ops[1].type != OP_REG32)
736 expect("(first source operand) register");
737 else if (!(opcode_nos == 0xd || opcode_nos == 0xf)) // not: mov, mvn (those have only one source operand)
738 operands |= ENCODE_RN(ops[1].reg);
739 switch (ops[2].type) {
740 case OP_REG32:
741 operands |= ops[2].reg;
742 break;
743 case OP_IM8:
744 case OP_IM32:
745 operands |= ENCODE_IMMEDIATE_FLAG;
746 immediate_value = ops[2].e.v;
747 for (half_immediate_rotation = 0; half_immediate_rotation < 16; ++half_immediate_rotation) {
748 if (immediate_value >= 0x00 && immediate_value < 0x100)
749 break;
750 // rotate left by two
751 immediate_value = ((immediate_value & 0x3FFFFFFF) << 2) | ((immediate_value & 0xC0000000) >> 30);
753 if (half_immediate_rotation >= 16) {
754 /* fallthrough */
755 } else {
756 operands |= immediate_value;
757 operands |= half_immediate_rotation << 8;
758 break;
760 case OP_IM8N: // immediate negative value
761 operands |= ENCODE_IMMEDIATE_FLAG;
762 immediate_value = ops[2].e.v;
763 /* Instruction swapping:
764 0001 = EOR - Rd:= Op1 EOR Op2 -> difficult
765 0011 = RSB - Rd:= Op2 - Op1 -> difficult
766 0111 = RSC - Rd:= Op2 - Op1 + C -> difficult
767 1000 = TST - CC on: Op1 AND Op2 -> difficult
768 1001 = TEQ - CC on: Op1 EOR Op2 -> difficult
769 1100 = ORR - Rd:= Op1 OR Op2 -> difficult
771 switch (opcode_nos) {
772 case 0x0: // AND - Rd:= Op1 AND Op2
773 opcode = 0xe << 21; // BIC
774 immediate_value = ~immediate_value;
775 break;
776 case 0x2: // SUB - Rd:= Op1 - Op2
777 opcode = 0x4 << 21; // ADD
778 immediate_value = -immediate_value;
779 break;
780 case 0x4: // ADD - Rd:= Op1 + Op2
781 opcode = 0x2 << 21; // SUB
782 immediate_value = -immediate_value;
783 break;
784 case 0x5: // ADC - Rd:= Op1 + Op2 + C
785 opcode = 0x6 << 21; // SBC
786 immediate_value = ~immediate_value;
787 break;
788 case 0x6: // SBC - Rd:= Op1 - Op2 + C
789 opcode = 0x5 << 21; // ADC
790 immediate_value = ~immediate_value;
791 break;
792 case 0xa: // CMP - CC on: Op1 - Op2
793 opcode = 0xb << 21; // CMN
794 immediate_value = -immediate_value;
795 break;
796 case 0xb: // CMN - CC on: Op1 + Op2
797 opcode = 0xa << 21; // CMP
798 immediate_value = -immediate_value;
799 break;
800 case 0xd: // MOV - Rd:= Op2
801 opcode = 0xf << 21; // MVN
802 immediate_value = ~immediate_value;
803 break;
804 case 0xe: // BIC - Rd:= Op1 AND NOT Op2
805 opcode = 0x0 << 21; // AND
806 immediate_value = ~immediate_value;
807 break;
808 case 0xf: // MVN - Rd:= NOT Op2
809 opcode = 0xd << 21; // MOV
810 immediate_value = ~immediate_value;
811 break;
812 default:
813 tcc_error("cannot use '%s' with a negative immediate value", get_tok_str(token, NULL));
815 for (half_immediate_rotation = 0; half_immediate_rotation < 16; ++half_immediate_rotation) {
816 if (immediate_value >= 0x00 && immediate_value < 0x100)
817 break;
818 // rotate left by two
819 immediate_value = ((immediate_value & 0x3FFFFFFF) << 2) | ((immediate_value & 0xC0000000) >> 30);
821 if (half_immediate_rotation >= 16) {
822 immediate_value = ops[2].e.v;
823 tcc_error("immediate value 0x%X cannot be encoded into ARM immediate", (unsigned) immediate_value);
824 return;
826 operands |= immediate_value;
827 operands |= half_immediate_rotation << 8;
828 break;
829 default:
830 expect("(second source operand) register or immediate value");
833 if (nb_shift) {
834 if (operands & ENCODE_IMMEDIATE_FLAG)
835 tcc_error("immediate rotation not implemented");
836 else
837 operands |= asm_encode_shift(&shift);
840 /* S=0 and S=1 entries alternate one after another, in that order */
841 opcode |= (opcode_idx & 1) ? ENCODE_SET_CONDITION_CODES : 0;
842 asm_emit_opcode(token, opcode | operands);
846 static void asm_shift_opcode(TCCState *s1, int token)
848 Operand ops[3];
849 int nb_ops;
850 int definitely_neutral = 0;
851 uint32_t opcode = 0xd << 21; // MOV
852 uint32_t operands = 0;
854 for (nb_ops = 0; nb_ops < sizeof(ops)/sizeof(ops[0]); ++nb_ops) {
855 parse_operand(s1, &ops[nb_ops]);
856 if (tok != ',') {
857 ++nb_ops;
858 break;
860 next(); // skip ','
862 if (nb_ops < 2) {
863 expect("at least two operands");
864 return;
867 if (ops[0].type != OP_REG32) {
868 expect("(destination operand) register");
869 return;
870 } else
871 operands |= ENCODE_RD(ops[0].reg);
873 if (nb_ops == 2) {
874 switch (ARM_INSTRUCTION_GROUP(token)) {
875 case TOK_ASM_rrxseq:
876 opcode |= ENCODE_SET_CONDITION_CODES;
877 /* fallthrough */
878 case TOK_ASM_rrxeq:
879 if (ops[1].type == OP_REG32) {
880 operands |= ops[1].reg;
881 operands |= ENCODE_BARREL_SHIFTER_MODE_ROR;
882 asm_emit_opcode(token, opcode | operands);
883 } else
884 tcc_error("(first source operand) register");
885 return;
886 default:
887 memcpy(&ops[2], &ops[1], sizeof(ops[1])); // move ops[2]
888 memcpy(&ops[1], &ops[0], sizeof(ops[0])); // ops[1] was implicit
889 nb_ops = 3;
892 if (nb_ops != 3) {
893 expect("two or three operands");
894 return;
897 switch (ARM_INSTRUCTION_GROUP(token)) {
898 case TOK_ASM_lslseq:
899 case TOK_ASM_lsrseq:
900 case TOK_ASM_asrseq:
901 case TOK_ASM_rorseq:
902 opcode |= ENCODE_SET_CONDITION_CODES;
903 break;
906 switch (ops[1].type) {
907 case OP_REG32:
908 operands |= ops[1].reg;
909 break;
910 case OP_IM8:
911 operands |= ENCODE_IMMEDIATE_FLAG;
912 operands |= ops[1].e.v;
913 tcc_error("Using an immediate value as the source operand is not possible with '%s' instruction on ARM", get_tok_str(token, NULL));
914 return;
917 switch (ops[2].type) {
918 case OP_REG32:
919 if ((ops[0].type == OP_REG32 && ops[0].reg == 15) ||
920 (ops[1].type == OP_REG32 && ops[1].reg == 15)) {
921 tcc_error("Using the 'pc' register in data processing instructions that have a register-controlled shift is not implemented by ARM");
923 operands |= asm_encode_shift(&ops[2]);
924 break;
925 case OP_IM8:
926 if (ops[2].e.v)
927 operands |= asm_encode_shift(&ops[2]);
928 else
929 definitely_neutral = 1;
930 break;
933 if (!definitely_neutral) switch (ARM_INSTRUCTION_GROUP(token)) {
934 case TOK_ASM_lslseq:
935 case TOK_ASM_lsleq:
936 operands |= ENCODE_BARREL_SHIFTER_MODE_LSL;
937 break;
938 case TOK_ASM_lsrseq:
939 case TOK_ASM_lsreq:
940 operands |= ENCODE_BARREL_SHIFTER_MODE_LSR;
941 break;
942 case TOK_ASM_asrseq:
943 case TOK_ASM_asreq:
944 operands |= ENCODE_BARREL_SHIFTER_MODE_ASR;
945 break;
946 case TOK_ASM_rorseq:
947 case TOK_ASM_roreq:
948 operands |= ENCODE_BARREL_SHIFTER_MODE_ROR;
949 break;
950 default:
951 expect("shift instruction");
952 return;
954 asm_emit_opcode(token, opcode | operands);
957 static void asm_multiplication_opcode(TCCState *s1, int token)
959 Operand ops[4];
960 int nb_ops = 0;
961 uint32_t opcode = 0x90;
963 for (nb_ops = 0; nb_ops < sizeof(ops)/sizeof(ops[0]); ++nb_ops) {
964 parse_operand(s1, &ops[nb_ops]);
965 if (tok != ',') {
966 ++nb_ops;
967 break;
969 next(); // skip ','
971 if (nb_ops < 2)
972 expect("at least two operands");
973 else if (nb_ops == 2) {
974 switch (ARM_INSTRUCTION_GROUP(token)) {
975 case TOK_ASM_mulseq:
976 case TOK_ASM_muleq:
977 memcpy(&ops[2], &ops[0], sizeof(ops[1])); // ARM is actually like this!
978 break;
979 default:
980 expect("at least three operands");
981 return;
983 nb_ops = 3;
986 // multiply (special case):
987 // operands:
988 // Rd: bits 19...16
989 // Rm: bits 3...0
990 // Rs: bits 11...8
991 // Rn: bits 15...12
993 if (ops[0].type == OP_REG32)
994 opcode |= ops[0].reg << 16;
995 else
996 expect("(destination operand) register");
997 if (ops[1].type == OP_REG32)
998 opcode |= ops[1].reg;
999 else
1000 expect("(first source operand) register");
1001 if (ops[2].type == OP_REG32)
1002 opcode |= ops[2].reg << 8;
1003 else
1004 expect("(second source operand) register");
1005 if (nb_ops > 3) {
1006 if (ops[3].type == OP_REG32)
1007 opcode |= ops[3].reg << 12;
1008 else
1009 expect("(third source operand) register");
1012 switch (ARM_INSTRUCTION_GROUP(token)) {
1013 case TOK_ASM_mulseq:
1014 opcode |= 1 << 20; // Status
1015 /* fallthrough */
1016 case TOK_ASM_muleq:
1017 if (nb_ops != 3)
1018 expect("three operands");
1019 else {
1020 asm_emit_opcode(token, opcode);
1022 break;
1023 case TOK_ASM_mlaseq:
1024 opcode |= 1 << 20; // Status
1025 /* fallthrough */
1026 case TOK_ASM_mlaeq:
1027 if (nb_ops != 4)
1028 expect("four operands");
1029 else {
1030 opcode |= 1 << 21; // Accumulate
1031 asm_emit_opcode(token, opcode);
1033 break;
1034 default:
1035 expect("known multiplication instruction");
1039 static void asm_long_multiplication_opcode(TCCState *s1, int token)
1041 Operand ops[4];
1042 int nb_ops = 0;
1043 uint32_t opcode = 0x90 | (1 << 23);
1045 for (nb_ops = 0; nb_ops < sizeof(ops)/sizeof(ops[0]); ++nb_ops) {
1046 parse_operand(s1, &ops[nb_ops]);
1047 if (tok != ',') {
1048 ++nb_ops;
1049 break;
1051 next(); // skip ','
1053 if (nb_ops != 4) {
1054 expect("four operands");
1055 return;
1058 // long multiply (special case):
1059 // operands:
1060 // RdLo: bits 15...12
1061 // RdHi: bits 19...16
1062 // Rs: bits 11...8
1063 // Rm: bits 3...0
1065 if (ops[0].type == OP_REG32)
1066 opcode |= ops[0].reg << 12;
1067 else
1068 expect("(destination lo accumulator) register");
1069 if (ops[1].type == OP_REG32)
1070 opcode |= ops[1].reg << 16;
1071 else
1072 expect("(destination hi accumulator) register");
1073 if (ops[2].type == OP_REG32)
1074 opcode |= ops[2].reg;
1075 else
1076 expect("(first source operand) register");
1077 if (ops[3].type == OP_REG32)
1078 opcode |= ops[3].reg << 8;
1079 else
1080 expect("(second source operand) register");
1082 switch (ARM_INSTRUCTION_GROUP(token)) {
1083 case TOK_ASM_smullseq:
1084 opcode |= 1 << 20; // Status
1085 /* fallthrough */
1086 case TOK_ASM_smulleq:
1087 opcode |= 1 << 22; // signed
1088 asm_emit_opcode(token, opcode);
1089 break;
1090 case TOK_ASM_umullseq:
1091 opcode |= 1 << 20; // Status
1092 /* fallthrough */
1093 case TOK_ASM_umulleq:
1094 asm_emit_opcode(token, opcode);
1095 break;
1096 case TOK_ASM_smlalseq:
1097 opcode |= 1 << 20; // Status
1098 /* fallthrough */
1099 case TOK_ASM_smlaleq:
1100 opcode |= 1 << 22; // signed
1101 opcode |= 1 << 21; // Accumulate
1102 asm_emit_opcode(token, opcode);
1103 break;
1104 case TOK_ASM_umlalseq:
1105 opcode |= 1 << 20; // Status
1106 /* fallthrough */
1107 case TOK_ASM_umlaleq:
1108 opcode |= 1 << 21; // Accumulate
1109 asm_emit_opcode(token, opcode);
1110 break;
1111 default:
1112 expect("known long multiplication instruction");
1116 static void asm_single_data_transfer_opcode(TCCState *s1, int token)
1118 Operand ops[3];
1119 Operand strex_operand;
1120 Operand shift;
1121 int nb_shift = 0;
1122 int exclam = 0;
1123 int closed_bracket = 0;
1124 int op2_minus = 0;
1125 uint32_t opcode = 0;
1126 // Note: ldr r0, [r4, #4] ; simple offset: r0 = *(int*)(r4+4); r4 unchanged
1127 // Note: ldr r0, [r4, #4]! ; pre-indexed: r0 = *(int*)(r4+4); r4 = r4+4
1128 // Note: ldr r0, [r4], #4 ; post-indexed: r0 = *(int*)(r4+0); r4 = r4+4
1130 parse_operand(s1, &ops[0]);
1131 if (ops[0].type == OP_REG32)
1132 opcode |= ENCODE_RD(ops[0].reg);
1133 else {
1134 expect("(destination operand) register");
1135 return;
1137 if (tok != ',')
1138 expect("at least two arguments");
1139 else
1140 next(); // skip ','
1142 switch (ARM_INSTRUCTION_GROUP(token)) {
1143 case TOK_ASM_strexbeq:
1144 case TOK_ASM_strexeq:
1145 parse_operand(s1, &strex_operand);
1146 if (strex_operand.type != OP_REG32) {
1147 expect("register");
1148 return;
1150 if (tok != ',')
1151 expect("at least three arguments");
1152 else
1153 next(); // skip ','
1154 break;
1157 if (tok != '[')
1158 expect("'['");
1159 else
1160 next(); // skip '['
1162 parse_operand(s1, &ops[1]);
1163 if (ops[1].type == OP_REG32)
1164 opcode |= ENCODE_RN(ops[1].reg);
1165 else {
1166 expect("(first source operand) register");
1167 return;
1169 if (tok == ']') {
1170 next();
1171 closed_bracket = 1;
1172 // exclam = 1; // implicit in hardware; don't do it in software
1174 if (tok == ',') {
1175 next(); // skip ','
1176 if (tok == '-') {
1177 op2_minus = 1;
1178 next();
1180 parse_operand(s1, &ops[2]);
1181 if (ops[2].type == OP_REG32) {
1182 if (ops[2].reg == 15) {
1183 tcc_error("Using 'pc' for register offset in '%s' is not implemented by ARM", get_tok_str(token, NULL));
1184 return;
1186 if (tok == ',') {
1187 next();
1188 opcode |= asm_parse_optional_shift(s1, &nb_shift, &shift);
1189 if (opcode == 0)
1190 expect("shift directive, or no comma");
1193 } else {
1194 // end of input expression in brackets--assume 0 offset
1195 ops[2].type = OP_IM8;
1196 ops[2].e.v = 0;
1197 opcode |= 1 << 24; // add offset before transfer
1199 if (!closed_bracket) {
1200 if (tok != ']')
1201 expect("']'");
1202 else
1203 next(); // skip ']'
1204 opcode |= 1 << 24; // add offset before transfer
1205 if (tok == '!') {
1206 exclam = 1;
1207 next(); // skip '!'
1211 // single data transfer: 0 1 I P U B W L << 20 (general case):
1212 // operands:
1213 // Rd: destination operand [ok]
1214 // Rn: first source operand [ok]
1215 // Operand2: bits 11...0 [ok]
1216 // I: immediate operand? [ok]
1217 // P: Pre/post indexing is PRE: Add offset before transfer [ok]
1218 // U: Up/down is up? (*adds* offset to base) [ok]
1219 // B: Byte/word is byte? [ok]
1220 // W: Write address back into base? [ok]
1221 // L: Load/store is load? [ok]
1222 if (exclam)
1223 opcode |= 1 << 21; // write offset back into register
1225 if (ops[2].type == OP_IM32 || ops[2].type == OP_IM8 || ops[2].type == OP_IM8N) {
1226 int v = ops[2].e.v;
1227 if (op2_minus)
1228 tcc_error("minus before '#' not supported for immediate values");
1229 if (v >= 0) {
1230 opcode |= 1 << 23; // up
1231 if (v >= 0x1000)
1232 tcc_error("offset out of range for '%s'", get_tok_str(token, NULL));
1233 else
1234 opcode |= v;
1235 } else { // down
1236 if (v <= -0x1000)
1237 tcc_error("offset out of range for '%s'", get_tok_str(token, NULL));
1238 else
1239 opcode |= -v;
1241 } else if (ops[2].type == OP_REG32) {
1242 if (!op2_minus)
1243 opcode |= 1 << 23; // up
1244 opcode |= ENCODE_IMMEDIATE_FLAG; /* if set, it means it's NOT immediate */
1245 opcode |= ops[2].reg;
1246 } else
1247 expect("register");
1249 switch (ARM_INSTRUCTION_GROUP(token)) {
1250 case TOK_ASM_strbeq:
1251 opcode |= 1 << 22; // B
1252 /* fallthrough */
1253 case TOK_ASM_streq:
1254 opcode |= 1 << 26; // Load/Store
1255 if (nb_shift)
1256 opcode |= asm_encode_shift(&shift);
1257 asm_emit_opcode(token, opcode);
1258 break;
1259 case TOK_ASM_ldrbeq:
1260 opcode |= 1 << 22; // B
1261 /* fallthrough */
1262 case TOK_ASM_ldreq:
1263 opcode |= 1 << 20; // L
1264 opcode |= 1 << 26; // Load/Store
1265 if (nb_shift)
1266 opcode |= asm_encode_shift(&shift);
1267 asm_emit_opcode(token, opcode);
1268 break;
1269 case TOK_ASM_strexbeq:
1270 opcode |= 1 << 22; // B
1271 /* fallthrough */
1272 case TOK_ASM_strexeq:
1273 if ((opcode & 0xFFF) || nb_shift) {
1274 tcc_error("neither offset nor shift allowed with 'strex'");
1275 return;
1276 } else if (opcode & ENCODE_IMMEDIATE_FLAG) { // if set, it means it's NOT immediate
1277 tcc_error("offset not allowed with 'strex'");
1278 return;
1280 if ((opcode & (1 << 24)) == 0) { // add offset after transfer
1281 tcc_error("adding offset after transfer not allowed with 'strex'");
1282 return;
1285 opcode |= 0xf90; // Used to mean: barrel shifter is enabled, barrel shift register is r15, mode is LSL
1286 opcode |= strex_operand.reg;
1287 asm_emit_opcode(token, opcode);
1288 break;
1289 case TOK_ASM_ldrexbeq:
1290 opcode |= 1 << 22; // B
1291 /* fallthrough */
1292 case TOK_ASM_ldrexeq:
1293 if ((opcode & 0xFFF) || nb_shift) {
1294 tcc_error("neither offset nor shift allowed with 'ldrex'");
1295 return;
1296 } else if (opcode & ENCODE_IMMEDIATE_FLAG) { // if set, it means it's NOT immediate
1297 tcc_error("offset not allowed with 'ldrex'");
1298 return;
1300 if ((opcode & (1 << 24)) == 0) { // add offset after transfer
1301 tcc_error("adding offset after transfer not allowed with 'ldrex'");
1302 return;
1304 opcode |= 1 << 20; // L
1305 opcode |= 0x00f;
1306 opcode |= 0xf90; // Used to mean: barrel shifter is enabled, barrel shift register is r15, mode is LSL
1307 asm_emit_opcode(token, opcode);
1308 break;
1309 default:
1310 expect("data transfer instruction");
1314 // Note: Only call this using a VFP register if you know exactly what you are doing (i.e. cp_number is 10 or 11 and you are doing a vmov)
1315 static void asm_emit_coprocessor_data_transfer(uint32_t high_nibble, uint8_t cp_number, uint8_t CRd, const Operand* Rn, const Operand* offset, int offset_minus, int preincrement, int writeback, int long_transfer, int load) {
1316 uint32_t opcode = 0x0;
1317 opcode |= 1 << 26; // Load/Store
1318 opcode |= 1 << 27; // coprocessor
1320 if (long_transfer)
1321 opcode |= 1 << 22; // long transfer
1323 if (load)
1324 opcode |= 1 << 20; // L
1326 opcode |= cp_number << 8;
1328 //assert(CRd < 16);
1329 opcode |= ENCODE_RD(CRd);
1331 if (Rn->type != OP_REG32) {
1332 expect("register");
1333 return;
1335 //assert(Rn->reg < 16);
1336 opcode |= ENCODE_RN(Rn->reg);
1337 if (preincrement)
1338 opcode |= 1 << 24; // add offset before transfer
1340 if (writeback)
1341 opcode |= 1 << 21; // write offset back into register
1343 if (offset->type == OP_IM8 || offset->type == OP_IM8N || offset->type == OP_IM32) {
1344 int v = offset->e.v;
1345 if (offset_minus)
1346 tcc_error("minus before '#' not supported for immediate values");
1347 if (offset->type == OP_IM8N || v < 0)
1348 v = -v;
1349 else
1350 opcode |= 1 << 23; // up
1351 if (v & 3) {
1352 tcc_error("immediate offset must be a multiple of 4");
1353 return;
1355 v >>= 2;
1356 if (v > 255) {
1357 tcc_error("immediate offset must be between -1020 and 1020");
1358 return;
1360 opcode |= v;
1361 } else if (offset->type == OP_REG32) {
1362 if (!offset_minus)
1363 opcode |= 1 << 23; // up
1364 opcode |= ENCODE_IMMEDIATE_FLAG; /* if set, it means it's NOT immediate */
1365 opcode |= offset->reg;
1366 tcc_error("Using register offset to register address is not possible here");
1367 return;
1368 } else if (offset->type == OP_VREG64) {
1369 opcode |= 16;
1370 opcode |= offset->reg;
1371 } else
1372 expect("immediate or register");
1374 asm_emit_unconditional_opcode((high_nibble << 28) | opcode);
1377 // Almost exactly the same as asm_single_data_transfer_opcode.
1378 // Difference: Offsets are smaller and multiples of 4; no shifts, no STREX, ENCODE_IMMEDIATE_FLAG is inverted again.
1379 static void asm_coprocessor_data_transfer_opcode(TCCState *s1, int token)
1381 Operand ops[3];
1382 uint8_t coprocessor;
1383 uint8_t coprocessor_destination_register;
1384 int preincrement = 0;
1385 int exclam = 0;
1386 int closed_bracket = 0;
1387 int op2_minus = 0;
1388 int long_transfer = 0;
1389 // Note: ldc p1, c0, [r4, #4] ; simple offset: r0 = *(int*)(r4+4); r4 unchanged
1390 // Note: ldc p2, c0, [r4, #4]! ; pre-indexed: r0 = *(int*)(r4+4); r4 = r4+4
1391 // Note: ldc p3, c0, [r4], #4 ; post-indexed: r0 = *(int*)(r4+0); r4 = r4+4
1393 if (tok >= TOK_ASM_p0 && tok <= TOK_ASM_p15) {
1394 coprocessor = tok - TOK_ASM_p0;
1395 next();
1396 } else {
1397 expect("'c<number>'");
1398 return;
1401 if (tok == ',')
1402 next();
1403 else
1404 expect("','");
1406 if (tok >= TOK_ASM_c0 && tok <= TOK_ASM_c15) {
1407 coprocessor_destination_register = tok - TOK_ASM_c0;
1408 next();
1409 } else {
1410 expect("'c<number>'");
1411 return;
1414 if (tok == ',')
1415 next();
1416 else
1417 expect("','");
1419 if (tok != '[')
1420 expect("'['");
1421 else
1422 next(); // skip '['
1424 parse_operand(s1, &ops[1]);
1425 if (ops[1].type != OP_REG32) {
1426 expect("(first source operand) register");
1427 return;
1429 if (tok == ']') {
1430 next();
1431 closed_bracket = 1;
1432 // exclam = 1; // implicit in hardware; don't do it in software
1434 if (tok == ',') {
1435 next(); // skip ','
1436 if (tok == '-') {
1437 op2_minus = 1;
1438 next();
1440 parse_operand(s1, &ops[2]);
1441 if (ops[2].type == OP_REG32) {
1442 if (ops[2].reg == 15) {
1443 tcc_error("Using 'pc' for register offset in '%s' is not implemented by ARM", get_tok_str(token, NULL));
1444 return;
1446 } else if (ops[2].type == OP_VREG64) {
1447 tcc_error("'%s' does not support VFP register operand", get_tok_str(token, NULL));
1448 return;
1450 } else {
1451 // end of input expression in brackets--assume 0 offset
1452 ops[2].type = OP_IM8;
1453 ops[2].e.v = 0;
1454 preincrement = 1; // add offset before transfer
1456 if (!closed_bracket) {
1457 if (tok != ']')
1458 expect("']'");
1459 else
1460 next(); // skip ']'
1461 preincrement = 1; // add offset before transfer
1462 if (tok == '!') {
1463 exclam = 1;
1464 next(); // skip '!'
1468 // TODO: Support options.
1470 if (token == TOK_ASM_ldc2 || token == TOK_ASM_stc2 || token == TOK_ASM_ldc2l || token == TOK_ASM_stc2l) {
1471 switch (token) {
1472 case TOK_ASM_ldc2l:
1473 long_transfer = 1; // long transfer
1474 /* fallthrough */
1475 case TOK_ASM_ldc2:
1476 asm_emit_coprocessor_data_transfer(0xF, coprocessor, coprocessor_destination_register, &ops[1], &ops[2], op2_minus, preincrement, exclam, long_transfer, 1);
1477 break;
1478 case TOK_ASM_stc2l:
1479 long_transfer = 1; // long transfer
1480 /* fallthrough */
1481 case TOK_ASM_stc2:
1482 asm_emit_coprocessor_data_transfer(0xF, coprocessor, coprocessor_destination_register, &ops[1], &ops[2], op2_minus, preincrement, exclam, long_transfer, 0);
1483 break;
1485 } else switch (ARM_INSTRUCTION_GROUP(token)) {
1486 case TOK_ASM_stcleq:
1487 long_transfer = 1;
1488 /* fallthrough */
1489 case TOK_ASM_stceq:
1490 asm_emit_coprocessor_data_transfer(condition_code_of_token(token), coprocessor, coprocessor_destination_register, &ops[1], &ops[2], op2_minus, preincrement, exclam, long_transfer, 0);
1491 break;
1492 case TOK_ASM_ldcleq:
1493 long_transfer = 1;
1494 /* fallthrough */
1495 case TOK_ASM_ldceq:
1496 asm_emit_coprocessor_data_transfer(condition_code_of_token(token), coprocessor, coprocessor_destination_register, &ops[1], &ops[2], op2_minus, preincrement, exclam, long_transfer, 1);
1497 break;
1498 default:
1499 expect("coprocessor data transfer instruction");
1503 #if defined(TCC_ARM_VFP)
1504 #define CP_SINGLE_PRECISION_FLOAT 10
1505 #define CP_DOUBLE_PRECISION_FLOAT 11
1507 static void asm_floating_point_single_data_transfer_opcode(TCCState *s1, int token)
1509 Operand ops[3];
1510 uint8_t coprocessor = 0;
1511 uint8_t coprocessor_destination_register = 0;
1512 int long_transfer = 0;
1513 // Note: vldr p1, c0, [r4, #4] ; simple offset: r0 = *(int*)(r4+4); r4 unchanged
1514 // Note: Not allowed: vldr p2, c0, [r4, #4]! ; pre-indexed: r0 = *(int*)(r4+4); r4 = r4+4
1515 // Note: Not allowed: vldr p3, c0, [r4], #4 ; post-indexed: r0 = *(int*)(r4+0); r4 = r4+4
1517 parse_operand(s1, &ops[0]);
1518 if (ops[0].type == OP_VREG32) {
1519 coprocessor = CP_SINGLE_PRECISION_FLOAT;
1520 coprocessor_destination_register = ops[0].reg;
1521 long_transfer = coprocessor_destination_register & 1;
1522 coprocessor_destination_register >>= 1;
1523 } else if (ops[0].type == OP_VREG64) {
1524 coprocessor = CP_DOUBLE_PRECISION_FLOAT;
1525 coprocessor_destination_register = ops[0].reg;
1526 next();
1527 } else {
1528 expect("floating point register");
1529 return;
1532 if (tok == ',')
1533 next();
1534 else
1535 expect("','");
1537 if (tok != '[')
1538 expect("'['");
1539 else
1540 next(); // skip '['
1542 parse_operand(s1, &ops[1]);
1543 if (ops[1].type != OP_REG32) {
1544 expect("(first source operand) register");
1545 return;
1547 if (tok == ',') {
1548 next(); // skip ','
1549 parse_operand(s1, &ops[2]);
1550 if (ops[2].type != OP_IM8 && ops[2].type != OP_IM8N) {
1551 expect("immediate offset");
1552 return;
1554 } else {
1555 // end of input expression in brackets--assume 0 offset
1556 ops[2].type = OP_IM8;
1557 ops[2].e.v = 0;
1559 if (tok != ']')
1560 expect("']'");
1561 else
1562 next(); // skip ']'
1564 switch (ARM_INSTRUCTION_GROUP(token)) {
1565 case TOK_ASM_vldreq:
1566 asm_emit_coprocessor_data_transfer(condition_code_of_token(token), coprocessor, coprocessor_destination_register, &ops[1], &ops[2], 0, 1, 0, long_transfer, 1);
1567 break;
1568 case TOK_ASM_vstreq:
1569 asm_emit_coprocessor_data_transfer(condition_code_of_token(token), coprocessor, coprocessor_destination_register, &ops[1], &ops[2], 0, 1, 0, long_transfer, 0);
1570 break;
1571 default:
1572 expect("floating point data transfer instruction");
1576 static void asm_floating_point_block_data_transfer_opcode(TCCState *s1, int token)
1578 uint8_t coprocessor = 0;
1579 int first_regset_register;
1580 int last_regset_register;
1581 uint8_t regset_item_count;
1582 uint8_t extra_register_bit = 0;
1583 int op0_exclam = 0;
1584 int load = 0;
1585 int preincrement = 0;
1586 Operand ops[1];
1587 Operand offset;
1588 switch (ARM_INSTRUCTION_GROUP(token)) {
1589 case TOK_ASM_vpusheq:
1590 case TOK_ASM_vpopeq:
1591 ops[0].type = OP_REG32;
1592 ops[0].reg = 13; // sp
1593 op0_exclam = 1;
1594 break;
1595 default:
1596 parse_operand(s1, &ops[0]);
1597 if (tok == '!') {
1598 op0_exclam = 1;
1599 next(); // skip '!'
1601 if (tok == ',')
1602 next(); // skip comma
1603 else {
1604 expect("','");
1605 return;
1609 if (tok != '{') {
1610 expect("'{'");
1611 return;
1613 next(); // skip '{'
1614 first_regset_register = asm_parse_vfp_regvar(tok, 1);
1615 if ((first_regset_register = asm_parse_vfp_regvar(tok, 1)) != -1) {
1616 coprocessor = CP_DOUBLE_PRECISION_FLOAT;
1617 next();
1618 } else if ((first_regset_register = asm_parse_vfp_regvar(tok, 0)) != -1) {
1619 coprocessor = CP_SINGLE_PRECISION_FLOAT;
1620 next();
1621 } else {
1622 expect("floating-point register");
1623 return;
1626 if (tok == '-') {
1627 next();
1628 if ((last_regset_register = asm_parse_vfp_regvar(tok, coprocessor == CP_DOUBLE_PRECISION_FLOAT)) != -1)
1629 next();
1630 else {
1631 expect("floating-point register");
1632 return;
1634 } else
1635 last_regset_register = first_regset_register;
1637 if (last_regset_register < first_regset_register) {
1638 tcc_error("registers will be processed in ascending order by hardware--but are not specified in ascending order here");
1639 return;
1641 if (tok != '}') {
1642 expect("'}'");
1643 return;
1645 next(); // skip '}'
1647 // Note: 0 (one down) is not implemented by us regardless.
1648 regset_item_count = last_regset_register - first_regset_register + 1;
1649 if (coprocessor == CP_DOUBLE_PRECISION_FLOAT)
1650 regset_item_count <<= 1;
1651 else {
1652 extra_register_bit = first_regset_register & 1;
1653 first_regset_register >>= 1;
1655 offset.type = OP_IM8;
1656 offset.e.v = regset_item_count << 2;
1657 switch (ARM_INSTRUCTION_GROUP(token)) {
1658 case TOK_ASM_vstmeq: // post-increment store
1659 case TOK_ASM_vstmiaeq: // post-increment store
1660 break;
1661 case TOK_ASM_vpopeq:
1662 case TOK_ASM_vldmeq: // post-increment load
1663 case TOK_ASM_vldmiaeq: // post-increment load
1664 load = 1;
1665 break;
1666 case TOK_ASM_vldmdbeq: // pre-decrement load
1667 load = 1;
1668 /* fallthrough */
1669 case TOK_ASM_vpusheq:
1670 case TOK_ASM_vstmdbeq: // pre-decrement store
1671 offset.type = OP_IM8N;
1672 offset.e.v = -offset.e.v;
1673 preincrement = 1;
1674 break;
1675 default:
1676 expect("floating point block data transfer instruction");
1677 return;
1679 if (ops[0].type != OP_REG32)
1680 expect("(first operand) register");
1681 else if (ops[0].reg == 15)
1682 tcc_error("'%s' does not support 'pc' as operand", get_tok_str(token, NULL));
1683 else if (!op0_exclam && ARM_INSTRUCTION_GROUP(token) != TOK_ASM_vldmeq && ARM_INSTRUCTION_GROUP(token) != TOK_ASM_vldmiaeq && ARM_INSTRUCTION_GROUP(token) != TOK_ASM_vstmeq && ARM_INSTRUCTION_GROUP(token) != TOK_ASM_vstmiaeq)
1684 tcc_error("first operand of '%s' should have an exclamation mark", get_tok_str(token, NULL));
1685 else
1686 asm_emit_coprocessor_data_transfer(condition_code_of_token(token), coprocessor, first_regset_register, &ops[0], &offset, 0, preincrement, op0_exclam, extra_register_bit, load);
1689 #define VMOV_FRACTIONAL_DIGITS 7
1690 #define VMOV_ONE 10000000 /* pow(10, VMOV_FRACTIONAL_DIGITS) */
1692 static uint32_t vmov_parse_fractional_part(const char* s)
1694 uint32_t result = 0;
1695 int i;
1696 for (i = 0; i < VMOV_FRACTIONAL_DIGITS; ++i) {
1697 char c = *s;
1698 result *= 10;
1699 if (c >= '0' && c <= '9') {
1700 result += (c - '0');
1701 ++s;
1704 if (*s)
1705 expect("decimal numeral");
1706 return result;
1709 static int vmov_linear_approx_index(uint32_t beginning, uint32_t end, uint32_t value)
1711 int i;
1712 uint32_t k;
1713 uint32_t xvalue;
1715 k = (end - beginning)/16;
1716 for (xvalue = beginning, i = 0; i < 16; ++i, xvalue += k) {
1717 if (value == xvalue)
1718 return i;
1720 //assert(0);
1721 return -1;
1724 static uint32_t vmov_parse_immediate_value() {
1725 uint32_t value;
1726 unsigned long integral_value;
1727 const char *p;
1729 if (tok != TOK_PPNUM) {
1730 expect("immediate value");
1731 return 0;
1733 p = tokc.str.data;
1734 errno = 0;
1735 integral_value = strtoul(p, (char **)&p, 0);
1737 if (errno || integral_value >= 32) {
1738 tcc_error("invalid floating-point immediate value");
1739 return 0;
1742 value = (uint32_t) integral_value * VMOV_ONE;
1743 if (*p == '.') {
1744 ++p;
1745 value += vmov_parse_fractional_part(p);
1747 next();
1748 return value;
1751 static uint8_t vmov_encode_immediate_value(uint32_t value)
1753 uint32_t limit;
1754 uint32_t end = 0;
1755 uint32_t beginning = 0;
1756 int r = -1;
1757 int n;
1758 int i;
1760 limit = 32 * VMOV_ONE;
1761 for (i = 0; i < 8; ++i) {
1762 if (value < limit) {
1763 end = limit;
1764 limit >>= 1;
1765 beginning = limit;
1766 r = i;
1767 } else
1768 limit >>= 1;
1770 if (r == -1 || value < beginning || value > end) {
1771 tcc_error("invalid decimal number for vmov: %d", value);
1772 return 0;
1774 n = vmov_linear_approx_index(beginning, end, value);
1775 return n | (((3 - r) & 0x7) << 4);
1778 // Not standalone.
1779 static void asm_floating_point_immediate_data_processing_opcode_tail(TCCState *s1, int token, uint8_t coprocessor, uint8_t CRd) {
1780 uint8_t opcode1 = 0;
1781 uint8_t opcode2 = 0;
1782 uint8_t operands[3] = {0, 0, 0};
1783 uint32_t immediate_value = 0;
1784 int op_minus = 0;
1785 uint8_t code;
1787 operands[0] = CRd;
1789 if (tok == '#' || tok == '$') {
1790 next();
1792 if (tok == '-') {
1793 op_minus = 1;
1794 next();
1796 immediate_value = vmov_parse_immediate_value();
1798 opcode1 = 11; // "Other" instruction
1799 switch (ARM_INSTRUCTION_GROUP(token)) {
1800 case TOK_ASM_vcmpeq_f32:
1801 case TOK_ASM_vcmpeq_f64:
1802 opcode2 = 2;
1803 operands[1] = 5;
1804 if (immediate_value) {
1805 expect("Immediate value 0");
1806 return;
1808 break;
1809 case TOK_ASM_vcmpeeq_f32:
1810 case TOK_ASM_vcmpeeq_f64:
1811 opcode2 = 6;
1812 operands[1] = 5;
1813 if (immediate_value) {
1814 expect("Immediate value 0");
1815 return;
1817 break;
1818 case TOK_ASM_vmoveq_f32:
1819 case TOK_ASM_vmoveq_f64:
1820 opcode2 = 0;
1821 if (op_minus)
1822 operands[1] = 0x8;
1823 else
1824 operands[1] = 0x0;
1825 code = vmov_encode_immediate_value(immediate_value);
1826 operands[1] |= code >> 4;
1827 operands[2] = code & 0xF;
1828 break;
1829 default:
1830 expect("known floating point with immediate instruction");
1831 return;
1834 if (coprocessor == CP_SINGLE_PRECISION_FLOAT) {
1835 if (operands[0] & 1)
1836 opcode1 |= 4;
1837 operands[0] >>= 1;
1840 asm_emit_coprocessor_opcode(condition_code_of_token(token), coprocessor, opcode1, operands[0], operands[1], operands[2], opcode2, 0);
1843 static void asm_floating_point_reg_arm_reg_transfer_opcode_tail(TCCState *s1, int token, int coprocessor, int nb_arm_regs, int nb_ops, Operand ops[3]) {
1844 uint8_t opcode1 = 0;
1845 uint8_t opcode2 = 0;
1846 switch (coprocessor) {
1847 case CP_SINGLE_PRECISION_FLOAT:
1848 // "vmov.f32 r2, s3" or "vmov.f32 s3, r2"
1849 if (nb_ops != 2 || nb_arm_regs != 1) {
1850 tcc_error("vmov.f32 only implemented for one VFP register operand and one ARM register operands");
1851 return;
1853 if (ops[0].type != OP_REG32) { // determine mode: load or store
1854 // need to swap operands 0 and 1
1855 memcpy(&ops[2], &ops[1], sizeof(ops[2]));
1856 memcpy(&ops[1], &ops[0], sizeof(ops[1]));
1857 memcpy(&ops[0], &ops[2], sizeof(ops[0]));
1858 } else
1859 opcode1 |= 1;
1861 if (ops[1].type == OP_VREG32) {
1862 if (ops[1].reg & 1)
1863 opcode2 |= 4;
1864 ops[1].reg >>= 1;
1867 if (ops[0].type == OP_VREG32) {
1868 if (ops[0].reg & 1)
1869 opcode1 |= 4;
1870 ops[0].reg >>= 1;
1873 asm_emit_coprocessor_opcode(condition_code_of_token(token), coprocessor, opcode1, ops[0].reg, (ops[1].type == OP_IM8) ? ops[1].e.v : ops[1].reg, 0x10, opcode2, 0);
1874 break;
1875 case CP_DOUBLE_PRECISION_FLOAT:
1876 if (nb_ops != 3 || nb_arm_regs != 2) {
1877 tcc_error("vmov.f32 only implemented for one VFP register operand and two ARM register operands");
1878 return;
1880 // Determine whether it's a store into a VFP register (vmov "d1, r2, r3") rather than "vmov r2, r3, d1"
1881 if (ops[0].type == OP_VREG64) {
1882 if (ops[2].type == OP_REG32) {
1883 Operand temp;
1884 // need to rotate operand list to the left
1885 memcpy(&temp, &ops[0], sizeof(temp));
1886 memcpy(&ops[0], &ops[1], sizeof(ops[0]));
1887 memcpy(&ops[1], &ops[2], sizeof(ops[1]));
1888 memcpy(&ops[2], &temp, sizeof(ops[2]));
1889 } else {
1890 tcc_error("vmov.f64 only implemented for one VFP register operand and two ARM register operands");
1891 return;
1893 } else if (ops[0].type != OP_REG32 || ops[1].type != OP_REG32 || ops[2].type != OP_VREG64) {
1894 tcc_error("vmov.f64 only implemented for one VFP register operand and two ARM register operands");
1895 return;
1896 } else {
1897 opcode1 |= 1;
1899 asm_emit_coprocessor_data_transfer(condition_code_of_token(token), coprocessor, ops[0].reg, &ops[1], &ops[2], 0, 0, 0, 1, opcode1);
1900 break;
1901 default:
1902 tcc_internal_error("unknown coprocessor");
1906 static void asm_floating_point_vcvt_data_processing_opcode(TCCState *s1, int token) {
1907 uint8_t coprocessor = 0;
1908 Operand ops[3];
1909 uint8_t opcode1 = 11;
1910 uint8_t opcode2 = 2;
1912 switch (ARM_INSTRUCTION_GROUP(token)) {
1913 case TOK_ASM_vcvtreq_s32_f64:
1914 case TOK_ASM_vcvtreq_u32_f64:
1915 case TOK_ASM_vcvteq_s32_f64:
1916 case TOK_ASM_vcvteq_u32_f64:
1917 case TOK_ASM_vcvteq_f64_s32:
1918 case TOK_ASM_vcvteq_f64_u32:
1919 case TOK_ASM_vcvteq_f32_f64:
1920 coprocessor = CP_DOUBLE_PRECISION_FLOAT;
1921 break;
1922 case TOK_ASM_vcvtreq_s32_f32:
1923 case TOK_ASM_vcvtreq_u32_f32:
1924 case TOK_ASM_vcvteq_s32_f32:
1925 case TOK_ASM_vcvteq_u32_f32:
1926 case TOK_ASM_vcvteq_f32_s32:
1927 case TOK_ASM_vcvteq_f32_u32:
1928 case TOK_ASM_vcvteq_f64_f32:
1929 coprocessor = CP_SINGLE_PRECISION_FLOAT;
1930 break;
1931 default:
1932 tcc_error("Unknown coprocessor for instruction '%s'", get_tok_str(token, NULL));
1933 return;
1936 parse_operand(s1, &ops[0]);
1937 ops[1].type = OP_IM8;
1938 ops[1].e.v = 8;
1939 /* floating-point -> integer */
1940 switch (ARM_INSTRUCTION_GROUP(token)) {
1941 case TOK_ASM_vcvtreq_s32_f32:
1942 case TOK_ASM_vcvtreq_s32_f64:
1943 case TOK_ASM_vcvteq_s32_f32:
1944 case TOK_ASM_vcvteq_s32_f64:
1945 ops[1].e.v |= 1; // signed
1946 /* fall through */
1947 case TOK_ASM_vcvteq_u32_f32:
1948 case TOK_ASM_vcvteq_u32_f64:
1949 case TOK_ASM_vcvtreq_u32_f32:
1950 case TOK_ASM_vcvtreq_u32_f64:
1951 ops[1].e.v |= 4; // to_integer (opc2)
1952 break;
1953 /* floating-point size conversion */
1954 case TOK_ASM_vcvteq_f64_f32:
1955 case TOK_ASM_vcvteq_f32_f64:
1956 ops[1].e.v = 7;
1957 break;
1960 if (tok == ',')
1961 next();
1962 else
1963 expect("','");
1964 parse_operand(s1, &ops[2]);
1966 switch (ARM_INSTRUCTION_GROUP(token)) {
1967 /* floating-point -> integer */
1968 case TOK_ASM_vcvteq_s32_f32:
1969 case TOK_ASM_vcvteq_s32_f64:
1970 case TOK_ASM_vcvteq_u32_f32:
1971 case TOK_ASM_vcvteq_u32_f64:
1972 opcode2 |= 4; // round_zero
1973 break;
1975 /* integer -> floating-point */
1976 case TOK_ASM_vcvteq_f64_s32:
1977 case TOK_ASM_vcvteq_f32_s32:
1978 opcode2 |= 4; // signed--special
1979 break;
1981 /* floating-point size conversion */
1982 case TOK_ASM_vcvteq_f64_f32:
1983 case TOK_ASM_vcvteq_f32_f64:
1984 opcode2 |= 4; // always set
1985 break;
1988 switch (ARM_INSTRUCTION_GROUP(token)) {
1989 case TOK_ASM_vcvteq_f64_u32:
1990 case TOK_ASM_vcvteq_f64_s32:
1991 case TOK_ASM_vcvteq_f64_f32:
1992 if (ops[0].type == OP_VREG64 && ops[2].type == OP_VREG32) {
1993 } else {
1994 expect("d<number>, s<number>");
1995 return;
1997 break;
1998 default:
1999 if (coprocessor == CP_SINGLE_PRECISION_FLOAT) {
2000 if (ops[0].type == OP_VREG32 && ops[2].type == OP_VREG32) {
2001 } else {
2002 expect("s<number>, s<number>");
2003 return;
2005 } else if (coprocessor == CP_DOUBLE_PRECISION_FLOAT) {
2006 if (ops[0].type == OP_VREG32 && ops[2].type == OP_VREG64) {
2007 } else {
2008 expect("s<number>, d<number>");
2009 return;
2014 if (ops[2].type == OP_VREG32) {
2015 if (ops[2].reg & 1)
2016 opcode2 |= 1;
2017 ops[2].reg >>= 1;
2019 if (ops[0].type == OP_VREG32) {
2020 if (ops[0].reg & 1)
2021 opcode1 |= 4;
2022 ops[0].reg >>= 1;
2024 asm_emit_coprocessor_opcode(condition_code_of_token(token), coprocessor, opcode1, ops[0].reg, (ops[1].type == OP_IM8) ? ops[1].e.v : ops[1].reg, (ops[2].type == OP_IM8) ? ops[2].e.v : ops[2].reg, opcode2, 0);
2027 static void asm_floating_point_data_processing_opcode(TCCState *s1, int token) {
2028 uint8_t coprocessor = CP_SINGLE_PRECISION_FLOAT;
2029 uint8_t opcode1 = 0;
2030 uint8_t opcode2 = 0; // (0 || 2) | register selection
2031 Operand ops[3];
2032 uint8_t nb_ops = 0;
2033 int vmov = 0;
2034 int nb_arm_regs = 0;
2036 /* TODO:
2037 Instruction opcode opcode2 Reason
2038 =============================================================
2039 - 1?00 ?1? Undefined
2040 VFNMS 1?01 ?0? Must be unconditional
2041 VFNMA 1?01 ?1? Must be unconditional
2042 VFMA 1?10 ?0? Must be unconditional
2043 VFMS 1?10 ?1? Must be unconditional
2045 VMOV Fd, Fm
2046 VMOV Sn, Sm, Rd, Rn
2047 VMOV Rd, Rn, Sn, Sm
2048 VMOV Dn[0], Rd
2049 VMOV Rd, Dn[0]
2050 VMOV Dn[1], Rd
2051 VMOV Rd, Dn[1]
2054 switch (ARM_INSTRUCTION_GROUP(token)) {
2055 case TOK_ASM_vmlaeq_f64:
2056 case TOK_ASM_vmlseq_f64:
2057 case TOK_ASM_vnmlseq_f64:
2058 case TOK_ASM_vnmlaeq_f64:
2059 case TOK_ASM_vmuleq_f64:
2060 case TOK_ASM_vnmuleq_f64:
2061 case TOK_ASM_vaddeq_f64:
2062 case TOK_ASM_vsubeq_f64:
2063 case TOK_ASM_vdiveq_f64:
2064 case TOK_ASM_vnegeq_f64:
2065 case TOK_ASM_vabseq_f64:
2066 case TOK_ASM_vsqrteq_f64:
2067 case TOK_ASM_vcmpeq_f64:
2068 case TOK_ASM_vcmpeeq_f64:
2069 case TOK_ASM_vmoveq_f64:
2070 coprocessor = CP_DOUBLE_PRECISION_FLOAT;
2073 switch (ARM_INSTRUCTION_GROUP(token)) {
2074 case TOK_ASM_vmoveq_f32:
2075 case TOK_ASM_vmoveq_f64:
2076 vmov = 1;
2077 break;
2080 for (nb_ops = 0; nb_ops < 3; ) {
2081 // Note: Necessary because parse_operand can't parse decimal numerals.
2082 if (nb_ops == 1 && (tok == '#' || tok == '$' || tok == TOK_PPNUM || tok == '-')) {
2083 asm_floating_point_immediate_data_processing_opcode_tail(s1, token, coprocessor, ops[0].reg);
2084 return;
2086 parse_operand(s1, &ops[nb_ops]);
2087 if (vmov && ops[nb_ops].type == OP_REG32) {
2088 ++nb_arm_regs;
2089 } else if (ops[nb_ops].type == OP_VREG32) {
2090 if (coprocessor != CP_SINGLE_PRECISION_FLOAT) {
2091 expect("'s<number>'");
2092 return;
2094 } else if (ops[nb_ops].type == OP_VREG64) {
2095 if (coprocessor != CP_DOUBLE_PRECISION_FLOAT) {
2096 expect("'d<number>'");
2097 return;
2099 } else {
2100 expect("floating point register");
2101 return;
2103 ++nb_ops;
2104 if (tok == ',')
2105 next();
2106 else
2107 break;
2110 if (nb_arm_regs == 0) {
2111 if (nb_ops == 2) { // implicit
2112 memcpy(&ops[2], &ops[1], sizeof(ops[1])); // move ops[2]
2113 memcpy(&ops[1], &ops[0], sizeof(ops[0])); // ops[1] was implicit
2114 nb_ops = 3;
2116 if (nb_ops < 3) {
2117 tcc_error("Not enough operands for '%s' (%u)", get_tok_str(token, NULL), nb_ops);
2118 return;
2122 switch (ARM_INSTRUCTION_GROUP(token)) {
2123 case TOK_ASM_vmlaeq_f32:
2124 case TOK_ASM_vmlaeq_f64:
2125 opcode1 = 0;
2126 opcode2 = 0;
2127 break;
2128 case TOK_ASM_vmlseq_f32:
2129 case TOK_ASM_vmlseq_f64:
2130 opcode1 = 0;
2131 opcode2 = 2;
2132 break;
2133 case TOK_ASM_vnmlseq_f32:
2134 case TOK_ASM_vnmlseq_f64:
2135 opcode1 = 1;
2136 opcode2 = 0;
2137 break;
2138 case TOK_ASM_vnmlaeq_f32:
2139 case TOK_ASM_vnmlaeq_f64:
2140 opcode1 = 1;
2141 opcode2 = 2;
2142 break;
2143 case TOK_ASM_vmuleq_f32:
2144 case TOK_ASM_vmuleq_f64:
2145 opcode1 = 2;
2146 opcode2 = 0;
2147 break;
2148 case TOK_ASM_vnmuleq_f32:
2149 case TOK_ASM_vnmuleq_f64:
2150 opcode1 = 2;
2151 opcode2 = 2;
2152 break;
2153 case TOK_ASM_vaddeq_f32:
2154 case TOK_ASM_vaddeq_f64:
2155 opcode1 = 3;
2156 opcode2 = 0;
2157 break;
2158 case TOK_ASM_vsubeq_f32:
2159 case TOK_ASM_vsubeq_f64:
2160 opcode1 = 3;
2161 opcode2 = 2;
2162 break;
2163 case TOK_ASM_vdiveq_f32:
2164 case TOK_ASM_vdiveq_f64:
2165 opcode1 = 8;
2166 opcode2 = 0;
2167 break;
2168 case TOK_ASM_vnegeq_f32:
2169 case TOK_ASM_vnegeq_f64:
2170 opcode1 = 11; // Other" instruction
2171 opcode2 = 2;
2172 ops[1].type = OP_IM8;
2173 ops[1].e.v = 1;
2174 break;
2175 case TOK_ASM_vabseq_f32:
2176 case TOK_ASM_vabseq_f64:
2177 opcode1 = 11; // "Other" instruction
2178 opcode2 = 6;
2179 ops[1].type = OP_IM8;
2180 ops[1].e.v = 0;
2181 break;
2182 case TOK_ASM_vsqrteq_f32:
2183 case TOK_ASM_vsqrteq_f64:
2184 opcode1 = 11; // "Other" instruction
2185 opcode2 = 6;
2186 ops[1].type = OP_IM8;
2187 ops[1].e.v = 1;
2188 break;
2189 case TOK_ASM_vcmpeq_f32:
2190 case TOK_ASM_vcmpeq_f64:
2191 opcode1 = 11; // "Other" instruction
2192 opcode2 = 2;
2193 ops[1].type = OP_IM8;
2194 ops[1].e.v = 4;
2195 break;
2196 case TOK_ASM_vcmpeeq_f32:
2197 case TOK_ASM_vcmpeeq_f64:
2198 opcode1 = 11; // "Other" instruction
2199 opcode2 = 6;
2200 ops[1].type = OP_IM8;
2201 ops[1].e.v = 4;
2202 break;
2203 case TOK_ASM_vmoveq_f32:
2204 case TOK_ASM_vmoveq_f64:
2205 if (nb_arm_regs > 0) { // vmov.f32 r2, s3 or similar
2206 asm_floating_point_reg_arm_reg_transfer_opcode_tail(s1, token, coprocessor, nb_arm_regs, nb_ops, ops);
2207 return;
2208 } else {
2209 opcode1 = 11; // "Other" instruction
2210 opcode2 = 2;
2211 ops[1].type = OP_IM8;
2212 ops[1].e.v = 0;
2214 break;
2215 default:
2216 expect("known floating point instruction");
2217 return;
2220 if (coprocessor == CP_SINGLE_PRECISION_FLOAT) {
2221 if (ops[2].type == OP_VREG32) {
2222 if (ops[2].reg & 1)
2223 opcode2 |= 1;
2224 ops[2].reg >>= 1;
2227 if (ops[1].type == OP_VREG32) {
2228 if (ops[1].reg & 1)
2229 opcode2 |= 4;
2230 ops[1].reg >>= 1;
2233 if (ops[0].type == OP_VREG32) {
2234 if (ops[0].reg & 1)
2235 opcode1 |= 4;
2236 ops[0].reg >>= 1;
2240 asm_emit_coprocessor_opcode(condition_code_of_token(token), coprocessor, opcode1, ops[0].reg, (ops[1].type == OP_IM8) ? ops[1].e.v : ops[1].reg, (ops[2].type == OP_IM8) ? ops[2].e.v : ops[2].reg, opcode2, 0);
2243 static void asm_floating_point_status_register_opcode(TCCState* s1, int token)
2245 uint8_t coprocessor = CP_SINGLE_PRECISION_FLOAT;
2246 uint8_t opcode;
2247 int vfp_sys_reg = -1;
2248 Operand arm_operand;
2249 switch (ARM_INSTRUCTION_GROUP(token)) {
2250 case TOK_ASM_vmrseq:
2251 opcode = 0xf;
2252 if (tok == TOK_ASM_apsr_nzcv) {
2253 arm_operand.type = OP_REG32;
2254 arm_operand.reg = 15; // not PC
2255 next(); // skip apsr_nzcv
2256 } else {
2257 parse_operand(s1, &arm_operand);
2258 if (arm_operand.type == OP_REG32 && arm_operand.reg == 15) {
2259 tcc_error("'%s' does not support 'pc' as operand", get_tok_str(token, NULL));
2260 return;
2264 if (tok != ',')
2265 expect("','");
2266 else
2267 next(); // skip ','
2268 vfp_sys_reg = asm_parse_vfp_status_regvar(tok);
2269 next(); // skip vfp sys reg
2270 if (arm_operand.type == OP_REG32 && arm_operand.reg == 15 && vfp_sys_reg != 1) {
2271 tcc_error("'%s' only supports the variant 'vmrs apsr_nzcv, fpscr' here", get_tok_str(token, NULL));
2272 return;
2274 break;
2275 case TOK_ASM_vmsreq:
2276 opcode = 0xe;
2277 vfp_sys_reg = asm_parse_vfp_status_regvar(tok);
2278 next(); // skip vfp sys reg
2279 if (tok != ',')
2280 expect("','");
2281 else
2282 next(); // skip ','
2283 parse_operand(s1, &arm_operand);
2284 if (arm_operand.type == OP_REG32 && arm_operand.reg == 15) {
2285 tcc_error("'%s' does not support 'pc' as operand", get_tok_str(token, NULL));
2286 return;
2288 break;
2289 default:
2290 expect("floating point status register instruction");
2291 return;
2293 if (vfp_sys_reg == -1) {
2294 expect("VFP system register");
2295 return;
2297 if (arm_operand.type != OP_REG32) {
2298 expect("ARM register");
2299 return;
2301 asm_emit_coprocessor_opcode(condition_code_of_token(token), coprocessor, opcode, arm_operand.reg, vfp_sys_reg, 0x10, 0, 0);
2304 #endif
2306 static void asm_misc_single_data_transfer_opcode(TCCState *s1, int token)
2308 Operand ops[3];
2309 int exclam = 0;
2310 int closed_bracket = 0;
2311 int op2_minus = 0;
2312 uint32_t opcode = (1 << 7) | (1 << 4);
2314 /* Note:
2315 The argument syntax is exactly the same as in arm_single_data_transfer_opcode, except that there's no STREX argument form.
2316 The main difference between this function and asm_misc_single_data_transfer_opcode is that the immediate values here must be smaller.
2317 Also, the combination (P=0, W=1) is unpredictable here.
2318 The immediate flag has moved to bit index 22--and its meaning has flipped.
2319 The immediate value itself has been split into two parts: one at bits 11...8, one at bits 3...0
2320 bit 26 (Load/Store instruction) is unset here.
2321 bits 7 and 4 are set here. */
2323 // Here: 0 0 0 P U I W L << 20
2324 // [compare single data transfer: 0 1 I P U B W L << 20]
2326 parse_operand(s1, &ops[0]);
2327 if (ops[0].type == OP_REG32)
2328 opcode |= ENCODE_RD(ops[0].reg);
2329 else {
2330 expect("(destination operand) register");
2331 return;
2333 if (tok != ',')
2334 expect("at least two arguments");
2335 else
2336 next(); // skip ','
2338 if (tok != '[')
2339 expect("'['");
2340 else
2341 next(); // skip '['
2343 parse_operand(s1, &ops[1]);
2344 if (ops[1].type == OP_REG32)
2345 opcode |= ENCODE_RN(ops[1].reg);
2346 else {
2347 expect("(first source operand) register");
2348 return;
2350 if (tok == ']') {
2351 next();
2352 closed_bracket = 1;
2353 // exclam = 1; // implicit in hardware; don't do it in software
2355 if (tok == ',') {
2356 next(); // skip ','
2357 if (tok == '-') {
2358 op2_minus = 1;
2359 next();
2361 parse_operand(s1, &ops[2]);
2362 } else {
2363 // end of input expression in brackets--assume 0 offset
2364 ops[2].type = OP_IM8;
2365 ops[2].e.v = 0;
2366 opcode |= 1 << 24; // add offset before transfer
2368 if (!closed_bracket) {
2369 if (tok != ']')
2370 expect("']'");
2371 else
2372 next(); // skip ']'
2373 opcode |= 1 << 24; // add offset before transfer
2374 if (tok == '!') {
2375 exclam = 1;
2376 next(); // skip '!'
2380 if (exclam) {
2381 if ((opcode & (1 << 24)) == 0) {
2382 tcc_error("result of '%s' would be unpredictable here", get_tok_str(token, NULL));
2383 return;
2385 opcode |= 1 << 21; // write offset back into register
2388 if (ops[2].type == OP_IM32 || ops[2].type == OP_IM8 || ops[2].type == OP_IM8N) {
2389 int v = ops[2].e.v;
2390 if (op2_minus)
2391 tcc_error("minus before '#' not supported for immediate values");
2392 if (v >= 0) {
2393 opcode |= 1 << 23; // up
2394 if (v >= 0x100)
2395 tcc_error("offset out of range for '%s'", get_tok_str(token, NULL));
2396 else {
2397 // bits 11...8: immediate hi nibble
2398 // bits 3...0: immediate lo nibble
2399 opcode |= (v & 0xF0) << 4;
2400 opcode |= v & 0xF;
2402 } else { // down
2403 if (v <= -0x100)
2404 tcc_error("offset out of range for '%s'", get_tok_str(token, NULL));
2405 else {
2406 v = -v;
2407 // bits 11...8: immediate hi nibble
2408 // bits 3...0: immediate lo nibble
2409 opcode |= (v & 0xF0) << 4;
2410 opcode |= v & 0xF;
2413 opcode |= 1 << 22; // not ENCODE_IMMEDIATE_FLAG;
2414 } else if (ops[2].type == OP_REG32) {
2415 if (!op2_minus)
2416 opcode |= 1 << 23; // up
2417 opcode |= ops[2].reg;
2418 } else
2419 expect("register");
2421 switch (ARM_INSTRUCTION_GROUP(token)) {
2422 case TOK_ASM_ldrsheq:
2423 opcode |= 1 << 5; // halfword, not byte
2424 /* fallthrough */
2425 case TOK_ASM_ldrsbeq:
2426 opcode |= 1 << 6; // sign extend
2427 opcode |= 1 << 20; // L
2428 asm_emit_opcode(token, opcode);
2429 break;
2430 case TOK_ASM_ldrheq:
2431 opcode |= 1 << 5; // halfword, not byte
2432 opcode |= 1 << 20; // L
2433 asm_emit_opcode(token, opcode);
2434 break;
2435 case TOK_ASM_strheq:
2436 opcode |= 1 << 5; // halfword, not byte
2437 asm_emit_opcode(token, opcode);
2438 break;
2442 /* Note: almost dupe of encbranch in arm-gen.c */
2443 static uint32_t encbranchoffset(int pos, int addr, int fail)
2445 addr-=pos+8;
2446 addr/=4;
2447 if(addr>=0x7fffff || addr<-0x800000) {
2448 if(fail)
2449 tcc_error("branch offset is too far");
2450 return 0;
2452 return /*not 0x0A000000|*/(addr&0xffffff);
2455 static void asm_branch_opcode(TCCState *s1, int token)
2457 int jmp_disp = 0;
2458 Operand op;
2459 ExprValue e;
2460 ElfSym *esym;
2462 switch (ARM_INSTRUCTION_GROUP(token)) {
2463 case TOK_ASM_beq:
2464 case TOK_ASM_bleq:
2465 asm_expr(s1, &e);
2466 esym = elfsym(e.sym);
2467 if (!esym || esym->st_shndx != cur_text_section->sh_num) {
2468 tcc_error("invalid branch target");
2469 return;
2471 jmp_disp = encbranchoffset(ind, e.v + esym->st_value, 1);
2472 break;
2473 default:
2474 parse_operand(s1, &op);
2475 break;
2477 switch (ARM_INSTRUCTION_GROUP(token)) {
2478 case TOK_ASM_beq:
2479 asm_emit_opcode(token, (0xa << 24) | (jmp_disp & 0xffffff));
2480 break;
2481 case TOK_ASM_bleq:
2482 asm_emit_opcode(token, (0xb << 24) | (jmp_disp & 0xffffff));
2483 break;
2484 case TOK_ASM_bxeq:
2485 if (op.type != OP_REG32)
2486 expect("register");
2487 else
2488 asm_emit_opcode(token, (0x12fff1 << 4) | op.reg);
2489 break;
2490 case TOK_ASM_blxeq:
2491 if (op.type != OP_REG32)
2492 expect("register");
2493 else
2494 asm_emit_opcode(token, (0x12fff3 << 4) | op.reg);
2495 break;
2496 default:
2497 expect("branch instruction");
2501 ST_FUNC void asm_opcode(TCCState *s1, int token)
2503 while (token == TOK_LINEFEED) {
2504 next();
2505 token = tok;
2507 if (token == TOK_EOF)
2508 return;
2509 if (token < TOK_ASM_nopeq) { // no condition code
2510 switch (token) {
2511 case TOK_ASM_cdp2:
2512 asm_coprocessor_opcode(s1, token);
2513 return;
2514 case TOK_ASM_ldc2:
2515 case TOK_ASM_ldc2l:
2516 case TOK_ASM_stc2:
2517 case TOK_ASM_stc2l:
2518 asm_coprocessor_data_transfer_opcode(s1, token);
2519 return;
2520 default:
2521 expect("instruction");
2522 return;
2526 switch (ARM_INSTRUCTION_GROUP(token)) {
2527 case TOK_ASM_pusheq:
2528 case TOK_ASM_popeq:
2529 case TOK_ASM_stmdaeq:
2530 case TOK_ASM_ldmdaeq:
2531 case TOK_ASM_stmeq:
2532 case TOK_ASM_ldmeq:
2533 case TOK_ASM_stmiaeq:
2534 case TOK_ASM_ldmiaeq:
2535 case TOK_ASM_stmdbeq:
2536 case TOK_ASM_ldmdbeq:
2537 case TOK_ASM_stmibeq:
2538 case TOK_ASM_ldmibeq:
2539 asm_block_data_transfer_opcode(s1, token);
2540 return;
2541 case TOK_ASM_nopeq:
2542 case TOK_ASM_wfeeq:
2543 case TOK_ASM_wfieq:
2544 asm_nullary_opcode(token);
2545 return;
2546 case TOK_ASM_swieq:
2547 case TOK_ASM_svceq:
2548 asm_unary_opcode(s1, token);
2549 return;
2550 case TOK_ASM_beq:
2551 case TOK_ASM_bleq:
2552 case TOK_ASM_bxeq:
2553 case TOK_ASM_blxeq:
2554 asm_branch_opcode(s1, token);
2555 return;
2556 case TOK_ASM_clzeq:
2557 case TOK_ASM_sxtbeq:
2558 case TOK_ASM_sxtheq:
2559 case TOK_ASM_uxtbeq:
2560 case TOK_ASM_uxtheq:
2561 case TOK_ASM_movteq:
2562 case TOK_ASM_movweq:
2563 asm_binary_opcode(s1, token);
2564 return;
2566 case TOK_ASM_ldreq:
2567 case TOK_ASM_ldrbeq:
2568 case TOK_ASM_streq:
2569 case TOK_ASM_strbeq:
2570 case TOK_ASM_ldrexeq:
2571 case TOK_ASM_ldrexbeq:
2572 case TOK_ASM_strexeq:
2573 case TOK_ASM_strexbeq:
2574 asm_single_data_transfer_opcode(s1, token);
2575 return;
2577 case TOK_ASM_ldrheq:
2578 case TOK_ASM_ldrsheq:
2579 case TOK_ASM_ldrsbeq:
2580 case TOK_ASM_strheq:
2581 asm_misc_single_data_transfer_opcode(s1, token);
2582 return;
2584 case TOK_ASM_andeq:
2585 case TOK_ASM_eoreq:
2586 case TOK_ASM_subeq:
2587 case TOK_ASM_rsbeq:
2588 case TOK_ASM_addeq:
2589 case TOK_ASM_adceq:
2590 case TOK_ASM_sbceq:
2591 case TOK_ASM_rsceq:
2592 case TOK_ASM_tsteq:
2593 case TOK_ASM_teqeq:
2594 case TOK_ASM_cmpeq:
2595 case TOK_ASM_cmneq:
2596 case TOK_ASM_orreq:
2597 case TOK_ASM_moveq:
2598 case TOK_ASM_biceq:
2599 case TOK_ASM_mvneq:
2600 case TOK_ASM_andseq:
2601 case TOK_ASM_eorseq:
2602 case TOK_ASM_subseq:
2603 case TOK_ASM_rsbseq:
2604 case TOK_ASM_addseq:
2605 case TOK_ASM_adcseq:
2606 case TOK_ASM_sbcseq:
2607 case TOK_ASM_rscseq:
2608 // case TOK_ASM_tstseq:
2609 // case TOK_ASM_teqseq:
2610 // case TOK_ASM_cmpseq:
2611 // case TOK_ASM_cmnseq:
2612 case TOK_ASM_orrseq:
2613 case TOK_ASM_movseq:
2614 case TOK_ASM_bicseq:
2615 case TOK_ASM_mvnseq:
2616 asm_data_processing_opcode(s1, token);
2617 return;
2619 case TOK_ASM_lsleq:
2620 case TOK_ASM_lslseq:
2621 case TOK_ASM_lsreq:
2622 case TOK_ASM_lsrseq:
2623 case TOK_ASM_asreq:
2624 case TOK_ASM_asrseq:
2625 case TOK_ASM_roreq:
2626 case TOK_ASM_rorseq:
2627 case TOK_ASM_rrxseq:
2628 case TOK_ASM_rrxeq:
2629 asm_shift_opcode(s1, token);
2630 return;
2632 case TOK_ASM_muleq:
2633 case TOK_ASM_mulseq:
2634 case TOK_ASM_mlaeq:
2635 case TOK_ASM_mlaseq:
2636 asm_multiplication_opcode(s1, token);
2637 return;
2639 case TOK_ASM_smulleq:
2640 case TOK_ASM_smullseq:
2641 case TOK_ASM_umulleq:
2642 case TOK_ASM_umullseq:
2643 case TOK_ASM_smlaleq:
2644 case TOK_ASM_smlalseq:
2645 case TOK_ASM_umlaleq:
2646 case TOK_ASM_umlalseq:
2647 asm_long_multiplication_opcode(s1, token);
2648 return;
2650 case TOK_ASM_cdpeq:
2651 case TOK_ASM_mcreq:
2652 case TOK_ASM_mrceq:
2653 asm_coprocessor_opcode(s1, token);
2654 return;
2656 case TOK_ASM_ldceq:
2657 case TOK_ASM_ldcleq:
2658 case TOK_ASM_stceq:
2659 case TOK_ASM_stcleq:
2660 asm_coprocessor_data_transfer_opcode(s1, token);
2661 return;
2663 #if defined(TCC_ARM_VFP)
2664 case TOK_ASM_vldreq:
2665 case TOK_ASM_vstreq:
2666 asm_floating_point_single_data_transfer_opcode(s1, token);
2667 return;
2669 case TOK_ASM_vmlaeq_f32:
2670 case TOK_ASM_vmlseq_f32:
2671 case TOK_ASM_vnmlseq_f32:
2672 case TOK_ASM_vnmlaeq_f32:
2673 case TOK_ASM_vmuleq_f32:
2674 case TOK_ASM_vnmuleq_f32:
2675 case TOK_ASM_vaddeq_f32:
2676 case TOK_ASM_vsubeq_f32:
2677 case TOK_ASM_vdiveq_f32:
2678 case TOK_ASM_vnegeq_f32:
2679 case TOK_ASM_vabseq_f32:
2680 case TOK_ASM_vsqrteq_f32:
2681 case TOK_ASM_vcmpeq_f32:
2682 case TOK_ASM_vcmpeeq_f32:
2683 case TOK_ASM_vmoveq_f32:
2684 case TOK_ASM_vmlaeq_f64:
2685 case TOK_ASM_vmlseq_f64:
2686 case TOK_ASM_vnmlseq_f64:
2687 case TOK_ASM_vnmlaeq_f64:
2688 case TOK_ASM_vmuleq_f64:
2689 case TOK_ASM_vnmuleq_f64:
2690 case TOK_ASM_vaddeq_f64:
2691 case TOK_ASM_vsubeq_f64:
2692 case TOK_ASM_vdiveq_f64:
2693 case TOK_ASM_vnegeq_f64:
2694 case TOK_ASM_vabseq_f64:
2695 case TOK_ASM_vsqrteq_f64:
2696 case TOK_ASM_vcmpeq_f64:
2697 case TOK_ASM_vcmpeeq_f64:
2698 case TOK_ASM_vmoveq_f64:
2699 asm_floating_point_data_processing_opcode(s1, token);
2700 return;
2702 case TOK_ASM_vcvtreq_s32_f32:
2703 case TOK_ASM_vcvtreq_s32_f64:
2704 case TOK_ASM_vcvteq_s32_f32:
2705 case TOK_ASM_vcvteq_s32_f64:
2706 case TOK_ASM_vcvtreq_u32_f32:
2707 case TOK_ASM_vcvtreq_u32_f64:
2708 case TOK_ASM_vcvteq_u32_f32:
2709 case TOK_ASM_vcvteq_u32_f64:
2710 case TOK_ASM_vcvteq_f64_s32:
2711 case TOK_ASM_vcvteq_f32_s32:
2712 case TOK_ASM_vcvteq_f64_u32:
2713 case TOK_ASM_vcvteq_f32_u32:
2714 case TOK_ASM_vcvteq_f64_f32:
2715 case TOK_ASM_vcvteq_f32_f64:
2716 asm_floating_point_vcvt_data_processing_opcode(s1, token);
2717 return;
2719 case TOK_ASM_vpusheq:
2720 case TOK_ASM_vpopeq:
2721 case TOK_ASM_vldmeq:
2722 case TOK_ASM_vldmiaeq:
2723 case TOK_ASM_vldmdbeq:
2724 case TOK_ASM_vstmeq:
2725 case TOK_ASM_vstmiaeq:
2726 case TOK_ASM_vstmdbeq:
2727 asm_floating_point_block_data_transfer_opcode(s1, token);
2728 return;
2730 case TOK_ASM_vmsreq:
2731 case TOK_ASM_vmrseq:
2732 asm_floating_point_status_register_opcode(s1, token);
2733 return;
2734 #endif
2736 default:
2737 expect("known instruction");
2741 ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier)
2743 int r, reg, size, val;
2744 char buf[64];
2746 r = sv->r;
2747 if ((r & VT_VALMASK) == VT_CONST) {
2748 if (!(r & VT_LVAL) && modifier != 'c' && modifier != 'n' &&
2749 modifier != 'P')
2750 cstr_ccat(add_str, '#');
2751 if (r & VT_SYM) {
2752 const char *name = get_tok_str(sv->sym->v, NULL);
2753 if (sv->sym->v >= SYM_FIRST_ANOM) {
2754 /* In case of anonymous symbols ("L.42", used
2755 for static data labels) we can't find them
2756 in the C symbol table when later looking up
2757 this name. So enter them now into the asm label
2758 list when we still know the symbol. */
2759 get_asm_sym(tok_alloc(name, strlen(name))->tok, sv->sym);
2761 if (tcc_state->leading_underscore)
2762 cstr_ccat(add_str, '_');
2763 cstr_cat(add_str, name, -1);
2764 if ((uint32_t) sv->c.i == 0)
2765 goto no_offset;
2766 cstr_ccat(add_str, '+');
2768 val = sv->c.i;
2769 if (modifier == 'n')
2770 val = -val;
2771 snprintf(buf, sizeof(buf), "%d", (int) sv->c.i);
2772 cstr_cat(add_str, buf, -1);
2773 no_offset:;
2774 } else if ((r & VT_VALMASK) == VT_LOCAL) {
2775 snprintf(buf, sizeof(buf), "[fp,#%d]", (int) sv->c.i);
2776 cstr_cat(add_str, buf, -1);
2777 } else if (r & VT_LVAL) {
2778 reg = r & VT_VALMASK;
2779 if (reg >= VT_CONST)
2780 tcc_internal_error("");
2781 snprintf(buf, sizeof(buf), "[%s]",
2782 get_tok_str(TOK_ASM_r0 + reg, NULL));
2783 cstr_cat(add_str, buf, -1);
2784 } else {
2785 /* register case */
2786 reg = r & VT_VALMASK;
2787 if (reg >= VT_CONST)
2788 tcc_internal_error("");
2790 /* choose register operand size */
2791 if ((sv->type.t & VT_BTYPE) == VT_BYTE ||
2792 (sv->type.t & VT_BTYPE) == VT_BOOL)
2793 size = 1;
2794 else if ((sv->type.t & VT_BTYPE) == VT_SHORT)
2795 size = 2;
2796 else
2797 size = 4;
2799 if (modifier == 'b') {
2800 size = 1;
2801 } else if (modifier == 'w') {
2802 size = 2;
2803 } else if (modifier == 'k') {
2804 size = 4;
2807 switch (size) {
2808 default:
2809 reg = TOK_ASM_r0 + reg;
2810 break;
2812 snprintf(buf, sizeof(buf), "%s", get_tok_str(reg, NULL));
2813 cstr_cat(add_str, buf, -1);
2817 /* generate prolog and epilog code for asm statement */
2818 ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands,
2819 int nb_outputs, int is_output,
2820 uint8_t *clobber_regs,
2821 int out_reg)
2823 uint8_t regs_allocated[NB_ASM_REGS];
2824 ASMOperand *op;
2825 int i, reg;
2826 uint32_t saved_regset = 0;
2828 // TODO: Check non-E ABI.
2829 // Note: Technically, r13 (sp) is also callee-saved--but that does not matter yet
2830 static const uint8_t reg_saved[] = { 4, 5, 6, 7, 8, 9 /* Note: sometimes special reg "sb" */ , 10, 11 };
2832 /* mark all used registers */
2833 memcpy(regs_allocated, clobber_regs, sizeof(regs_allocated));
2834 for(i = 0; i < nb_operands;i++) {
2835 op = &operands[i];
2836 if (op->reg >= 0)
2837 regs_allocated[op->reg] = 1;
2839 for(i = 0; i < sizeof(reg_saved)/sizeof(reg_saved[0]); i++) {
2840 reg = reg_saved[i];
2841 if (regs_allocated[reg])
2842 saved_regset |= 1 << reg;
2845 if (!is_output) { // prolog
2846 /* generate reg save code */
2847 if (saved_regset)
2848 gen_le32(0xe92d0000 | saved_regset); // push {...}
2850 /* generate load code */
2851 for(i = 0; i < nb_operands; i++) {
2852 op = &operands[i];
2853 if (op->reg >= 0) {
2854 if ((op->vt->r & VT_VALMASK) == VT_LLOCAL &&
2855 op->is_memory) {
2856 /* memory reference case (for both input and
2857 output cases) */
2858 SValue sv;
2859 sv = *op->vt;
2860 sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL | VT_LVAL;
2861 sv.type.t = VT_PTR;
2862 load(op->reg, &sv);
2863 } else if (i >= nb_outputs || op->is_rw) { // not write-only
2864 /* load value in register */
2865 load(op->reg, op->vt);
2866 if (op->is_llong)
2867 tcc_error("long long not implemented");
2871 } else { // epilog
2872 /* generate save code */
2873 for(i = 0 ; i < nb_outputs; i++) {
2874 op = &operands[i];
2875 if (op->reg >= 0) {
2876 if ((op->vt->r & VT_VALMASK) == VT_LLOCAL) {
2877 if (!op->is_memory) {
2878 SValue sv;
2879 sv = *op->vt;
2880 sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL;
2881 sv.type.t = VT_PTR;
2882 load(out_reg, &sv);
2884 sv = *op->vt;
2885 sv.r = (sv.r & ~VT_VALMASK) | out_reg;
2886 store(op->reg, &sv);
2888 } else {
2889 store(op->reg, op->vt);
2890 if (op->is_llong)
2891 tcc_error("long long not implemented");
2896 /* generate reg restore code */
2897 if (saved_regset)
2898 gen_le32(0xe8bd0000 | saved_regset); // pop {...}
2902 /* return the constraint priority (we allocate first the lowest
2903 numbered constraints) */
2904 static inline int constraint_priority(const char *str)
2906 int priority, c, pr;
2908 /* we take the lowest priority */
2909 priority = 0;
2910 for(;;) {
2911 c = *str;
2912 if (c == '\0')
2913 break;
2914 str++;
2915 switch(c) {
2916 case 'l': // in ARM mode, that's an alias for 'r' [ARM].
2917 case 'r': // register [general]
2918 case 'p': // valid memory address for load,store [general]
2919 pr = 3;
2920 break;
2921 case 'M': // integer constant for shifts [ARM]
2922 case 'I': // integer valid for data processing instruction immediate
2923 case 'J': // integer in range -4095...4095
2925 case 'i': // immediate integer operand, including symbolic constants [general]
2926 case 'm': // memory operand [general]
2927 case 'g': // general-purpose-register, memory, immediate integer [general]
2928 pr = 4;
2929 break;
2930 default:
2931 tcc_error("unknown constraint '%c'", c);
2932 pr = 0;
2934 if (pr > priority)
2935 priority = pr;
2937 return priority;
2940 static const char *skip_constraint_modifiers(const char *p)
2942 /* Constraint modifier:
2943 = Operand is written to by this instruction
2944 + Operand is both read and written to by this instruction
2945 % Instruction is commutative for this operand and the following operand.
2947 Per-alternative constraint modifier:
2948 & Operand is clobbered before the instruction is done using the input operands
2950 while (*p == '=' || *p == '&' || *p == '+' || *p == '%')
2951 p++;
2952 return p;
2955 #define REG_OUT_MASK 0x01
2956 #define REG_IN_MASK 0x02
2958 #define is_reg_allocated(reg) (regs_allocated[reg] & reg_mask)
2960 ST_FUNC void asm_compute_constraints(ASMOperand *operands,
2961 int nb_operands, int nb_outputs,
2962 const uint8_t *clobber_regs,
2963 int *pout_reg)
2965 /* overall format: modifier, then ,-seperated list of alternatives; all operands for a single instruction must have the same number of alternatives */
2966 /* TODO: Simple constraints
2967 whitespace ignored
2968 o memory operand that is offsetable
2969 V memory but not offsetable
2970 < memory operand with autodecrement addressing is allowed. Restrictions apply.
2971 > memory operand with autoincrement addressing is allowed. Restrictions apply.
2972 n immediate integer operand with a known numeric value
2973 E immediate floating operand (const_double) is allowed, but only if target=host
2974 F immediate floating operand (const_double or const_vector) is allowed
2975 s immediate integer operand whose value is not an explicit integer
2976 X any operand whatsoever
2977 0...9 (postfix); (can also be more than 1 digit number); an operand that matches the specified operand number is allowed
2980 /* TODO: ARM constraints:
2981 k the stack pointer register
2982 G the floating-point constant 0.0
2983 Q memory reference where the exact address is in a single register ("m" is preferable for asm statements)
2984 R an item in the constant pool
2985 S symbol in the text segment of the current file
2986 [ Uv memory reference suitable for VFP load/store insns (reg+constant offset)]
2987 [ Uy memory reference suitable for iWMMXt load/store instructions]
2988 Uq memory reference suitable for the ARMv4 ldrsb instruction
2990 ASMOperand *op;
2991 int sorted_op[MAX_ASM_OPERANDS];
2992 int i, j, k, p1, p2, tmp, reg, c, reg_mask;
2993 const char *str;
2994 uint8_t regs_allocated[NB_ASM_REGS];
2996 /* init fields */
2997 for (i = 0; i < nb_operands; i++) {
2998 op = &operands[i];
2999 op->input_index = -1;
3000 op->ref_index = -1;
3001 op->reg = -1;
3002 op->is_memory = 0;
3003 op->is_rw = 0;
3005 /* compute constraint priority and evaluate references to output
3006 constraints if input constraints */
3007 for (i = 0; i < nb_operands; i++) {
3008 op = &operands[i];
3009 str = op->constraint;
3010 str = skip_constraint_modifiers(str);
3011 if (isnum(*str) || *str == '[') {
3012 /* this is a reference to another constraint */
3013 k = find_constraint(operands, nb_operands, str, NULL);
3014 if ((unsigned) k >= i || i < nb_outputs)
3015 tcc_error("invalid reference in constraint %d ('%s')",
3016 i, str);
3017 op->ref_index = k;
3018 if (operands[k].input_index >= 0)
3019 tcc_error("cannot reference twice the same operand");
3020 operands[k].input_index = i;
3021 op->priority = 5;
3022 } else if ((op->vt->r & VT_VALMASK) == VT_LOCAL
3023 && op->vt->sym
3024 && (reg = op->vt->sym->r & VT_VALMASK) < VT_CONST) {
3025 op->priority = 1;
3026 op->reg = reg;
3027 } else {
3028 op->priority = constraint_priority(str);
3032 /* sort operands according to their priority */
3033 for (i = 0; i < nb_operands; i++)
3034 sorted_op[i] = i;
3035 for (i = 0; i < nb_operands - 1; i++) {
3036 for (j = i + 1; j < nb_operands; j++) {
3037 p1 = operands[sorted_op[i]].priority;
3038 p2 = operands[sorted_op[j]].priority;
3039 if (p2 < p1) {
3040 tmp = sorted_op[i];
3041 sorted_op[i] = sorted_op[j];
3042 sorted_op[j] = tmp;
3047 for (i = 0; i < NB_ASM_REGS; i++) {
3048 if (clobber_regs[i])
3049 regs_allocated[i] = REG_IN_MASK | REG_OUT_MASK;
3050 else
3051 regs_allocated[i] = 0;
3053 /* sp cannot be used */
3054 regs_allocated[13] = REG_IN_MASK | REG_OUT_MASK;
3055 /* fp cannot be used yet */
3056 regs_allocated[11] = REG_IN_MASK | REG_OUT_MASK;
3058 /* allocate registers and generate corresponding asm moves */
3059 for (i = 0; i < nb_operands; i++) {
3060 j = sorted_op[i];
3061 op = &operands[j];
3062 str = op->constraint;
3063 /* no need to allocate references */
3064 if (op->ref_index >= 0)
3065 continue;
3066 /* select if register is used for output, input or both */
3067 if (op->input_index >= 0) {
3068 reg_mask = REG_IN_MASK | REG_OUT_MASK;
3069 } else if (j < nb_outputs) {
3070 reg_mask = REG_OUT_MASK;
3071 } else {
3072 reg_mask = REG_IN_MASK;
3074 if (op->reg >= 0) {
3075 if (is_reg_allocated(op->reg))
3076 tcc_error
3077 ("asm regvar requests register that's taken already");
3078 reg = op->reg;
3079 goto reg_found;
3081 try_next:
3082 c = *str++;
3083 switch (c) {
3084 case '=': // Operand is written-to
3085 goto try_next;
3086 case '+': // Operand is both READ and written-to
3087 op->is_rw = 1;
3088 /* FALL THRU */
3089 case '&': // Operand is clobbered before the instruction is done using the input operands
3090 if (j >= nb_outputs)
3091 tcc_error("'%c' modifier can only be applied to outputs",
3093 reg_mask = REG_IN_MASK | REG_OUT_MASK;
3094 goto try_next;
3095 case 'l': // In non-thumb mode, alias for 'r'--otherwise r0-r7 [ARM]
3096 case 'r': // general-purpose register
3097 case 'p': // loadable/storable address
3098 /* any general register */
3099 for (reg = 0; reg <= 8; reg++) {
3100 if (!is_reg_allocated(reg))
3101 goto reg_found;
3103 goto try_next;
3104 reg_found:
3105 /* now we can reload in the register */
3106 op->is_llong = 0;
3107 op->reg = reg;
3108 regs_allocated[reg] |= reg_mask;
3109 break;
3110 case 'I': // integer that is valid as an data processing instruction immediate (0...255, rotated by a multiple of two)
3111 case 'J': // integer in the range -4095 to 4095 [ARM]
3112 case 'K': // integer that satisfies constraint I when inverted (one's complement)
3113 case 'L': // integer that satisfies constraint I when inverted (two's complement)
3114 case 'i': // immediate integer operand, including symbolic constants
3115 if (!((op->vt->r & (VT_VALMASK | VT_LVAL)) == VT_CONST))
3116 goto try_next;
3117 break;
3118 case 'M': // integer in the range 0 to 32
3119 if (!
3120 ((op->vt->r & (VT_VALMASK | VT_LVAL | VT_SYM)) ==
3121 VT_CONST))
3122 goto try_next;
3123 break;
3124 case 'm': // memory operand
3125 case 'g':
3126 /* nothing special to do because the operand is already in
3127 memory, except if the pointer itself is stored in a
3128 memory variable (VT_LLOCAL case) */
3129 /* XXX: fix constant case */
3130 /* if it is a reference to a memory zone, it must lie
3131 in a register, so we reserve the register in the
3132 input registers and a load will be generated
3133 later */
3134 if (j < nb_outputs || c == 'm') {
3135 if ((op->vt->r & VT_VALMASK) == VT_LLOCAL) {
3136 /* any general register */
3137 for (reg = 0; reg <= 8; reg++) {
3138 if (!(regs_allocated[reg] & REG_IN_MASK))
3139 goto reg_found1;
3141 goto try_next;
3142 reg_found1:
3143 /* now we can reload in the register */
3144 regs_allocated[reg] |= REG_IN_MASK;
3145 op->reg = reg;
3146 op->is_memory = 1;
3149 break;
3150 default:
3151 tcc_error("asm constraint %d ('%s') could not be satisfied",
3152 j, op->constraint);
3153 break;
3155 /* if a reference is present for that operand, we assign it too */
3156 if (op->input_index >= 0) {
3157 operands[op->input_index].reg = op->reg;
3158 operands[op->input_index].is_llong = op->is_llong;
3162 /* compute out_reg. It is used to store outputs registers to memory
3163 locations references by pointers (VT_LLOCAL case) */
3164 *pout_reg = -1;
3165 for (i = 0; i < nb_operands; i++) {
3166 op = &operands[i];
3167 if (op->reg >= 0 &&
3168 (op->vt->r & VT_VALMASK) == VT_LLOCAL && !op->is_memory) {
3169 for (reg = 0; reg <= 8; reg++) {
3170 if (!(regs_allocated[reg] & REG_OUT_MASK))
3171 goto reg_found2;
3173 tcc_error("could not find free output register for reloading");
3174 reg_found2:
3175 *pout_reg = reg;
3176 break;
3180 /* print sorted constraints */
3181 #ifdef ASM_DEBUG
3182 for (i = 0; i < nb_operands; i++) {
3183 j = sorted_op[i];
3184 op = &operands[j];
3185 printf("%%%d [%s]: \"%s\" r=0x%04x reg=%d\n",
3187 op->id ? get_tok_str(op->id, NULL) : "",
3188 op->constraint, op->vt->r, op->reg);
3190 if (*pout_reg >= 0)
3191 printf("out_reg=%d\n", *pout_reg);
3192 #endif
3195 ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str)
3197 int reg;
3198 TokenSym *ts;
3200 if (!strcmp(str, "memory") ||
3201 !strcmp(str, "cc") ||
3202 !strcmp(str, "flags"))
3203 return;
3204 ts = tok_alloc(str, strlen(str));
3205 reg = asm_parse_regvar(ts->tok);
3206 if (reg == -1) {
3207 tcc_error("invalid clobber register '%s'", str);
3209 clobber_regs[reg] = 1;
3212 /* If T refers to a register then return the register number and type.
3213 Otherwise return -1. */
3214 ST_FUNC int asm_parse_regvar (int t)
3216 if (t >= TOK_ASM_r0 && t <= TOK_ASM_pc) { /* register name */
3217 switch (t) {
3218 case TOK_ASM_fp:
3219 return TOK_ASM_r11 - TOK_ASM_r0;
3220 case TOK_ASM_ip:
3221 return TOK_ASM_r12 - TOK_ASM_r0;
3222 case TOK_ASM_sp:
3223 return TOK_ASM_r13 - TOK_ASM_r0;
3224 case TOK_ASM_lr:
3225 return TOK_ASM_r14 - TOK_ASM_r0;
3226 case TOK_ASM_pc:
3227 return TOK_ASM_r15 - TOK_ASM_r0;
3228 default:
3229 return t - TOK_ASM_r0;
3231 } else
3232 return -1;
3235 /*************************************************************/
3236 #endif /* ndef TARGET_DEFS_ONLY */