Fix arm NetBSD cross compilation
[tinycc.git] / arm-asm.c
blobedfbab3d8d5a066f53ee2d9270eba69df313c952
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,
45 #define OP_REG32 (1 << OPT_REG32)
46 #define OP_REG (OP_REG32)
47 #define OP_IM32 (1 << OPT_IM32)
48 #define OP_IM8 (1 << OPT_IM8)
49 #define OP_IM8N (1 << OPT_IM8N)
50 #define OP_REGSET32 (1 << OPT_REGSET32)
52 typedef struct Operand {
53 uint32_t type;
54 union {
55 uint8_t reg;
56 uint16_t regset;
57 ExprValue e;
59 } Operand;
61 /* Parse a text containing operand and store the result in OP */
62 static void parse_operand(TCCState *s1, Operand *op)
64 ExprValue e;
65 int8_t reg;
66 uint16_t regset = 0;
68 op->type = 0;
70 if (tok == '{') { // regset literal
71 next(); // skip '{'
72 while (tok != '}' && tok != TOK_EOF) {
73 reg = asm_parse_regvar(tok);
74 if (reg == -1) {
75 expect("register");
76 return;
77 } else
78 next(); // skip register name
80 if ((1 << reg) < regset)
81 tcc_warning("registers will be processed in ascending order by hardware--but are not specified in ascending order here");
82 regset |= 1 << reg;
83 if (tok != ',')
84 break;
85 next(); // skip ','
87 if (tok != '}')
88 expect("'}'");
89 next(); // skip '}'
90 if (regset == 0) {
91 // ARM instructions don't support empty regset.
92 tcc_error("empty register list is not supported");
93 } else {
94 op->type = OP_REGSET32;
95 op->regset = regset;
97 } else if (tok == '#' || tok == '$') {
98 /* constant value */
99 next(); // skip '#' or '$'
100 asm_expr(s1, &e);
101 op->type = OP_IM32;
102 op->e = e;
103 if (!op->e.sym) {
104 if ((int) op->e.v < 0 && (int) op->e.v >= -255)
105 op->type = OP_IM8N;
106 else if (op->e.v == (uint8_t)op->e.v)
107 op->type = OP_IM8;
108 } else
109 expect("constant");
110 } else if ((reg = asm_parse_regvar(tok)) != -1) {
111 next(); // skip register name
112 op->type = OP_REG32;
113 op->reg = (uint8_t) reg;
114 } else
115 expect("operand");
118 /* XXX: make it faster ? */
119 ST_FUNC void g(int c)
121 int ind1;
122 if (nocode_wanted)
123 return;
124 ind1 = ind + 1;
125 if (ind1 > cur_text_section->data_allocated)
126 section_realloc(cur_text_section, ind1);
127 cur_text_section->data[ind] = c;
128 ind = ind1;
131 ST_FUNC void gen_le16 (int i)
133 g(i);
134 g(i>>8);
137 ST_FUNC void gen_le32 (int i)
139 int ind1;
140 if (nocode_wanted)
141 return;
142 ind1 = ind + 4;
143 if (ind1 > cur_text_section->data_allocated)
144 section_realloc(cur_text_section, ind1);
145 cur_text_section->data[ind++] = i & 0xFF;
146 cur_text_section->data[ind++] = (i >> 8) & 0xFF;
147 cur_text_section->data[ind++] = (i >> 16) & 0xFF;
148 cur_text_section->data[ind++] = (i >> 24) & 0xFF;
151 ST_FUNC void gen_expr32(ExprValue *pe)
153 gen_le32(pe->v);
156 static uint32_t condition_code_of_token(int token) {
157 if (token < TOK_ASM_nopeq) {
158 expect("instruction");
159 return 0;
160 } else
161 return (token - TOK_ASM_nopeq) & 15;
164 static void asm_emit_opcode(int token, uint32_t opcode) {
165 gen_le32((condition_code_of_token(token) << 28) | opcode);
168 static void asm_nullary_opcode(int token)
170 switch (ARM_INSTRUCTION_GROUP(token)) {
171 case TOK_ASM_nopeq:
172 asm_emit_opcode(token, 0xd << 21); // mov r0, r0
173 break;
174 case TOK_ASM_wfeeq:
175 asm_emit_opcode(token, 0x320f002);
176 case TOK_ASM_wfieq:
177 asm_emit_opcode(token, 0x320f003);
178 break;
179 default:
180 expect("nullary instruction");
184 static void asm_unary_opcode(TCCState *s1, int token)
186 Operand op;
187 parse_operand(s1, &op);
189 switch (ARM_INSTRUCTION_GROUP(token)) {
190 case TOK_ASM_swieq:
191 if (op.type != OP_IM8)
192 expect("immediate 8-bit unsigned integer");
193 else {
194 /* Note: Dummy operand (ignored by processor): ARM ref documented 0...255, ARM instruction set documented 24 bit */
195 asm_emit_opcode(token, (0xf << 24) | op.e.v);
197 break;
198 default:
199 expect("unary instruction");
203 static void asm_binary_opcode(TCCState *s1, int token)
205 Operand ops[2];
206 Operand rotation;
207 uint32_t encoded_rotation = 0;
208 uint64_t amount;
209 parse_operand(s1, &ops[0]);
210 if (tok == ',')
211 next();
212 else
213 expect("','");
214 parse_operand(s1, &ops[1]);
215 if (ops[0].type != OP_REG32) {
216 expect("(destination operand) register");
217 return;
220 if (ops[0].reg == 15) {
221 tcc_error("'%s' does not support 'pc' as operand", get_tok_str(token, NULL));
222 return;
225 if (ops[0].reg == 13)
226 tcc_warning("Using 'sp' as operand with '%s' is deprecated by ARM", get_tok_str(token, NULL));
228 if (ops[1].type != OP_REG32) {
229 switch (ARM_INSTRUCTION_GROUP(token)) {
230 case TOK_ASM_movteq:
231 case TOK_ASM_movweq:
232 if (ops[1].type == OP_IM8 || ops[1].type == OP_IM8N || ops[1].type == OP_IM32) {
233 if (ops[1].e.v >= 0 && ops[1].e.v <= 0xFFFF) {
234 uint16_t immediate_value = ops[1].e.v;
235 switch (ARM_INSTRUCTION_GROUP(token)) {
236 case TOK_ASM_movteq:
237 asm_emit_opcode(token, 0x3400000 | (ops[0].reg << 12) | (immediate_value & 0xF000) << 4 | (immediate_value & 0xFFF));
238 break;
239 case TOK_ASM_movweq:
240 asm_emit_opcode(token, 0x3000000 | (ops[0].reg << 12) | (immediate_value & 0xF000) << 4 | (immediate_value & 0xFFF));
241 break;
243 } else
244 expect("(source operand) immediate 16 bit value");
245 } else
246 expect("(source operand) immediate");
247 break;
248 default:
249 expect("(source operand) register");
251 return;
254 if (ops[1].reg == 15) {
255 tcc_error("'%s' does not support 'pc' as operand", get_tok_str(token, NULL));
256 return;
259 if (ops[1].reg == 13)
260 tcc_warning("Using 'sp' as operand with '%s' is deprecated by ARM", get_tok_str(token, NULL));
262 if (tok == ',') {
263 next(); // skip ','
264 if (tok == TOK_ASM_ror) {
265 next(); // skip 'ror'
266 parse_operand(s1, &rotation);
267 if (rotation.type != OP_IM8) {
268 expect("immediate value for rotation");
269 return;
270 } else {
271 amount = rotation.e.v;
272 switch (amount) {
273 case 8:
274 encoded_rotation = 1 << 10;
275 break;
276 case 16:
277 encoded_rotation = 2 << 10;
278 break;
279 case 24:
280 encoded_rotation = 3 << 10;
281 break;
282 default:
283 expect("'8' or '16' or '24'");
284 return;
289 switch (ARM_INSTRUCTION_GROUP(token)) {
290 case TOK_ASM_clzeq:
291 if (encoded_rotation)
292 tcc_error("clz does not support rotation");
293 asm_emit_opcode(token, 0x16f0f10 | (ops[0].reg << 12) | ops[1].reg);
294 break;
295 case TOK_ASM_sxtbeq:
296 asm_emit_opcode(token, 0x6af0070 | (ops[0].reg << 12) | ops[1].reg | encoded_rotation);
297 break;
298 case TOK_ASM_sxtheq:
299 asm_emit_opcode(token, 0x6bf0070 | (ops[0].reg << 12) | ops[1].reg | encoded_rotation);
300 break;
301 case TOK_ASM_uxtbeq:
302 asm_emit_opcode(token, 0x6ef0070 | (ops[0].reg << 12) | ops[1].reg | encoded_rotation);
303 break;
304 case TOK_ASM_uxtheq:
305 asm_emit_opcode(token, 0x6ff0070 | (ops[0].reg << 12) | ops[1].reg | encoded_rotation);
306 break;
307 default:
308 expect("binary instruction");
312 /* data processing and single data transfer instructions only */
313 #define ENCODE_RN(register_index) ((register_index) << 16)
314 #define ENCODE_RD(register_index) ((register_index) << 12)
315 #define ENCODE_SET_CONDITION_CODES (1 << 20)
317 /* Note: For data processing instructions, "1" means immediate.
318 Note: For single data transfer instructions, "0" means immediate. */
319 #define ENCODE_IMMEDIATE_FLAG (1 << 25)
321 #define ENCODE_BARREL_SHIFTER_SHIFT_BY_REGISTER (1 << 4)
322 #define ENCODE_BARREL_SHIFTER_MODE_LSL (0 << 5)
323 #define ENCODE_BARREL_SHIFTER_MODE_LSR (1 << 5)
324 #define ENCODE_BARREL_SHIFTER_MODE_ASR (2 << 5)
325 #define ENCODE_BARREL_SHIFTER_MODE_ROR (3 << 5)
326 #define ENCODE_BARREL_SHIFTER_REGISTER(register_index) ((register_index) << 8)
327 #define ENCODE_BARREL_SHIFTER_IMMEDIATE(value) ((value) << 7)
329 static void asm_block_data_transfer_opcode(TCCState *s1, int token)
331 uint32_t opcode;
332 int op0_exclam = 0;
333 Operand ops[2];
334 int nb_ops = 1;
335 parse_operand(s1, &ops[0]);
336 if (tok == '!') {
337 op0_exclam = 1;
338 next(); // skip '!'
340 if (tok == ',') {
341 next(); // skip comma
342 parse_operand(s1, &ops[1]);
343 ++nb_ops;
345 if (nb_ops < 1) {
346 expect("at least one operand");
347 return;
348 } else if (ops[nb_ops - 1].type != OP_REGSET32) {
349 expect("(last operand) register list");
350 return;
353 // block data transfer: 1 0 0 P U S W L << 20 (general case):
354 // operands:
355 // Rn: bits 19...16 base register
356 // Register List: bits 15...0
358 switch (ARM_INSTRUCTION_GROUP(token)) {
359 case TOK_ASM_pusheq: // TODO: Optimize 1-register case to: str ?, [sp, #-4]!
360 // Instruction: 1 I=0 P=1 U=0 S=0 W=1 L=0 << 20, op 1101
361 // operands:
362 // Rn: base register
363 // Register List: bits 15...0
364 if (nb_ops != 1)
365 expect("exactly one operand");
366 else
367 asm_emit_opcode(token, (0x92d << 16) | ops[0].regset); // TODO: base register ?
368 break;
369 case TOK_ASM_popeq: // TODO: Optimize 1-register case to: ldr ?, [sp], #4
370 // Instruction: 1 I=0 P=0 U=1 S=0 W=0 L=1 << 20, op 1101
371 // operands:
372 // Rn: base register
373 // Register List: bits 15...0
374 if (nb_ops != 1)
375 expect("exactly one operand");
376 else
377 asm_emit_opcode(token, (0x8bd << 16) | ops[0].regset); // TODO: base register ?
378 break;
379 case TOK_ASM_stmdaeq:
380 case TOK_ASM_ldmdaeq:
381 case TOK_ASM_stmeq:
382 case TOK_ASM_ldmeq:
383 case TOK_ASM_stmiaeq:
384 case TOK_ASM_ldmiaeq:
385 case TOK_ASM_stmdbeq:
386 case TOK_ASM_ldmdbeq:
387 case TOK_ASM_stmibeq:
388 case TOK_ASM_ldmibeq:
389 switch (ARM_INSTRUCTION_GROUP(token)) {
390 case TOK_ASM_stmdaeq: // post-decrement store
391 opcode = 0x80 << 20;
392 break;
393 case TOK_ASM_ldmdaeq: // post-decrement load
394 opcode = 0x81 << 20;
395 break;
396 case TOK_ASM_stmeq: // post-increment store
397 case TOK_ASM_stmiaeq: // post-increment store
398 opcode = 0x88 << 20;
399 break;
400 case TOK_ASM_ldmeq: // post-increment load
401 case TOK_ASM_ldmiaeq: // post-increment load
402 opcode = 0x89 << 20;
403 break;
404 case TOK_ASM_stmdbeq: // pre-decrement store
405 opcode = 0x90 << 20;
406 break;
407 case TOK_ASM_ldmdbeq: // pre-decrement load
408 opcode = 0x91 << 20;
409 break;
410 case TOK_ASM_stmibeq: // pre-increment store
411 opcode = 0x98 << 20;
412 break;
413 case TOK_ASM_ldmibeq: // pre-increment load
414 opcode = 0x99 << 20;
415 break;
416 default:
417 tcc_error("internal error: This place should not be reached (fallback in asm_block_data_transfer_opcode)");
419 // operands:
420 // Rn: first operand
421 // Register List: lower bits
422 if (nb_ops != 2)
423 expect("exactly two operands");
424 else if (ops[0].type != OP_REG32)
425 expect("(first operand) register");
426 else {
427 if (op0_exclam)
428 opcode |= 1 << 21; // writeback
429 asm_emit_opcode(token, opcode | ENCODE_RN(ops[0].reg) | ops[1].regset);
431 break;
432 default:
433 expect("block data transfer instruction");
437 /* Parses shift directive and returns the parts that would have to be set in the opcode because of it.
438 Does not encode the actual shift amount.
439 It's not an error if there is no shift directive.
441 NB_SHIFT: will be set to 1 iff SHIFT is filled. Note that for rrx, there's no need to fill SHIFT.
442 SHIFT: will be filled in with the shift operand to use, if any. */
443 static uint32_t asm_parse_optional_shift(TCCState* s1, int* nb_shift, Operand* shift)
445 uint32_t opcode = 0;
446 *nb_shift = 0;
447 switch (tok) {
448 case TOK_ASM_asl:
449 case TOK_ASM_lsl:
450 case TOK_ASM_asr:
451 case TOK_ASM_lsr:
452 case TOK_ASM_ror:
453 switch (tok) {
454 case TOK_ASM_asl:
455 /* fallthrough */
456 case TOK_ASM_lsl:
457 opcode = ENCODE_BARREL_SHIFTER_MODE_LSL;
458 break;
459 case TOK_ASM_asr:
460 opcode = ENCODE_BARREL_SHIFTER_MODE_ASR;
461 break;
462 case TOK_ASM_lsr:
463 opcode = ENCODE_BARREL_SHIFTER_MODE_LSR;
464 break;
465 case TOK_ASM_ror:
466 opcode = ENCODE_BARREL_SHIFTER_MODE_ROR;
467 break;
469 next();
470 parse_operand(s1, shift);
471 *nb_shift = 1;
472 break;
473 case TOK_ASM_rrx:
474 next();
475 opcode = ENCODE_BARREL_SHIFTER_MODE_ROR;
476 break;
478 return opcode;
481 static uint32_t asm_encode_shift(Operand* shift)
483 uint64_t amount;
484 uint32_t operands = 0;
485 switch (shift->type) {
486 case OP_REG32:
487 if (shift->reg == 15)
488 tcc_error("r15 cannot be used as a shift count");
489 else {
490 operands = ENCODE_BARREL_SHIFTER_SHIFT_BY_REGISTER;
491 operands |= ENCODE_BARREL_SHIFTER_REGISTER(shift->reg);
493 break;
494 case OP_IM8:
495 amount = shift->e.v;
496 if (amount > 0 && amount < 32)
497 operands = ENCODE_BARREL_SHIFTER_IMMEDIATE(amount);
498 else
499 tcc_error("shift count out of range");
500 break;
501 default:
502 tcc_error("unknown shift amount");
504 return operands;
507 static void asm_data_processing_opcode(TCCState *s1, int token)
509 Operand ops[3];
510 int nb_ops;
511 Operand shift = {};
512 int nb_shift = 0;
513 uint32_t operands = 0;
515 /* modulo 16 entries per instruction for the different condition codes */
516 uint32_t opcode_idx = (ARM_INSTRUCTION_GROUP(token) - TOK_ASM_andeq) >> 4;
517 uint32_t opcode_nos = opcode_idx >> 1; // without "s"; "OpCode" in ARM docs
519 for (nb_ops = 0; nb_ops < sizeof(ops)/sizeof(ops[0]); ) {
520 if (tok == TOK_ASM_asl || tok == TOK_ASM_lsl || tok == TOK_ASM_lsr || tok == TOK_ASM_asr || tok == TOK_ASM_ror || tok == TOK_ASM_rrx)
521 break;
522 parse_operand(s1, &ops[nb_ops]);
523 ++nb_ops;
524 if (tok != ',')
525 break;
526 next(); // skip ','
528 if (tok == ',')
529 next();
530 operands |= asm_parse_optional_shift(s1, &nb_shift, &shift);
531 if (nb_ops < 2)
532 expect("at least two operands");
533 else if (nb_ops == 2) {
534 memcpy(&ops[2], &ops[1], sizeof(ops[1])); // move ops[2]
535 memcpy(&ops[1], &ops[0], sizeof(ops[0])); // ops[1] was implicit
536 nb_ops = 3;
537 } else if (nb_ops == 3) {
538 if (opcode_nos == 0xd || opcode_nos == 0xf || opcode_nos == 0xa || opcode_nos == 0xb || opcode_nos == 0x8 || opcode_nos == 0x9) { // mov, mvn, cmp, cmn, tst, teq
539 tcc_error("'%s' cannot be used with three operands", get_tok_str(token, NULL));
540 return;
543 if (nb_ops != 3) {
544 expect("two or three operands");
545 return;
546 } else {
547 uint32_t opcode = 0;
548 uint32_t immediate_value;
549 uint8_t half_immediate_rotation;
550 if (nb_shift && shift.type == OP_REG32) {
551 if ((ops[0].type == OP_REG32 && ops[0].reg == 15) ||
552 (ops[1].type == OP_REG32 && ops[1].reg == 15)) {
553 tcc_error("Using the 'pc' register in data processing instructions that have a register-controlled shift is not implemented by ARM");
554 return;
558 // data processing (general case):
559 // operands:
560 // Rn: bits 19...16 (first operand)
561 // Rd: bits 15...12 (destination)
562 // Operand2: bits 11...0 (second operand); depending on I that's either a register or an immediate
563 // operator:
564 // bits 24...21: "OpCode"--see below
566 /* operations in the token list are ordered by opcode */
567 opcode = opcode_nos << 21; // drop "s"
568 if (ops[0].type != OP_REG32)
569 expect("(destination operand) register");
570 else if (opcode_nos == 0xa || opcode_nos == 0xb || opcode_nos == 0x8 || opcode_nos == 0x9) // cmp, cmn, tst, teq
571 operands |= ENCODE_SET_CONDITION_CODES; // force S set, otherwise it's a completely different instruction.
572 else
573 operands |= ENCODE_RD(ops[0].reg);
574 if (ops[1].type != OP_REG32)
575 expect("(first source operand) register");
576 else if (!(opcode_nos == 0xd || opcode_nos == 0xf)) // not: mov, mvn (those have only one source operand)
577 operands |= ENCODE_RN(ops[1].reg);
578 switch (ops[2].type) {
579 case OP_REG32:
580 operands |= ops[2].reg;
581 break;
582 case OP_IM8:
583 case OP_IM32:
584 operands |= ENCODE_IMMEDIATE_FLAG;
585 immediate_value = ops[2].e.v;
586 for (half_immediate_rotation = 0; half_immediate_rotation < 16; ++half_immediate_rotation) {
587 if (immediate_value >= 0x00 && immediate_value < 0x100)
588 break;
589 // rotate left by two
590 immediate_value = ((immediate_value & 0x3FFFFFFF) << 2) | ((immediate_value & 0xC0000000) >> 30);
592 if (half_immediate_rotation >= 16) {
593 /* fallthrough */
594 } else {
595 operands |= immediate_value;
596 operands |= half_immediate_rotation << 8;
597 break;
599 case OP_IM8N: // immediate negative value
600 operands |= ENCODE_IMMEDIATE_FLAG;
601 immediate_value = ops[2].e.v;
602 /* Instruction swapping:
603 0001 = EOR - Rd:= Op1 EOR Op2 -> difficult
604 0011 = RSB - Rd:= Op2 - Op1 -> difficult
605 0111 = RSC - Rd:= Op2 - Op1 + C -> difficult
606 1000 = TST - CC on: Op1 AND Op2 -> difficult
607 1001 = TEQ - CC on: Op1 EOR Op2 -> difficult
608 1100 = ORR - Rd:= Op1 OR Op2 -> difficult
610 switch (opcode_nos) {
611 case 0x0: // AND - Rd:= Op1 AND Op2
612 opcode = 0xe << 21; // BIC
613 immediate_value = ~immediate_value;
614 break;
615 case 0x2: // SUB - Rd:= Op1 - Op2
616 opcode = 0x4 << 21; // ADD
617 immediate_value = -immediate_value;
618 break;
619 case 0x4: // ADD - Rd:= Op1 + Op2
620 opcode = 0x2 << 21; // SUB
621 immediate_value = -immediate_value;
622 break;
623 case 0x5: // ADC - Rd:= Op1 + Op2 + C
624 opcode = 0x6 << 21; // SBC
625 immediate_value = ~immediate_value;
626 break;
627 case 0x6: // SBC - Rd:= Op1 - Op2 + C
628 opcode = 0x5 << 21; // ADC
629 immediate_value = ~immediate_value;
630 break;
631 case 0xa: // CMP - CC on: Op1 - Op2
632 opcode = 0xb << 21; // CMN
633 immediate_value = -immediate_value;
634 break;
635 case 0xb: // CMN - CC on: Op1 + Op2
636 opcode = 0xa << 21; // CMP
637 immediate_value = -immediate_value;
638 break;
639 case 0xd: // MOV - Rd:= Op2
640 opcode = 0xf << 21; // MVN
641 immediate_value = ~immediate_value;
642 break;
643 case 0xe: // BIC - Rd:= Op1 AND NOT Op2
644 opcode = 0x0 << 21; // AND
645 immediate_value = ~immediate_value;
646 break;
647 case 0xf: // MVN - Rd:= NOT Op2
648 opcode = 0xd << 21; // MOV
649 immediate_value = ~immediate_value;
650 break;
651 default:
652 tcc_error("cannot use '%s' with a negative immediate value", get_tok_str(token, NULL));
654 for (half_immediate_rotation = 0; half_immediate_rotation < 16; ++half_immediate_rotation) {
655 if (immediate_value >= 0x00 && immediate_value < 0x100)
656 break;
657 // rotate left by two
658 immediate_value = ((immediate_value & 0x3FFFFFFF) << 2) | ((immediate_value & 0xC0000000) >> 30);
660 if (half_immediate_rotation >= 16) {
661 immediate_value = ops[2].e.v;
662 tcc_error("immediate value 0x%X cannot be encoded into ARM immediate", (unsigned) immediate_value);
663 return;
665 operands |= immediate_value;
666 operands |= half_immediate_rotation << 8;
667 break;
668 default:
669 expect("(second source operand) register or immediate value");
672 if (nb_shift) {
673 if (operands & ENCODE_IMMEDIATE_FLAG)
674 tcc_error("immediate rotation not implemented");
675 else
676 operands |= asm_encode_shift(&shift);
679 /* S=0 and S=1 entries alternate one after another, in that order */
680 opcode |= (opcode_idx & 1) ? ENCODE_SET_CONDITION_CODES : 0;
681 asm_emit_opcode(token, opcode | operands);
685 static void asm_shift_opcode(TCCState *s1, int token)
687 Operand ops[3];
688 int nb_ops;
689 int definitely_neutral = 0;
690 uint32_t opcode = 0xd << 21; // MOV
691 uint32_t operands = 0;
693 for (nb_ops = 0; nb_ops < sizeof(ops)/sizeof(ops[0]); ++nb_ops) {
694 parse_operand(s1, &ops[nb_ops]);
695 if (tok != ',') {
696 ++nb_ops;
697 break;
699 next(); // skip ','
701 if (nb_ops < 2) {
702 expect("at least two operands");
703 return;
706 if (ops[0].type != OP_REG32) {
707 expect("(destination operand) register");
708 return;
709 } else
710 operands |= ENCODE_RD(ops[0].reg);
712 if (nb_ops == 2) {
713 switch (ARM_INSTRUCTION_GROUP(token)) {
714 case TOK_ASM_rrxseq:
715 opcode |= ENCODE_SET_CONDITION_CODES;
716 /* fallthrough */
717 case TOK_ASM_rrxeq:
718 if (ops[1].type == OP_REG32) {
719 operands |= ops[1].reg;
720 operands |= ENCODE_BARREL_SHIFTER_MODE_ROR;
721 asm_emit_opcode(token, opcode | operands);
722 } else
723 tcc_error("(first source operand) register");
724 return;
725 default:
726 memcpy(&ops[2], &ops[1], sizeof(ops[1])); // move ops[2]
727 memcpy(&ops[1], &ops[0], sizeof(ops[0])); // ops[1] was implicit
728 nb_ops = 3;
731 if (nb_ops != 3) {
732 expect("two or three operands");
733 return;
736 switch (ARM_INSTRUCTION_GROUP(token)) {
737 case TOK_ASM_lslseq:
738 case TOK_ASM_lsrseq:
739 case TOK_ASM_asrseq:
740 case TOK_ASM_rorseq:
741 opcode |= ENCODE_SET_CONDITION_CODES;
742 break;
745 switch (ops[1].type) {
746 case OP_REG32:
747 operands |= ops[1].reg;
748 break;
749 case OP_IM8:
750 operands |= ENCODE_IMMEDIATE_FLAG;
751 operands |= ops[1].e.v;
752 break;
755 switch (ops[2].type) {
756 case OP_REG32:
757 if ((ops[0].type == OP_REG32 && ops[0].reg == 15) ||
758 (ops[1].type == OP_REG32 && ops[1].reg == 15)) {
759 tcc_error("Using the 'pc' register in data processing instructions that have a register-controlled shift is not implemented by ARM");
761 operands |= asm_encode_shift(&ops[2]);
762 break;
763 case OP_IM8:
764 if (ops[2].e.v)
765 operands |= asm_encode_shift(&ops[2]);
766 else
767 definitely_neutral = 1;
768 break;
771 if (!definitely_neutral) switch (ARM_INSTRUCTION_GROUP(token)) {
772 case TOK_ASM_lslseq:
773 case TOK_ASM_lsleq:
774 operands |= ENCODE_BARREL_SHIFTER_MODE_LSL;
775 break;
776 case TOK_ASM_lsrseq:
777 case TOK_ASM_lsreq:
778 operands |= ENCODE_BARREL_SHIFTER_MODE_LSR;
779 break;
780 case TOK_ASM_asrseq:
781 case TOK_ASM_asreq:
782 operands |= ENCODE_BARREL_SHIFTER_MODE_ASR;
783 break;
784 case TOK_ASM_rorseq:
785 case TOK_ASM_roreq:
786 operands |= ENCODE_BARREL_SHIFTER_MODE_ROR;
787 break;
788 default:
789 expect("shift instruction");
790 return;
792 asm_emit_opcode(token, opcode | operands);
795 static void asm_multiplication_opcode(TCCState *s1, int token)
797 Operand ops[4];
798 int nb_ops = 0;
799 uint32_t opcode = 0x90;
801 for (nb_ops = 0; nb_ops < sizeof(ops)/sizeof(ops[0]); ++nb_ops) {
802 parse_operand(s1, &ops[nb_ops]);
803 if (tok != ',') {
804 ++nb_ops;
805 break;
807 next(); // skip ','
809 if (nb_ops < 2)
810 expect("at least two operands");
811 else if (nb_ops == 2) {
812 switch (ARM_INSTRUCTION_GROUP(token)) {
813 case TOK_ASM_mulseq:
814 case TOK_ASM_muleq:
815 memcpy(&ops[2], &ops[0], sizeof(ops[1])); // ARM is actually like this!
816 break;
817 default:
818 expect("at least three operands");
819 return;
821 nb_ops = 3;
824 // multiply (special case):
825 // operands:
826 // Rd: bits 19...16
827 // Rm: bits 3...0
828 // Rs: bits 11...8
829 // Rn: bits 15...12
831 if (ops[0].type == OP_REG32)
832 opcode |= ops[0].reg << 16;
833 else
834 expect("(destination operand) register");
835 if (ops[1].type == OP_REG32)
836 opcode |= ops[1].reg;
837 else
838 expect("(first source operand) register");
839 if (ops[2].type == OP_REG32)
840 opcode |= ops[2].reg << 8;
841 else
842 expect("(second source operand) register");
843 if (nb_ops > 3) {
844 if (ops[3].type == OP_REG32)
845 opcode |= ops[3].reg << 12;
846 else
847 expect("(third source operand) register");
850 switch (ARM_INSTRUCTION_GROUP(token)) {
851 case TOK_ASM_mulseq:
852 opcode |= 1 << 20; // Status
853 /* fallthrough */
854 case TOK_ASM_muleq:
855 if (nb_ops != 3)
856 expect("three operands");
857 else {
858 asm_emit_opcode(token, opcode);
860 break;
861 case TOK_ASM_mlaseq:
862 opcode |= 1 << 20; // Status
863 /* fallthrough */
864 case TOK_ASM_mlaeq:
865 if (nb_ops != 4)
866 expect("four operands");
867 else {
868 opcode |= 1 << 21; // Accumulate
869 asm_emit_opcode(token, opcode);
871 break;
872 default:
873 expect("known multiplication instruction");
877 static void asm_long_multiplication_opcode(TCCState *s1, int token)
879 Operand ops[4];
880 int nb_ops = 0;
881 uint32_t opcode = 0x90 | (1 << 23);
883 for (nb_ops = 0; nb_ops < sizeof(ops)/sizeof(ops[0]); ++nb_ops) {
884 parse_operand(s1, &ops[nb_ops]);
885 if (tok != ',') {
886 ++nb_ops;
887 break;
889 next(); // skip ','
891 if (nb_ops != 4) {
892 expect("four operands");
893 return;
896 // long multiply (special case):
897 // operands:
898 // RdLo: bits 15...12
899 // RdHi: bits 19...16
900 // Rs: bits 11...8
901 // Rm: bits 3...0
903 if (ops[0].type == OP_REG32)
904 opcode |= ops[0].reg << 12;
905 else
906 expect("(destination lo accumulator) register");
907 if (ops[1].type == OP_REG32)
908 opcode |= ops[1].reg << 16;
909 else
910 expect("(destination hi accumulator) register");
911 if (ops[2].type == OP_REG32)
912 opcode |= ops[2].reg;
913 else
914 expect("(first source operand) register");
915 if (ops[3].type == OP_REG32)
916 opcode |= ops[3].reg << 8;
917 else
918 expect("(second source operand) register");
920 switch (ARM_INSTRUCTION_GROUP(token)) {
921 case TOK_ASM_smullseq:
922 opcode |= 1 << 20; // Status
923 /* fallthrough */
924 case TOK_ASM_smulleq:
925 opcode |= 1 << 22; // signed
926 asm_emit_opcode(token, opcode);
927 break;
928 case TOK_ASM_umullseq:
929 opcode |= 1 << 20; // Status
930 /* fallthrough */
931 case TOK_ASM_umulleq:
932 asm_emit_opcode(token, opcode);
933 break;
934 case TOK_ASM_smlalseq:
935 opcode |= 1 << 20; // Status
936 /* fallthrough */
937 case TOK_ASM_smlaleq:
938 opcode |= 1 << 22; // signed
939 opcode |= 1 << 21; // Accumulate
940 asm_emit_opcode(token, opcode);
941 break;
942 case TOK_ASM_umlalseq:
943 opcode |= 1 << 20; // Status
944 /* fallthrough */
945 case TOK_ASM_umlaleq:
946 opcode |= 1 << 21; // Accumulate
947 asm_emit_opcode(token, opcode);
948 break;
949 default:
950 expect("known long multiplication instruction");
954 static void asm_single_data_transfer_opcode(TCCState *s1, int token)
956 Operand ops[3];
957 Operand strex_operand;
958 Operand shift;
959 int nb_shift = 0;
960 int exclam = 0;
961 int closed_bracket = 0;
962 int op2_minus = 0;
963 uint32_t opcode = 0;
964 // Note: ldr r0, [r4, #4] ; simple offset: r0 = *(int*)(r4+4); r4 unchanged
965 // Note: ldr r0, [r4, #4]! ; pre-indexed: r0 = *(int*)(r4+4); r4 = r4+4
966 // Note: ldr r0, [r4], #4 ; post-indexed: r0 = *(int*)(r4+0); r4 = r4+4
968 parse_operand(s1, &ops[0]);
969 if (ops[0].type == OP_REG32)
970 opcode |= ENCODE_RD(ops[0].reg);
971 else {
972 expect("(destination operand) register");
973 return;
975 if (tok != ',')
976 expect("at least two arguments");
977 else
978 next(); // skip ','
980 switch (ARM_INSTRUCTION_GROUP(token)) {
981 case TOK_ASM_strexbeq:
982 case TOK_ASM_strexeq:
983 parse_operand(s1, &strex_operand);
984 if (strex_operand.type != OP_REG32) {
985 expect("register");
986 return;
988 if (tok != ',')
989 expect("at least three arguments");
990 else
991 next(); // skip ','
992 break;
995 if (tok != '[')
996 expect("'['");
997 else
998 next(); // skip '['
1000 parse_operand(s1, &ops[1]);
1001 if (ops[1].type == OP_REG32)
1002 opcode |= ENCODE_RN(ops[1].reg);
1003 else {
1004 expect("(first source operand) register");
1005 return;
1007 if (tok == ']') {
1008 next();
1009 closed_bracket = 1;
1010 // exclam = 1; // implicit in hardware; don't do it in software
1012 if (tok == ',') {
1013 next(); // skip ','
1014 if (tok == '-') {
1015 op2_minus = 1;
1016 next();
1018 parse_operand(s1, &ops[2]);
1019 if (ops[2].type == OP_REG32) {
1020 if (ops[2].reg == 15) {
1021 tcc_error("Using 'pc' for register offset in '%s' is not implemented by ARM", get_tok_str(token, NULL));
1022 return;
1024 if (tok == ',') {
1025 next();
1026 opcode |= asm_parse_optional_shift(s1, &nb_shift, &shift);
1027 if (opcode == 0)
1028 expect("shift directive, or no comma");
1031 } else {
1032 // end of input expression in brackets--assume 0 offset
1033 ops[2].type = OP_IM8;
1034 ops[2].e.v = 0;
1035 opcode |= 1 << 24; // add offset before transfer
1037 if (!closed_bracket) {
1038 if (tok != ']')
1039 expect("']'");
1040 else
1041 next(); // skip ']'
1042 opcode |= 1 << 24; // add offset before transfer
1043 if (tok == '!') {
1044 exclam = 1;
1045 next(); // skip '!'
1049 // single data transfer: 0 1 I P U B W L << 20 (general case):
1050 // operands:
1051 // Rd: destination operand [ok]
1052 // Rn: first source operand [ok]
1053 // Operand2: bits 11...0 [ok]
1054 // I: immediate operand? [ok]
1055 // P: Pre/post indexing is PRE: Add offset before transfer [ok]
1056 // U: Up/down is up? (*adds* offset to base) [ok]
1057 // B: Byte/word is byte? TODO
1058 // W: Write address back into base? [ok]
1059 // L: Load/store is load? [ok]
1060 if (exclam)
1061 opcode |= 1 << 21; // write offset back into register
1063 if (ops[2].type == OP_IM32 || ops[2].type == OP_IM8 || ops[2].type == OP_IM8N) {
1064 int v = ops[2].e.v;
1065 if (op2_minus)
1066 tcc_error("minus before '#' not supported for immediate values");
1067 if (v >= 0) {
1068 opcode |= 1 << 23; // up
1069 if (v >= 0x1000)
1070 tcc_error("offset out of range for '%s'", get_tok_str(token, NULL));
1071 else
1072 opcode |= v;
1073 } else { // down
1074 if (v <= -0x1000)
1075 tcc_error("offset out of range for '%s'", get_tok_str(token, NULL));
1076 else
1077 opcode |= -v;
1079 } else if (ops[2].type == OP_REG32) {
1080 if (!op2_minus)
1081 opcode |= 1 << 23; // up
1082 opcode |= ENCODE_IMMEDIATE_FLAG; /* if set, it means it's NOT immediate */
1083 opcode |= ops[2].reg;
1084 } else
1085 expect("register");
1087 switch (ARM_INSTRUCTION_GROUP(token)) {
1088 case TOK_ASM_strbeq:
1089 opcode |= 1 << 22; // B
1090 /* fallthrough */
1091 case TOK_ASM_streq:
1092 opcode |= 1 << 26; // Load/Store
1093 if (nb_shift)
1094 opcode |= asm_encode_shift(&shift);
1095 asm_emit_opcode(token, opcode);
1096 break;
1097 case TOK_ASM_ldrbeq:
1098 opcode |= 1 << 22; // B
1099 /* fallthrough */
1100 case TOK_ASM_ldreq:
1101 opcode |= 1 << 20; // L
1102 opcode |= 1 << 26; // Load/Store
1103 if (nb_shift)
1104 opcode |= asm_encode_shift(&shift);
1105 asm_emit_opcode(token, opcode);
1106 break;
1107 case TOK_ASM_strexbeq:
1108 opcode |= 1 << 22; // B
1109 /* fallthrough */
1110 case TOK_ASM_strexeq:
1111 if ((opcode & 0xFFF) || nb_shift) {
1112 tcc_error("neither offset nor shift allowed with 'strex'");
1113 return;
1114 } else if (opcode & ENCODE_IMMEDIATE_FLAG) { // if set, it means it's NOT immediate
1115 tcc_error("offset not allowed with 'strex'");
1116 return;
1118 if ((opcode & (1 << 24)) == 0) { // add offset after transfer
1119 tcc_error("adding offset after transfer not allowed with 'strex'");
1120 return;
1123 opcode |= 0xf90; // Used to mean: barrel shifter is enabled, barrel shift register is r15, mode is LSL
1124 opcode |= strex_operand.reg;
1125 asm_emit_opcode(token, opcode);
1126 break;
1127 case TOK_ASM_ldrexbeq:
1128 opcode |= 1 << 22; // B
1129 /* fallthrough */
1130 case TOK_ASM_ldrexeq:
1131 if ((opcode & 0xFFF) || nb_shift) {
1132 tcc_error("neither offset nor shift allowed with 'ldrex'");
1133 return;
1134 } else if (opcode & ENCODE_IMMEDIATE_FLAG) { // if set, it means it's NOT immediate
1135 tcc_error("offset not allowed with 'ldrex'");
1136 return;
1138 if ((opcode & (1 << 24)) == 0) { // add offset after transfer
1139 tcc_error("adding offset after transfer not allowed with 'ldrex'");
1140 return;
1142 opcode |= 1 << 20; // L
1143 opcode |= 0x00f;
1144 opcode |= 0xf90; // Used to mean: barrel shifter is enabled, barrel shift register is r15, mode is LSL
1145 asm_emit_opcode(token, opcode);
1146 break;
1147 default:
1148 expect("data transfer instruction");
1152 static void asm_misc_single_data_transfer_opcode(TCCState *s1, int token)
1154 Operand ops[3];
1155 int exclam = 0;
1156 int closed_bracket = 0;
1157 int op2_minus = 0;
1158 uint32_t opcode = (1 << 7) | (1 << 4);
1160 /* Note:
1161 The argument syntax is exactly the same as in arm_single_data_transfer_opcode, except that there's no STREX argument form.
1162 The main difference between this function and asm_misc_single_data_transfer_opcode is that the immediate values here must be smaller.
1163 Also, the combination (P=0, W=1) is unpredictable here.
1164 The immediate flag has moved to bit index 22--and its meaning has flipped.
1165 The immediate value itself has been split into two parts: one at bits 11...8, one at bits 3...0
1166 bit 26 (Load/Store instruction) is unset here.
1167 bits 7 and 4 are set here. */
1169 // Here: 0 0 0 P U I W L << 20
1170 // [compare single data transfer: 0 1 I P U B W L << 20]
1172 parse_operand(s1, &ops[0]);
1173 if (ops[0].type == OP_REG32)
1174 opcode |= ENCODE_RD(ops[0].reg);
1175 else {
1176 expect("(destination operand) register");
1177 return;
1179 if (tok != ',')
1180 expect("at least two arguments");
1181 else
1182 next(); // skip ','
1184 if (tok != '[')
1185 expect("'['");
1186 else
1187 next(); // skip '['
1189 parse_operand(s1, &ops[1]);
1190 if (ops[1].type == OP_REG32)
1191 opcode |= ENCODE_RN(ops[1].reg);
1192 else {
1193 expect("(first source operand) register");
1194 return;
1196 if (tok == ']') {
1197 next();
1198 closed_bracket = 1;
1199 // exclam = 1; // implicit in hardware; don't do it in software
1201 if (tok == ',') {
1202 next(); // skip ','
1203 if (tok == '-') {
1204 op2_minus = 1;
1205 next();
1207 parse_operand(s1, &ops[2]);
1208 } else {
1209 // end of input expression in brackets--assume 0 offset
1210 ops[2].type = OP_IM8;
1211 ops[2].e.v = 0;
1212 opcode |= 1 << 24; // add offset before transfer
1214 if (!closed_bracket) {
1215 if (tok != ']')
1216 expect("']'");
1217 else
1218 next(); // skip ']'
1219 opcode |= 1 << 24; // add offset before transfer
1220 if (tok == '!') {
1221 exclam = 1;
1222 next(); // skip '!'
1226 if (exclam) {
1227 if ((opcode & (1 << 24)) == 0) {
1228 tcc_error("result of '%s' would be unpredictable here", get_tok_str(token, NULL));
1229 return;
1231 opcode |= 1 << 21; // write offset back into register
1234 if (ops[2].type == OP_IM32 || ops[2].type == OP_IM8 || ops[2].type == OP_IM8N) {
1235 int v = ops[2].e.v;
1236 if (op2_minus)
1237 tcc_error("minus before '#' not supported for immediate values");
1238 if (v >= 0) {
1239 opcode |= 1 << 23; // up
1240 if (v >= 0x100)
1241 tcc_error("offset out of range for '%s'", get_tok_str(token, NULL));
1242 else {
1243 // bits 11...8: immediate hi nibble
1244 // bits 3...0: immediate lo nibble
1245 opcode |= (v & 0xF0) << 4;
1246 opcode |= v & 0xF;
1248 } else { // down
1249 if (v <= -0x100)
1250 tcc_error("offset out of range for '%s'", get_tok_str(token, NULL));
1251 else {
1252 v = -v;
1253 // bits 11...8: immediate hi nibble
1254 // bits 3...0: immediate lo nibble
1255 opcode |= (v & 0xF0) << 4;
1256 opcode |= v & 0xF;
1259 opcode |= 1 << 22; // not ENCODE_IMMEDIATE_FLAG;
1260 } else if (ops[2].type == OP_REG32) {
1261 if (!op2_minus)
1262 opcode |= 1 << 23; // up
1263 opcode |= ops[2].reg;
1264 } else
1265 expect("register");
1267 switch (ARM_INSTRUCTION_GROUP(token)) {
1268 case TOK_ASM_ldrsheq:
1269 opcode |= 1 << 5; // halfword, not byte
1270 /* fallthrough */
1271 case TOK_ASM_ldrsbeq:
1272 opcode |= 1 << 6; // sign extend
1273 opcode |= 1 << 20; // L
1274 asm_emit_opcode(token, opcode);
1275 break;
1276 case TOK_ASM_ldrheq:
1277 opcode |= 1 << 5; // halfword, not byte
1278 opcode |= 1 << 20; // L
1279 asm_emit_opcode(token, opcode);
1280 break;
1281 case TOK_ASM_strheq:
1282 opcode |= 1 << 5; // halfword, not byte
1283 asm_emit_opcode(token, opcode);
1284 break;
1288 /* Note: almost dupe of encbranch in arm-gen.c */
1289 static uint32_t encbranchoffset(int pos, int addr, int fail)
1291 addr-=pos+8;
1292 addr/=4;
1293 if(addr>=0x7fffff || addr<-0x800000) {
1294 if(fail)
1295 tcc_error("branch offset is too far");
1296 return 0;
1298 return /*not 0x0A000000|*/(addr&0xffffff);
1301 static void asm_branch_opcode(TCCState *s1, int token)
1303 int jmp_disp = 0;
1304 Operand op;
1305 ExprValue e;
1306 ElfSym *esym;
1308 switch (ARM_INSTRUCTION_GROUP(token)) {
1309 case TOK_ASM_beq:
1310 case TOK_ASM_bleq:
1311 asm_expr(s1, &e);
1312 esym = elfsym(e.sym);
1313 if (!esym || esym->st_shndx != cur_text_section->sh_num) {
1314 tcc_error("invalid branch target");
1315 return;
1317 jmp_disp = encbranchoffset(ind, e.v + esym->st_value, 1);
1318 break;
1319 default:
1320 parse_operand(s1, &op);
1321 break;
1323 switch (ARM_INSTRUCTION_GROUP(token)) {
1324 case TOK_ASM_beq:
1325 asm_emit_opcode(token, (0xa << 24) | (jmp_disp & 0xffffff));
1326 break;
1327 case TOK_ASM_bleq:
1328 asm_emit_opcode(token, (0xb << 24) | (jmp_disp & 0xffffff));
1329 break;
1330 case TOK_ASM_bxeq:
1331 if (op.type != OP_REG32)
1332 expect("register");
1333 else
1334 asm_emit_opcode(token, (0x12fff1 << 4) | op.reg);
1335 break;
1336 case TOK_ASM_blxeq:
1337 if (op.type != OP_REG32)
1338 expect("register");
1339 else
1340 asm_emit_opcode(token, (0x12fff3 << 4) | op.reg);
1341 break;
1342 default:
1343 expect("branch instruction");
1347 ST_FUNC void asm_opcode(TCCState *s1, int token)
1349 while (token == TOK_LINEFEED) {
1350 next();
1351 token = tok;
1353 if (token == TOK_EOF)
1354 return;
1355 if (token < TOK_ASM_nopeq) {
1356 expect("instruction");
1357 return;
1360 switch (ARM_INSTRUCTION_GROUP(token)) {
1361 case TOK_ASM_pusheq:
1362 case TOK_ASM_popeq:
1363 case TOK_ASM_stmdaeq:
1364 case TOK_ASM_ldmdaeq:
1365 case TOK_ASM_stmeq:
1366 case TOK_ASM_ldmeq:
1367 case TOK_ASM_stmiaeq:
1368 case TOK_ASM_ldmiaeq:
1369 case TOK_ASM_stmdbeq:
1370 case TOK_ASM_ldmdbeq:
1371 case TOK_ASM_stmibeq:
1372 case TOK_ASM_ldmibeq:
1373 return asm_block_data_transfer_opcode(s1, token);
1374 case TOK_ASM_nopeq:
1375 case TOK_ASM_wfeeq:
1376 case TOK_ASM_wfieq:
1377 return asm_nullary_opcode(token);
1378 case TOK_ASM_swieq:
1379 return asm_unary_opcode(s1, token);
1380 case TOK_ASM_beq:
1381 case TOK_ASM_bleq:
1382 case TOK_ASM_bxeq:
1383 case TOK_ASM_blxeq:
1384 return asm_branch_opcode(s1, token);
1385 case TOK_ASM_clzeq:
1386 case TOK_ASM_sxtbeq:
1387 case TOK_ASM_sxtheq:
1388 case TOK_ASM_uxtbeq:
1389 case TOK_ASM_uxtheq:
1390 case TOK_ASM_movteq:
1391 case TOK_ASM_movweq:
1392 return asm_binary_opcode(s1, token);
1394 case TOK_ASM_ldreq:
1395 case TOK_ASM_ldrbeq:
1396 case TOK_ASM_streq:
1397 case TOK_ASM_strbeq:
1398 case TOK_ASM_ldrexeq:
1399 case TOK_ASM_ldrexbeq:
1400 case TOK_ASM_strexeq:
1401 case TOK_ASM_strexbeq:
1402 return asm_single_data_transfer_opcode(s1, token);
1404 case TOK_ASM_ldrheq:
1405 case TOK_ASM_ldrsheq:
1406 case TOK_ASM_ldrsbeq:
1407 case TOK_ASM_strheq:
1408 return asm_misc_single_data_transfer_opcode(s1, token);
1410 case TOK_ASM_andeq:
1411 case TOK_ASM_eoreq:
1412 case TOK_ASM_subeq:
1413 case TOK_ASM_rsbeq:
1414 case TOK_ASM_addeq:
1415 case TOK_ASM_adceq:
1416 case TOK_ASM_sbceq:
1417 case TOK_ASM_rsceq:
1418 case TOK_ASM_tsteq:
1419 case TOK_ASM_teqeq:
1420 case TOK_ASM_cmpeq:
1421 case TOK_ASM_cmneq:
1422 case TOK_ASM_orreq:
1423 case TOK_ASM_moveq:
1424 case TOK_ASM_biceq:
1425 case TOK_ASM_mvneq:
1426 case TOK_ASM_andseq:
1427 case TOK_ASM_eorseq:
1428 case TOK_ASM_subseq:
1429 case TOK_ASM_rsbseq:
1430 case TOK_ASM_addseq:
1431 case TOK_ASM_adcseq:
1432 case TOK_ASM_sbcseq:
1433 case TOK_ASM_rscseq:
1434 // case TOK_ASM_tstseq:
1435 // case TOK_ASM_teqseq:
1436 // case TOK_ASM_cmpseq:
1437 // case TOK_ASM_cmnseq:
1438 case TOK_ASM_orrseq:
1439 case TOK_ASM_movseq:
1440 case TOK_ASM_bicseq:
1441 case TOK_ASM_mvnseq:
1442 return asm_data_processing_opcode(s1, token);
1444 case TOK_ASM_lsleq:
1445 case TOK_ASM_lslseq:
1446 case TOK_ASM_lsreq:
1447 case TOK_ASM_lsrseq:
1448 case TOK_ASM_asreq:
1449 case TOK_ASM_asrseq:
1450 case TOK_ASM_roreq:
1451 case TOK_ASM_rorseq:
1452 case TOK_ASM_rrxseq:
1453 case TOK_ASM_rrxeq:
1454 return asm_shift_opcode(s1, token);
1456 case TOK_ASM_muleq:
1457 case TOK_ASM_mulseq:
1458 case TOK_ASM_mlaeq:
1459 case TOK_ASM_mlaseq:
1460 return asm_multiplication_opcode(s1, token);
1462 case TOK_ASM_smulleq:
1463 case TOK_ASM_smullseq:
1464 case TOK_ASM_umulleq:
1465 case TOK_ASM_umullseq:
1466 case TOK_ASM_smlaleq:
1467 case TOK_ASM_smlalseq:
1468 case TOK_ASM_umlaleq:
1469 case TOK_ASM_umlalseq:
1470 return asm_long_multiplication_opcode(s1, token);
1471 default:
1472 expect("known instruction");
1476 ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier)
1478 int r, reg, size, val;
1479 char buf[64];
1481 r = sv->r;
1482 if ((r & VT_VALMASK) == VT_CONST) {
1483 if (!(r & VT_LVAL) && modifier != 'c' && modifier != 'n' &&
1484 modifier != 'P')
1485 cstr_ccat(add_str, '#');
1486 if (r & VT_SYM) {
1487 const char *name = get_tok_str(sv->sym->v, NULL);
1488 if (sv->sym->v >= SYM_FIRST_ANOM) {
1489 /* In case of anonymous symbols ("L.42", used
1490 for static data labels) we can't find them
1491 in the C symbol table when later looking up
1492 this name. So enter them now into the asm label
1493 list when we still know the symbol. */
1494 get_asm_sym(tok_alloc(name, strlen(name))->tok, sv->sym);
1496 if (tcc_state->leading_underscore)
1497 cstr_ccat(add_str, '_');
1498 cstr_cat(add_str, name, -1);
1499 if ((uint32_t) sv->c.i == 0)
1500 goto no_offset;
1501 cstr_ccat(add_str, '+');
1503 val = sv->c.i;
1504 if (modifier == 'n')
1505 val = -val;
1506 snprintf(buf, sizeof(buf), "%d", (int) sv->c.i);
1507 cstr_cat(add_str, buf, -1);
1508 no_offset:;
1509 } else if ((r & VT_VALMASK) == VT_LOCAL) {
1510 snprintf(buf, sizeof(buf), "[fp,#%d]", (int) sv->c.i);
1511 cstr_cat(add_str, buf, -1);
1512 } else if (r & VT_LVAL) {
1513 reg = r & VT_VALMASK;
1514 if (reg >= VT_CONST)
1515 tcc_internal_error("");
1516 snprintf(buf, sizeof(buf), "[%s]",
1517 get_tok_str(TOK_ASM_r0 + reg, NULL));
1518 cstr_cat(add_str, buf, -1);
1519 } else {
1520 /* register case */
1521 reg = r & VT_VALMASK;
1522 if (reg >= VT_CONST)
1523 tcc_internal_error("");
1525 /* choose register operand size */
1526 if ((sv->type.t & VT_BTYPE) == VT_BYTE ||
1527 (sv->type.t & VT_BTYPE) == VT_BOOL)
1528 size = 1;
1529 else if ((sv->type.t & VT_BTYPE) == VT_SHORT)
1530 size = 2;
1531 else
1532 size = 4;
1534 if (modifier == 'b') {
1535 size = 1;
1536 } else if (modifier == 'w') {
1537 size = 2;
1538 } else if (modifier == 'k') {
1539 size = 4;
1542 switch (size) {
1543 default:
1544 reg = TOK_ASM_r0 + reg;
1545 break;
1547 snprintf(buf, sizeof(buf), "%s", get_tok_str(reg, NULL));
1548 cstr_cat(add_str, buf, -1);
1552 /* generate prolog and epilog code for asm statement */
1553 ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands,
1554 int nb_outputs, int is_output,
1555 uint8_t *clobber_regs,
1556 int out_reg)
1558 uint8_t regs_allocated[NB_ASM_REGS];
1559 ASMOperand *op;
1560 int i, reg;
1561 uint32_t saved_regset = 0;
1563 // TODO: Check non-E ABI.
1564 // Note: Technically, r13 (sp) is also callee-saved--but that does not matter yet
1565 static uint8_t reg_saved[] = { 4, 5, 6, 7, 8, 9 /* Note: sometimes special reg "sb" */ , 10, 11 };
1567 /* mark all used registers */
1568 memcpy(regs_allocated, clobber_regs, sizeof(regs_allocated));
1569 for(i = 0; i < nb_operands;i++) {
1570 op = &operands[i];
1571 if (op->reg >= 0)
1572 regs_allocated[op->reg] = 1;
1574 for(i = 0; i < sizeof(reg_saved)/sizeof(reg_saved[0]); i++) {
1575 reg = reg_saved[i];
1576 if (regs_allocated[reg])
1577 saved_regset |= 1 << reg;
1580 if (!is_output) { // prolog
1581 /* generate reg save code */
1582 if (saved_regset)
1583 gen_le32(0xe92d0000 | saved_regset); // push {...}
1585 /* generate load code */
1586 for(i = 0; i < nb_operands; i++) {
1587 op = &operands[i];
1588 if (op->reg >= 0) {
1589 if ((op->vt->r & VT_VALMASK) == VT_LLOCAL &&
1590 op->is_memory) {
1591 /* memory reference case (for both input and
1592 output cases) */
1593 SValue sv;
1594 sv = *op->vt;
1595 sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL | VT_LVAL;
1596 sv.type.t = VT_PTR;
1597 load(op->reg, &sv);
1598 } else if (i >= nb_outputs || op->is_rw) { // not write-only
1599 /* load value in register */
1600 load(op->reg, op->vt);
1601 if (op->is_llong)
1602 tcc_error("long long not implemented");
1606 } else { // epilog
1607 /* generate save code */
1608 for(i = 0 ; i < nb_outputs; i++) {
1609 op = &operands[i];
1610 if (op->reg >= 0) {
1611 if ((op->vt->r & VT_VALMASK) == VT_LLOCAL) {
1612 if (!op->is_memory) {
1613 SValue sv;
1614 sv = *op->vt;
1615 sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL;
1616 sv.type.t = VT_PTR;
1617 load(out_reg, &sv);
1619 sv = *op->vt;
1620 sv.r = (sv.r & ~VT_VALMASK) | out_reg;
1621 store(op->reg, &sv);
1623 } else {
1624 store(op->reg, op->vt);
1625 if (op->is_llong)
1626 tcc_error("long long not implemented");
1631 /* generate reg restore code */
1632 if (saved_regset)
1633 gen_le32(0xe8bd0000 | saved_regset); // pop {...}
1637 /* return the constraint priority (we allocate first the lowest
1638 numbered constraints) */
1639 static inline int constraint_priority(const char *str)
1641 int priority, c, pr;
1643 /* we take the lowest priority */
1644 priority = 0;
1645 for(;;) {
1646 c = *str;
1647 if (c == '\0')
1648 break;
1649 str++;
1650 switch(c) {
1651 case 'l': // in ARM mode, that's an alias for 'r' [ARM].
1652 case 'r': // register [general]
1653 case 'p': // valid memory address for load,store [general]
1654 pr = 3;
1655 break;
1656 case 'M': // integer constant for shifts [ARM]
1657 case 'I': // integer valid for data processing instruction immediate
1658 case 'J': // integer in range -4095...4095
1660 case 'i': // immediate integer operand, including symbolic constants [general]
1661 case 'm': // memory operand [general]
1662 case 'g': // general-purpose-register, memory, immediate integer [general]
1663 pr = 4;
1664 break;
1665 default:
1666 tcc_error("unknown constraint '%c'", c);
1667 pr = 0;
1669 if (pr > priority)
1670 priority = pr;
1672 return priority;
1675 static const char *skip_constraint_modifiers(const char *p)
1677 /* Constraint modifier:
1678 = Operand is written to by this instruction
1679 + Operand is both read and written to by this instruction
1680 % Instruction is commutative for this operand and the following operand.
1682 Per-alternative constraint modifier:
1683 & Operand is clobbered before the instruction is done using the input operands
1685 while (*p == '=' || *p == '&' || *p == '+' || *p == '%')
1686 p++;
1687 return p;
1690 #define REG_OUT_MASK 0x01
1691 #define REG_IN_MASK 0x02
1693 #define is_reg_allocated(reg) (regs_allocated[reg] & reg_mask)
1695 ST_FUNC void asm_compute_constraints(ASMOperand *operands,
1696 int nb_operands, int nb_outputs,
1697 const uint8_t *clobber_regs,
1698 int *pout_reg)
1700 /* overall format: modifier, then ,-seperated list of alternatives; all operands for a single instruction must have the same number of alternatives */
1701 /* TODO: Simple constraints
1702 whitespace ignored
1703 o memory operand that is offsetable
1704 V memory but not offsetable
1705 < memory operand with autodecrement addressing is allowed. Restrictions apply.
1706 > memory operand with autoincrement addressing is allowed. Restrictions apply.
1707 n immediate integer operand with a known numeric value
1708 E immediate floating operand (const_double) is allowed, but only if target=host
1709 F immediate floating operand (const_double or const_vector) is allowed
1710 s immediate integer operand whose value is not an explicit integer
1711 X any operand whatsoever
1712 0...9 (postfix); (can also be more than 1 digit number); an operand that matches the specified operand number is allowed
1715 /* TODO: ARM constraints:
1716 k the stack pointer register
1717 G the floating-point constant 0.0
1718 Q memory reference where the exact address is in a single register ("m" is preferable for asm statements)
1719 R an item in the constant pool
1720 S symbol in the text segment of the current file
1721 [ Uv memory reference suitable for VFP load/store insns (reg+constant offset)]
1722 [ Uy memory reference suitable for iWMMXt load/store instructions]
1723 Uq memory reference suitable for the ARMv4 ldrsb instruction
1725 ASMOperand *op;
1726 int sorted_op[MAX_ASM_OPERANDS];
1727 int i, j, k, p1, p2, tmp, reg, c, reg_mask;
1728 const char *str;
1729 uint8_t regs_allocated[NB_ASM_REGS];
1731 /* init fields */
1732 for (i = 0; i < nb_operands; i++) {
1733 op = &operands[i];
1734 op->input_index = -1;
1735 op->ref_index = -1;
1736 op->reg = -1;
1737 op->is_memory = 0;
1738 op->is_rw = 0;
1740 /* compute constraint priority and evaluate references to output
1741 constraints if input constraints */
1742 for (i = 0; i < nb_operands; i++) {
1743 op = &operands[i];
1744 str = op->constraint;
1745 str = skip_constraint_modifiers(str);
1746 if (isnum(*str) || *str == '[') {
1747 /* this is a reference to another constraint */
1748 k = find_constraint(operands, nb_operands, str, NULL);
1749 if ((unsigned) k >= i || i < nb_outputs)
1750 tcc_error("invalid reference in constraint %d ('%s')",
1751 i, str);
1752 op->ref_index = k;
1753 if (operands[k].input_index >= 0)
1754 tcc_error("cannot reference twice the same operand");
1755 operands[k].input_index = i;
1756 op->priority = 5;
1757 } else if ((op->vt->r & VT_VALMASK) == VT_LOCAL
1758 && op->vt->sym
1759 && (reg = op->vt->sym->r & VT_VALMASK) < VT_CONST) {
1760 op->priority = 1;
1761 op->reg = reg;
1762 } else {
1763 op->priority = constraint_priority(str);
1767 /* sort operands according to their priority */
1768 for (i = 0; i < nb_operands; i++)
1769 sorted_op[i] = i;
1770 for (i = 0; i < nb_operands - 1; i++) {
1771 for (j = i + 1; j < nb_operands; j++) {
1772 p1 = operands[sorted_op[i]].priority;
1773 p2 = operands[sorted_op[j]].priority;
1774 if (p2 < p1) {
1775 tmp = sorted_op[i];
1776 sorted_op[i] = sorted_op[j];
1777 sorted_op[j] = tmp;
1782 for (i = 0; i < NB_ASM_REGS; i++) {
1783 if (clobber_regs[i])
1784 regs_allocated[i] = REG_IN_MASK | REG_OUT_MASK;
1785 else
1786 regs_allocated[i] = 0;
1788 /* sp cannot be used */
1789 regs_allocated[13] = REG_IN_MASK | REG_OUT_MASK;
1790 /* fp cannot be used yet */
1791 regs_allocated[11] = REG_IN_MASK | REG_OUT_MASK;
1793 /* allocate registers and generate corresponding asm moves */
1794 for (i = 0; i < nb_operands; i++) {
1795 j = sorted_op[i];
1796 op = &operands[j];
1797 str = op->constraint;
1798 /* no need to allocate references */
1799 if (op->ref_index >= 0)
1800 continue;
1801 /* select if register is used for output, input or both */
1802 if (op->input_index >= 0) {
1803 reg_mask = REG_IN_MASK | REG_OUT_MASK;
1804 } else if (j < nb_outputs) {
1805 reg_mask = REG_OUT_MASK;
1806 } else {
1807 reg_mask = REG_IN_MASK;
1809 if (op->reg >= 0) {
1810 if (is_reg_allocated(op->reg))
1811 tcc_error
1812 ("asm regvar requests register that's taken already");
1813 reg = op->reg;
1814 goto reg_found;
1816 try_next:
1817 c = *str++;
1818 switch (c) {
1819 case '=': // Operand is written-to
1820 goto try_next;
1821 case '+': // Operand is both READ and written-to
1822 op->is_rw = 1;
1823 /* FALL THRU */
1824 case '&': // Operand is clobbered before the instruction is done using the input operands
1825 if (j >= nb_outputs)
1826 tcc_error("'%c' modifier can only be applied to outputs",
1828 reg_mask = REG_IN_MASK | REG_OUT_MASK;
1829 goto try_next;
1830 case 'l': // In non-thumb mode, alias for 'r'--otherwise r0-r7 [ARM]
1831 case 'r': // general-purpose register
1832 case 'p': // loadable/storable address
1833 /* any general register */
1834 for (reg = 0; reg <= 8; reg++) {
1835 if (!is_reg_allocated(reg))
1836 goto reg_found;
1838 goto try_next;
1839 reg_found:
1840 /* now we can reload in the register */
1841 op->is_llong = 0;
1842 op->reg = reg;
1843 regs_allocated[reg] |= reg_mask;
1844 break;
1845 case 'I': // integer that is valid as an data processing instruction immediate (0...255, rotated by a multiple of two)
1846 case 'J': // integer in the range -4095 to 4095 [ARM]
1847 case 'K': // integer that satisfies constraint I when inverted (one's complement)
1848 case 'L': // integer that satisfies constraint I when inverted (two's complement)
1849 case 'i': // immediate integer operand, including symbolic constants
1850 if (!((op->vt->r & (VT_VALMASK | VT_LVAL)) == VT_CONST))
1851 goto try_next;
1852 break;
1853 case 'M': // integer in the range 0 to 32
1854 if (!
1855 ((op->vt->r & (VT_VALMASK | VT_LVAL | VT_SYM)) ==
1856 VT_CONST))
1857 goto try_next;
1858 break;
1859 case 'm': // memory operand
1860 case 'g':
1861 /* nothing special to do because the operand is already in
1862 memory, except if the pointer itself is stored in a
1863 memory variable (VT_LLOCAL case) */
1864 /* XXX: fix constant case */
1865 /* if it is a reference to a memory zone, it must lie
1866 in a register, so we reserve the register in the
1867 input registers and a load will be generated
1868 later */
1869 if (j < nb_outputs || c == 'm') {
1870 if ((op->vt->r & VT_VALMASK) == VT_LLOCAL) {
1871 /* any general register */
1872 for (reg = 0; reg <= 8; reg++) {
1873 if (!(regs_allocated[reg] & REG_IN_MASK))
1874 goto reg_found1;
1876 goto try_next;
1877 reg_found1:
1878 /* now we can reload in the register */
1879 regs_allocated[reg] |= REG_IN_MASK;
1880 op->reg = reg;
1881 op->is_memory = 1;
1884 break;
1885 default:
1886 tcc_error("asm constraint %d ('%s') could not be satisfied",
1887 j, op->constraint);
1888 break;
1890 /* if a reference is present for that operand, we assign it too */
1891 if (op->input_index >= 0) {
1892 operands[op->input_index].reg = op->reg;
1893 operands[op->input_index].is_llong = op->is_llong;
1897 /* compute out_reg. It is used to store outputs registers to memory
1898 locations references by pointers (VT_LLOCAL case) */
1899 *pout_reg = -1;
1900 for (i = 0; i < nb_operands; i++) {
1901 op = &operands[i];
1902 if (op->reg >= 0 &&
1903 (op->vt->r & VT_VALMASK) == VT_LLOCAL && !op->is_memory) {
1904 for (reg = 0; reg <= 8; reg++) {
1905 if (!(regs_allocated[reg] & REG_OUT_MASK))
1906 goto reg_found2;
1908 tcc_error("could not find free output register for reloading");
1909 reg_found2:
1910 *pout_reg = reg;
1911 break;
1915 /* print sorted constraints */
1916 #ifdef ASM_DEBUG
1917 for (i = 0; i < nb_operands; i++) {
1918 j = sorted_op[i];
1919 op = &operands[j];
1920 printf("%%%d [%s]: \"%s\" r=0x%04x reg=%d\n",
1922 op->id ? get_tok_str(op->id, NULL) : "",
1923 op->constraint, op->vt->r, op->reg);
1925 if (*pout_reg >= 0)
1926 printf("out_reg=%d\n", *pout_reg);
1927 #endif
1930 ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str)
1932 int reg;
1933 TokenSym *ts;
1935 if (!strcmp(str, "memory") ||
1936 !strcmp(str, "cc") ||
1937 !strcmp(str, "flags"))
1938 return;
1939 ts = tok_alloc(str, strlen(str));
1940 reg = asm_parse_regvar(ts->tok);
1941 if (reg == -1) {
1942 tcc_error("invalid clobber register '%s'", str);
1944 clobber_regs[reg] = 1;
1947 /* If T refers to a register then return the register number and type.
1948 Otherwise return -1. */
1949 ST_FUNC int asm_parse_regvar (int t)
1951 if (t >= TOK_ASM_r0 && t <= TOK_ASM_pc) { /* register name */
1952 switch (t) {
1953 case TOK_ASM_fp:
1954 return TOK_ASM_r11 - TOK_ASM_r0;
1955 case TOK_ASM_ip:
1956 return TOK_ASM_r12 - TOK_ASM_r0;
1957 case TOK_ASM_sp:
1958 return TOK_ASM_r13 - TOK_ASM_r0;
1959 case TOK_ASM_lr:
1960 return TOK_ASM_r14 - TOK_ASM_r0;
1961 case TOK_ASM_pc:
1962 return TOK_ASM_r15 - TOK_ASM_r0;
1963 default:
1964 return t - TOK_ASM_r0;
1966 } else
1967 return -1;
1970 /*************************************************************/
1971 #endif /* ndef TARGET_DEFS_ONLY */