Better handling of UCNs in strings
[tinycc.git] / arm-asm.c
blob285ec5e60598a8cd79049cf76b6c994b22c44d94
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;
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 = 0x82 << 20;
392 break;
393 case TOK_ASM_ldmdaeq: // post-decrement load
394 opcode = 0x83 << 20;
395 break;
396 case TOK_ASM_stmeq: // post-increment store
397 case TOK_ASM_stmiaeq: // post-increment store
398 opcode = 0x8a << 20;
399 break;
400 case TOK_ASM_ldmeq: // post-increment load
401 case TOK_ASM_ldmiaeq: // post-increment load
402 opcode = 0x8b << 20;
403 break;
404 case TOK_ASM_stmdbeq: // pre-decrement store
405 opcode = 0x92 << 20;
406 break;
407 case TOK_ASM_ldmdbeq: // pre-decrement load
408 opcode = 0x93 << 20;
409 break;
410 case TOK_ASM_stmibeq: // pre-increment store
411 opcode = 0x9a << 20;
412 break;
413 case TOK_ASM_ldmibeq: // pre-increment load
414 opcode = 0x9b << 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 if (!op0_exclam)
427 tcc_error("first operand of '%s' should have an exclamation mark", get_tok_str(token, NULL));
428 else
429 asm_emit_opcode(token, opcode | ENCODE_RN(ops[0].reg) | ops[1].regset);
430 break;
431 default:
432 expect("block data transfer instruction");
436 /* Parses shift directive and returns the parts that would have to be set in the opcode because of it.
437 Does not encode the actual shift amount.
438 It's not an error if there is no shift directive.
440 NB_SHIFT: will be set to 1 iff SHIFT is filled. Note that for rrx, there's no need to fill SHIFT.
441 SHIFT: will be filled in with the shift operand to use, if any. */
442 static uint32_t asm_parse_optional_shift(TCCState* s1, int* nb_shift, Operand* shift)
444 uint32_t opcode = 0;
445 *nb_shift = 0;
446 switch (tok) {
447 case TOK_ASM_asl:
448 case TOK_ASM_lsl:
449 case TOK_ASM_asr:
450 case TOK_ASM_lsr:
451 case TOK_ASM_ror:
452 switch (tok) {
453 case TOK_ASM_asl:
454 /* fallthrough */
455 case TOK_ASM_lsl:
456 opcode = ENCODE_BARREL_SHIFTER_MODE_LSL;
457 break;
458 case TOK_ASM_asr:
459 opcode = ENCODE_BARREL_SHIFTER_MODE_ASR;
460 break;
461 case TOK_ASM_lsr:
462 opcode = ENCODE_BARREL_SHIFTER_MODE_LSR;
463 break;
464 case TOK_ASM_ror:
465 opcode = ENCODE_BARREL_SHIFTER_MODE_ROR;
466 break;
468 next();
469 parse_operand(s1, shift);
470 *nb_shift = 1;
471 break;
472 case TOK_ASM_rrx:
473 next();
474 opcode = ENCODE_BARREL_SHIFTER_MODE_ROR;
475 break;
477 return opcode;
480 static uint32_t asm_encode_shift(Operand* shift)
482 uint64_t amount;
483 uint32_t operands = 0;
484 switch (shift->type) {
485 case OP_REG32:
486 if (shift->reg == 15)
487 tcc_error("r15 cannot be used as a shift count");
488 else {
489 operands = ENCODE_BARREL_SHIFTER_SHIFT_BY_REGISTER;
490 operands |= ENCODE_BARREL_SHIFTER_REGISTER(shift->reg);
492 break;
493 case OP_IM8:
494 amount = shift->e.v;
495 if (amount > 0 && amount < 32)
496 operands = ENCODE_BARREL_SHIFTER_IMMEDIATE(amount);
497 else
498 tcc_error("shift count out of range");
499 break;
500 default:
501 tcc_error("unknown shift amount");
503 return operands;
506 static void asm_data_processing_opcode(TCCState *s1, int token)
508 Operand ops[3];
509 int nb_ops;
510 Operand shift = {};
511 int nb_shift = 0;
512 uint32_t operands = 0;
514 /* modulo 16 entries per instruction for the different condition codes */
515 uint32_t opcode_idx = (ARM_INSTRUCTION_GROUP(token) - TOK_ASM_andeq) >> 4;
516 uint32_t opcode_nos = opcode_idx >> 1; // without "s"; "OpCode" in ARM docs
518 for (nb_ops = 0; nb_ops < sizeof(ops)/sizeof(ops[0]); ) {
519 if (tok == TOK_ASM_asl || tok == TOK_ASM_lsl || tok == TOK_ASM_lsr || tok == TOK_ASM_asr || tok == TOK_ASM_ror || tok == TOK_ASM_rrx)
520 break;
521 parse_operand(s1, &ops[nb_ops]);
522 ++nb_ops;
523 if (tok != ',')
524 break;
525 next(); // skip ','
527 if (tok == ',')
528 next();
529 operands |= asm_parse_optional_shift(s1, &nb_shift, &shift);
530 if (nb_ops < 2)
531 expect("at least two operands");
532 else if (nb_ops == 2) {
533 memcpy(&ops[2], &ops[1], sizeof(ops[1])); // move ops[2]
534 memcpy(&ops[1], &ops[0], sizeof(ops[0])); // ops[1] was implicit
535 nb_ops = 3;
536 } else if (nb_ops == 3) {
537 if (opcode_nos == 0xd || opcode_nos == 0xf || opcode_nos == 0xa || opcode_nos == 0xb || opcode_nos == 0x8 || opcode_nos == 0x9) { // mov, mvn, cmp, cmn, tst, teq
538 tcc_error("'%s' cannot be used with three operands", get_tok_str(token, NULL));
539 return;
542 if (nb_ops != 3) {
543 expect("two or three operands");
544 return;
545 } else {
546 uint32_t opcode = 0;
547 uint32_t immediate_value;
548 uint8_t half_immediate_rotation;
549 if (nb_shift && shift.type == OP_REG32) {
550 if ((ops[0].type == OP_REG32 && ops[0].reg == 15) ||
551 (ops[1].type == OP_REG32 && ops[1].reg == 15)) {
552 tcc_error("Using the 'pc' register in data processing instructions that have a register-controlled shift is not implemented by ARM");
553 return;
557 // data processing (general case):
558 // operands:
559 // Rn: bits 19...16 (first operand)
560 // Rd: bits 15...12 (destination)
561 // Operand2: bits 11...0 (second operand); depending on I that's either a register or an immediate
562 // operator:
563 // bits 24...21: "OpCode"--see below
565 /* operations in the token list are ordered by opcode */
566 opcode = opcode_nos << 21; // drop "s"
567 if (ops[0].type != OP_REG32)
568 expect("(destination operand) register");
569 else if (opcode_nos == 0xa || opcode_nos == 0xb || opcode_nos == 0x8 || opcode_nos == 0x9) // cmp, cmn, tst, teq
570 operands |= ENCODE_SET_CONDITION_CODES; // force S set, otherwise it's a completely different instruction.
571 else
572 operands |= ENCODE_RD(ops[0].reg);
573 if (ops[1].type != OP_REG32)
574 expect("(first source operand) register");
575 else if (!(opcode_nos == 0xd || opcode_nos == 0xf)) // not: mov, mvn (those have only one source operand)
576 operands |= ENCODE_RN(ops[1].reg);
577 switch (ops[2].type) {
578 case OP_REG32:
579 operands |= ops[2].reg;
580 break;
581 case OP_IM8:
582 case OP_IM32:
583 operands |= ENCODE_IMMEDIATE_FLAG;
584 immediate_value = ops[2].e.v;
585 for (half_immediate_rotation = 0; half_immediate_rotation < 16; ++half_immediate_rotation) {
586 if (immediate_value >= 0x00 && immediate_value < 0x100)
587 break;
588 // rotate left by two
589 immediate_value = ((immediate_value & 0x3FFFFFFF) << 2) | ((immediate_value & 0xC0000000) >> 30);
591 if (half_immediate_rotation >= 16) {
592 /* fallthrough */
593 } else {
594 operands |= immediate_value;
595 operands |= half_immediate_rotation << 8;
596 break;
598 case OP_IM8N: // immediate negative value
599 operands |= ENCODE_IMMEDIATE_FLAG;
600 immediate_value = ops[2].e.v;
601 /* Instruction swapping:
602 0001 = EOR - Rd:= Op1 EOR Op2 -> difficult
603 0011 = RSB - Rd:= Op2 - Op1 -> difficult
604 0111 = RSC - Rd:= Op2 - Op1 + C -> difficult
605 1000 = TST - CC on: Op1 AND Op2 -> difficult
606 1001 = TEQ - CC on: Op1 EOR Op2 -> difficult
607 1100 = ORR - Rd:= Op1 OR Op2 -> difficult
609 switch (opcode_nos) {
610 case 0x0: // AND - Rd:= Op1 AND Op2
611 opcode = 0xe << 21; // BIC
612 immediate_value = ~immediate_value;
613 break;
614 case 0x2: // SUB - Rd:= Op1 - Op2
615 opcode = 0x4 << 21; // ADD
616 immediate_value = -immediate_value;
617 break;
618 case 0x4: // ADD - Rd:= Op1 + Op2
619 opcode = 0x2 << 21; // SUB
620 immediate_value = -immediate_value;
621 break;
622 case 0x5: // ADC - Rd:= Op1 + Op2 + C
623 opcode = 0x6 << 21; // SBC
624 immediate_value = ~immediate_value;
625 break;
626 case 0x6: // SBC - Rd:= Op1 - Op2 + C
627 opcode = 0x5 << 21; // ADC
628 immediate_value = ~immediate_value;
629 break;
630 case 0xa: // CMP - CC on: Op1 - Op2
631 opcode = 0xb << 21; // CMN
632 immediate_value = -immediate_value;
633 break;
634 case 0xb: // CMN - CC on: Op1 + Op2
635 opcode = 0xa << 21; // CMP
636 immediate_value = -immediate_value;
637 break;
638 case 0xd: // MOV - Rd:= Op2
639 opcode = 0xf << 21; // MVN
640 immediate_value = ~immediate_value;
641 break;
642 case 0xe: // BIC - Rd:= Op1 AND NOT Op2
643 opcode = 0x0 << 21; // AND
644 immediate_value = ~immediate_value;
645 break;
646 case 0xf: // MVN - Rd:= NOT Op2
647 opcode = 0xd << 21; // MOV
648 immediate_value = ~immediate_value;
649 break;
650 default:
651 tcc_error("cannot use '%s' with a negative immediate value", get_tok_str(token, NULL));
653 for (half_immediate_rotation = 0; half_immediate_rotation < 16; ++half_immediate_rotation) {
654 if (immediate_value >= 0x00 && immediate_value < 0x100)
655 break;
656 // rotate left by two
657 immediate_value = ((immediate_value & 0x3FFFFFFF) << 2) | ((immediate_value & 0xC0000000) >> 30);
659 if (half_immediate_rotation >= 16) {
660 immediate_value = ops[2].e.v;
661 tcc_error("immediate value 0x%X cannot be encoded into ARM immediate", (unsigned) immediate_value);
662 return;
664 operands |= immediate_value;
665 operands |= half_immediate_rotation << 8;
666 break;
667 default:
668 expect("(second source operand) register or immediate value");
671 if (nb_shift) {
672 if (operands & ENCODE_IMMEDIATE_FLAG)
673 tcc_error("immediate rotation not implemented");
674 else
675 operands |= asm_encode_shift(&shift);
678 /* S=0 and S=1 entries alternate one after another, in that order */
679 opcode |= (opcode_idx & 1) ? ENCODE_SET_CONDITION_CODES : 0;
680 asm_emit_opcode(token, opcode | operands);
684 static void asm_shift_opcode(TCCState *s1, int token)
686 Operand ops[3];
687 int nb_ops;
688 int definitely_neutral = 0;
689 uint32_t opcode = 0xd << 21; // MOV
690 uint32_t operands = 0;
692 for (nb_ops = 0; nb_ops < sizeof(ops)/sizeof(ops[0]); ++nb_ops) {
693 parse_operand(s1, &ops[nb_ops]);
694 if (tok != ',') {
695 ++nb_ops;
696 break;
698 next(); // skip ','
700 if (nb_ops < 2) {
701 expect("at least two operands");
702 return;
705 if (ops[0].type != OP_REG32) {
706 expect("(destination operand) register");
707 return;
708 } else
709 operands |= ENCODE_RD(ops[0].reg);
711 if (nb_ops == 2) {
712 switch (ARM_INSTRUCTION_GROUP(token)) {
713 case TOK_ASM_rrxseq:
714 opcode |= ENCODE_SET_CONDITION_CODES;
715 /* fallthrough */
716 case TOK_ASM_rrxeq:
717 if (ops[1].type == OP_REG32) {
718 operands |= ops[1].reg;
719 operands |= ENCODE_BARREL_SHIFTER_MODE_ROR;
720 asm_emit_opcode(token, opcode | operands);
721 } else
722 tcc_error("(first source operand) register");
723 return;
724 default:
725 memcpy(&ops[2], &ops[1], sizeof(ops[1])); // move ops[2]
726 memcpy(&ops[1], &ops[0], sizeof(ops[0])); // ops[1] was implicit
727 nb_ops = 3;
730 if (nb_ops != 3) {
731 expect("two or three operands");
732 return;
735 switch (ARM_INSTRUCTION_GROUP(token)) {
736 case TOK_ASM_lslseq:
737 case TOK_ASM_lsrseq:
738 case TOK_ASM_asrseq:
739 case TOK_ASM_rorseq:
740 opcode |= ENCODE_SET_CONDITION_CODES;
741 break;
744 switch (ops[1].type) {
745 case OP_REG32:
746 operands |= ops[1].reg;
747 break;
748 case OP_IM8:
749 operands |= ENCODE_IMMEDIATE_FLAG;
750 operands |= ops[1].e.v;
751 break;
754 switch (ops[2].type) {
755 case OP_REG32:
756 if ((ops[0].type == OP_REG32 && ops[0].reg == 15) ||
757 (ops[1].type == OP_REG32 && ops[1].reg == 15)) {
758 tcc_error("Using the 'pc' register in data processing instructions that have a register-controlled shift is not implemented by ARM");
760 operands |= asm_encode_shift(&ops[2]);
761 break;
762 case OP_IM8:
763 if (ops[2].e.v)
764 operands |= asm_encode_shift(&ops[2]);
765 else
766 definitely_neutral = 1;
767 break;
770 if (!definitely_neutral) switch (ARM_INSTRUCTION_GROUP(token)) {
771 case TOK_ASM_lslseq:
772 case TOK_ASM_lsleq:
773 operands |= ENCODE_BARREL_SHIFTER_MODE_LSL;
774 break;
775 case TOK_ASM_lsrseq:
776 case TOK_ASM_lsreq:
777 operands |= ENCODE_BARREL_SHIFTER_MODE_LSR;
778 break;
779 case TOK_ASM_asrseq:
780 case TOK_ASM_asreq:
781 operands |= ENCODE_BARREL_SHIFTER_MODE_ASR;
782 break;
783 case TOK_ASM_rorseq:
784 case TOK_ASM_roreq:
785 operands |= ENCODE_BARREL_SHIFTER_MODE_ROR;
786 break;
787 default:
788 expect("shift instruction");
789 return;
791 asm_emit_opcode(token, opcode | operands);
794 static void asm_multiplication_opcode(TCCState *s1, int token)
796 Operand ops[4];
797 int nb_ops = 0;
798 uint32_t opcode = 0x90;
800 for (nb_ops = 0; nb_ops < sizeof(ops)/sizeof(ops[0]); ++nb_ops) {
801 parse_operand(s1, &ops[nb_ops]);
802 if (tok != ',') {
803 ++nb_ops;
804 break;
806 next(); // skip ','
808 if (nb_ops < 2)
809 expect("at least two operands");
810 else if (nb_ops == 2) {
811 switch (ARM_INSTRUCTION_GROUP(token)) {
812 case TOK_ASM_mulseq:
813 case TOK_ASM_muleq:
814 memcpy(&ops[2], &ops[0], sizeof(ops[1])); // ARM is actually like this!
815 break;
816 default:
817 expect("at least three operands");
818 return;
820 nb_ops = 3;
823 // multiply (special case):
824 // operands:
825 // Rd: bits 19...16
826 // Rm: bits 3...0
827 // Rs: bits 11...8
828 // Rn: bits 15...12
830 if (ops[0].type == OP_REG32)
831 opcode |= ops[0].reg << 16;
832 else
833 expect("(destination operand) register");
834 if (ops[1].type == OP_REG32)
835 opcode |= ops[1].reg;
836 else
837 expect("(first source operand) register");
838 if (ops[2].type == OP_REG32)
839 opcode |= ops[2].reg << 8;
840 else
841 expect("(second source operand) register");
842 if (nb_ops > 3) {
843 if (ops[3].type == OP_REG32)
844 opcode |= ops[3].reg << 12;
845 else
846 expect("(third source operand) register");
849 switch (ARM_INSTRUCTION_GROUP(token)) {
850 case TOK_ASM_mulseq:
851 opcode |= 1 << 20; // Status
852 /* fallthrough */
853 case TOK_ASM_muleq:
854 if (nb_ops != 3)
855 expect("three operands");
856 else {
857 asm_emit_opcode(token, opcode);
859 break;
860 case TOK_ASM_mlaseq:
861 opcode |= 1 << 20; // Status
862 /* fallthrough */
863 case TOK_ASM_mlaeq:
864 if (nb_ops != 4)
865 expect("four operands");
866 else {
867 opcode |= 1 << 21; // Accumulate
868 asm_emit_opcode(token, opcode);
870 break;
871 default:
872 expect("known multiplication instruction");
876 static void asm_long_multiplication_opcode(TCCState *s1, int token)
878 Operand ops[4];
879 int nb_ops = 0;
880 uint32_t opcode = 0x90 | (1 << 23);
882 for (nb_ops = 0; nb_ops < sizeof(ops)/sizeof(ops[0]); ++nb_ops) {
883 parse_operand(s1, &ops[nb_ops]);
884 if (tok != ',') {
885 ++nb_ops;
886 break;
888 next(); // skip ','
890 if (nb_ops != 4) {
891 expect("four operands");
892 return;
895 // long multiply (special case):
896 // operands:
897 // RdLo: bits 15...12
898 // RdHi: bits 19...16
899 // Rs: bits 11...8
900 // Rm: bits 3...0
902 if (ops[0].type == OP_REG32)
903 opcode |= ops[0].reg << 12;
904 else
905 expect("(destination lo accumulator) register");
906 if (ops[1].type == OP_REG32)
907 opcode |= ops[1].reg << 16;
908 else
909 expect("(destination hi accumulator) register");
910 if (ops[2].type == OP_REG32)
911 opcode |= ops[2].reg;
912 else
913 expect("(first source operand) register");
914 if (ops[3].type == OP_REG32)
915 opcode |= ops[3].reg << 8;
916 else
917 expect("(second source operand) register");
919 switch (ARM_INSTRUCTION_GROUP(token)) {
920 case TOK_ASM_smullseq:
921 opcode |= 1 << 20; // Status
922 /* fallthrough */
923 case TOK_ASM_smulleq:
924 opcode |= 1 << 22; // signed
925 asm_emit_opcode(token, opcode);
926 break;
927 case TOK_ASM_umullseq:
928 opcode |= 1 << 20; // Status
929 /* fallthrough */
930 case TOK_ASM_umulleq:
931 asm_emit_opcode(token, opcode);
932 break;
933 case TOK_ASM_smlalseq:
934 opcode |= 1 << 20; // Status
935 /* fallthrough */
936 case TOK_ASM_smlaleq:
937 opcode |= 1 << 22; // signed
938 opcode |= 1 << 21; // Accumulate
939 asm_emit_opcode(token, opcode);
940 break;
941 case TOK_ASM_umlalseq:
942 opcode |= 1 << 20; // Status
943 /* fallthrough */
944 case TOK_ASM_umlaleq:
945 opcode |= 1 << 21; // Accumulate
946 asm_emit_opcode(token, opcode);
947 break;
948 default:
949 expect("known long multiplication instruction");
953 static void asm_single_data_transfer_opcode(TCCState *s1, int token)
955 Operand ops[3];
956 Operand strex_operand;
957 Operand shift;
958 int nb_shift = 0;
959 int exclam = 0;
960 int closed_bracket = 0;
961 int op2_minus = 0;
962 uint32_t opcode = 0;
963 // Note: ldr r0, [r4, #4] ; simple offset: r0 = *(int*)(r4+4); r4 unchanged
964 // Note: ldr r0, [r4, #4]! ; pre-indexed: r0 = *(int*)(r4+4); r4 = r4+4
965 // Note: ldr r0, [r4], #4 ; post-indexed: r0 = *(int*)(r4+0); r4 = r4+4
967 parse_operand(s1, &ops[0]);
968 if (ops[0].type == OP_REG32)
969 opcode |= ENCODE_RD(ops[0].reg);
970 else {
971 expect("(destination operand) register");
972 return;
974 if (tok != ',')
975 expect("at least two arguments");
976 else
977 next(); // skip ','
979 switch (ARM_INSTRUCTION_GROUP(token)) {
980 case TOK_ASM_strexbeq:
981 case TOK_ASM_strexeq:
982 parse_operand(s1, &strex_operand);
983 if (strex_operand.type != OP_REG32) {
984 expect("register");
985 return;
987 if (tok != ',')
988 expect("at least three arguments");
989 else
990 next(); // skip ','
991 break;
994 if (tok != '[')
995 expect("'['");
996 else
997 next(); // skip '['
999 parse_operand(s1, &ops[1]);
1000 if (ops[1].type == OP_REG32)
1001 opcode |= ENCODE_RN(ops[1].reg);
1002 else {
1003 expect("(first source operand) register");
1004 return;
1006 if (tok == ']') {
1007 next();
1008 closed_bracket = 1;
1009 // exclam = 1; // implicit in hardware; don't do it in software
1011 if (tok == ',') {
1012 next(); // skip ','
1013 if (tok == '-') {
1014 op2_minus = 1;
1015 next();
1017 parse_operand(s1, &ops[2]);
1018 if (ops[2].type == OP_REG32) {
1019 if (ops[2].reg == 15) {
1020 tcc_error("Using 'pc' for register offset in '%s' is not implemented by ARM", get_tok_str(token, NULL));
1021 return;
1023 if (tok == ',') {
1024 next();
1025 opcode |= asm_parse_optional_shift(s1, &nb_shift, &shift);
1026 if (opcode == 0)
1027 expect("shift directive, or no comma");
1030 } else {
1031 // end of input expression in brackets--assume 0 offset
1032 ops[2].type = OP_IM8;
1033 ops[2].e.v = 0;
1034 opcode |= 1 << 24; // add offset before transfer
1036 if (!closed_bracket) {
1037 if (tok != ']')
1038 expect("']'");
1039 else
1040 next(); // skip ']'
1041 opcode |= 1 << 24; // add offset before transfer
1042 if (tok == '!') {
1043 exclam = 1;
1044 next(); // skip '!'
1048 // single data transfer: 0 1 I P U B W L << 20 (general case):
1049 // operands:
1050 // Rd: destination operand [ok]
1051 // Rn: first source operand [ok]
1052 // Operand2: bits 11...0 [ok]
1053 // I: immediate operand? [ok]
1054 // P: Pre/post indexing is PRE: Add offset before transfer [ok]
1055 // U: Up/down is up? (*adds* offset to base) [ok]
1056 // B: Byte/word is byte? TODO
1057 // W: Write address back into base? [ok]
1058 // L: Load/store is load? [ok]
1059 if (exclam)
1060 opcode |= 1 << 21; // write offset back into register
1062 if (ops[2].type == OP_IM32 || ops[2].type == OP_IM8 || ops[2].type == OP_IM8N) {
1063 int v = ops[2].e.v;
1064 if (op2_minus)
1065 tcc_error("minus before '#' not supported for immediate values");
1066 if (v >= 0) {
1067 opcode |= 1 << 23; // up
1068 if (v >= 0x1000)
1069 tcc_error("offset out of range for '%s'", get_tok_str(token, NULL));
1070 else
1071 opcode |= v;
1072 } else { // down
1073 if (v <= -0x1000)
1074 tcc_error("offset out of range for '%s'", get_tok_str(token, NULL));
1075 else
1076 opcode |= -v;
1078 } else if (ops[2].type == OP_REG32) {
1079 if (!op2_minus)
1080 opcode |= 1 << 23; // up
1081 opcode |= ENCODE_IMMEDIATE_FLAG; /* if set, it means it's NOT immediate */
1082 opcode |= ops[2].reg;
1083 } else
1084 expect("register");
1086 switch (ARM_INSTRUCTION_GROUP(token)) {
1087 case TOK_ASM_strbeq:
1088 opcode |= 1 << 22; // B
1089 /* fallthrough */
1090 case TOK_ASM_streq:
1091 opcode |= 1 << 26; // Load/Store
1092 if (nb_shift)
1093 opcode |= asm_encode_shift(&shift);
1094 asm_emit_opcode(token, opcode);
1095 break;
1096 case TOK_ASM_ldrbeq:
1097 opcode |= 1 << 22; // B
1098 /* fallthrough */
1099 case TOK_ASM_ldreq:
1100 opcode |= 1 << 20; // L
1101 opcode |= 1 << 26; // Load/Store
1102 if (nb_shift)
1103 opcode |= asm_encode_shift(&shift);
1104 asm_emit_opcode(token, opcode);
1105 break;
1106 case TOK_ASM_strexbeq:
1107 opcode |= 1 << 22; // B
1108 /* fallthrough */
1109 case TOK_ASM_strexeq:
1110 if ((opcode & 0xFFF) || nb_shift) {
1111 tcc_error("neither offset nor shift allowed with 'strex'");
1112 return;
1113 } else if (opcode & ENCODE_IMMEDIATE_FLAG) { // if set, it means it's NOT immediate
1114 tcc_error("offset not allowed with 'strex'");
1115 return;
1117 if ((opcode & (1 << 24)) == 0) { // add offset after transfer
1118 tcc_error("adding offset after transfer not allowed with 'strex'");
1119 return;
1122 opcode |= 0xf90; // Used to mean: barrel shifter is enabled, barrel shift register is r15, mode is LSL
1123 opcode |= strex_operand.reg;
1124 asm_emit_opcode(token, opcode);
1125 break;
1126 case TOK_ASM_ldrexbeq:
1127 opcode |= 1 << 22; // B
1128 /* fallthrough */
1129 case TOK_ASM_ldrexeq:
1130 if ((opcode & 0xFFF) || nb_shift) {
1131 tcc_error("neither offset nor shift allowed with 'ldrex'");
1132 return;
1133 } else if (opcode & ENCODE_IMMEDIATE_FLAG) { // if set, it means it's NOT immediate
1134 tcc_error("offset not allowed with 'ldrex'");
1135 return;
1137 if ((opcode & (1 << 24)) == 0) { // add offset after transfer
1138 tcc_error("adding offset after transfer not allowed with 'ldrex'");
1139 return;
1141 opcode |= 1 << 20; // L
1142 opcode |= 0x00f;
1143 opcode |= 0xf90; // Used to mean: barrel shifter is enabled, barrel shift register is r15, mode is LSL
1144 asm_emit_opcode(token, opcode);
1145 break;
1146 default:
1147 expect("data transfer instruction");
1151 static void asm_misc_single_data_transfer_opcode(TCCState *s1, int token)
1153 Operand ops[3];
1154 int exclam = 0;
1155 int closed_bracket = 0;
1156 int op2_minus = 0;
1157 uint32_t opcode = (1 << 7) | (1 << 4);
1159 /* Note:
1160 The argument syntax is exactly the same as in arm_single_data_transfer_opcode, except that there's no STREX argument form.
1161 The main difference between this function and asm_misc_single_data_transfer_opcode is that the immediate values here must be smaller.
1162 Also, the combination (P=0, W=1) is unpredictable here.
1163 The immediate flag has moved to bit index 22--and its meaning has flipped.
1164 The immediate value itself has been split into two parts: one at bits 11...8, one at bits 3...0
1165 bit 26 (Load/Store instruction) is unset here.
1166 bits 7 and 4 are set here. */
1168 // Here: 0 0 0 P U I W L << 20
1169 // [compare single data transfer: 0 1 I P U B W L << 20]
1171 parse_operand(s1, &ops[0]);
1172 if (ops[0].type == OP_REG32)
1173 opcode |= ENCODE_RD(ops[0].reg);
1174 else {
1175 expect("(destination operand) register");
1176 return;
1178 if (tok != ',')
1179 expect("at least two arguments");
1180 else
1181 next(); // skip ','
1183 if (tok != '[')
1184 expect("'['");
1185 else
1186 next(); // skip '['
1188 parse_operand(s1, &ops[1]);
1189 if (ops[1].type == OP_REG32)
1190 opcode |= ENCODE_RN(ops[1].reg);
1191 else {
1192 expect("(first source operand) register");
1193 return;
1195 if (tok == ']') {
1196 next();
1197 closed_bracket = 1;
1198 // exclam = 1; // implicit in hardware; don't do it in software
1200 if (tok == ',') {
1201 next(); // skip ','
1202 if (tok == '-') {
1203 op2_minus = 1;
1204 next();
1206 parse_operand(s1, &ops[2]);
1207 } else {
1208 // end of input expression in brackets--assume 0 offset
1209 ops[2].type = OP_IM8;
1210 ops[2].e.v = 0;
1211 opcode |= 1 << 24; // add offset before transfer
1213 if (!closed_bracket) {
1214 if (tok != ']')
1215 expect("']'");
1216 else
1217 next(); // skip ']'
1218 opcode |= 1 << 24; // add offset before transfer
1219 if (tok == '!') {
1220 exclam = 1;
1221 next(); // skip '!'
1225 if (exclam) {
1226 if ((opcode & (1 << 24)) == 0) {
1227 tcc_error("result of '%s' would be unpredictable here", get_tok_str(token, NULL));
1228 return;
1230 opcode |= 1 << 21; // write offset back into register
1233 if (ops[2].type == OP_IM32 || ops[2].type == OP_IM8 || ops[2].type == OP_IM8N) {
1234 int v = ops[2].e.v;
1235 if (op2_minus)
1236 tcc_error("minus before '#' not supported for immediate values");
1237 if (v >= 0) {
1238 opcode |= 1 << 23; // up
1239 if (v >= 0x100)
1240 tcc_error("offset out of range for '%s'", get_tok_str(token, NULL));
1241 else {
1242 // bits 11...8: immediate hi nibble
1243 // bits 3...0: immediate lo nibble
1244 opcode |= (v & 0xF0) << 4;
1245 opcode |= v & 0xF;
1247 } else { // down
1248 if (v <= -0x100)
1249 tcc_error("offset out of range for '%s'", get_tok_str(token, NULL));
1250 else {
1251 v = -v;
1252 // bits 11...8: immediate hi nibble
1253 // bits 3...0: immediate lo nibble
1254 opcode |= (v & 0xF0) << 4;
1255 opcode |= v & 0xF;
1258 opcode |= 1 << 22; // not ENCODE_IMMEDIATE_FLAG;
1259 } else if (ops[2].type == OP_REG32) {
1260 if (!op2_minus)
1261 opcode |= 1 << 23; // up
1262 opcode |= ops[2].reg;
1263 } else
1264 expect("register");
1266 switch (ARM_INSTRUCTION_GROUP(token)) {
1267 case TOK_ASM_ldrsheq:
1268 opcode |= 1 << 5; // halfword, not byte
1269 /* fallthrough */
1270 case TOK_ASM_ldrsbeq:
1271 opcode |= 1 << 6; // sign extend
1272 opcode |= 1 << 20; // L
1273 asm_emit_opcode(token, opcode);
1274 break;
1275 case TOK_ASM_ldrheq:
1276 opcode |= 1 << 5; // halfword, not byte
1277 opcode |= 1 << 20; // L
1278 asm_emit_opcode(token, opcode);
1279 break;
1280 case TOK_ASM_strheq:
1281 opcode |= 1 << 5; // halfword, not byte
1282 asm_emit_opcode(token, opcode);
1283 break;
1287 /* Note: almost dupe of encbranch in arm-gen.c */
1288 static uint32_t encbranchoffset(int pos, int addr, int fail)
1290 addr-=pos+8;
1291 addr/=4;
1292 if(addr>=0x7fffff || addr<-0x800000) {
1293 if(fail)
1294 tcc_error("branch offset is too far");
1295 return 0;
1297 return /*not 0x0A000000|*/(addr&0xffffff);
1300 static void asm_branch_opcode(TCCState *s1, int token)
1302 int jmp_disp = 0;
1303 Operand op;
1304 ExprValue e;
1305 ElfSym *esym;
1307 switch (ARM_INSTRUCTION_GROUP(token)) {
1308 case TOK_ASM_beq:
1309 case TOK_ASM_bleq:
1310 asm_expr(s1, &e);
1311 esym = elfsym(e.sym);
1312 if (!esym || esym->st_shndx != cur_text_section->sh_num) {
1313 tcc_error("invalid branch target");
1314 return;
1316 jmp_disp = encbranchoffset(ind, e.v + esym->st_value, 1);
1317 break;
1318 default:
1319 parse_operand(s1, &op);
1320 break;
1322 switch (ARM_INSTRUCTION_GROUP(token)) {
1323 case TOK_ASM_beq:
1324 asm_emit_opcode(token, (0xa << 24) | (jmp_disp & 0xffffff));
1325 break;
1326 case TOK_ASM_bleq:
1327 asm_emit_opcode(token, (0xb << 24) | (jmp_disp & 0xffffff));
1328 break;
1329 case TOK_ASM_bxeq:
1330 if (op.type != OP_REG32)
1331 expect("register");
1332 else
1333 asm_emit_opcode(token, (0x12fff1 << 4) | op.reg);
1334 break;
1335 case TOK_ASM_blxeq:
1336 if (op.type != OP_REG32)
1337 expect("register");
1338 else
1339 asm_emit_opcode(token, (0x12fff3 << 4) | op.reg);
1340 break;
1341 default:
1342 expect("branch instruction");
1346 ST_FUNC void asm_opcode(TCCState *s1, int token)
1348 while (token == TOK_LINEFEED) {
1349 next();
1350 token = tok;
1352 if (token == TOK_EOF)
1353 return;
1354 if (token < TOK_ASM_nopeq) {
1355 expect("instruction");
1356 return;
1359 switch (ARM_INSTRUCTION_GROUP(token)) {
1360 case TOK_ASM_pusheq:
1361 case TOK_ASM_popeq:
1362 case TOK_ASM_stmdaeq:
1363 case TOK_ASM_ldmdaeq:
1364 case TOK_ASM_stmeq:
1365 case TOK_ASM_ldmeq:
1366 case TOK_ASM_stmiaeq:
1367 case TOK_ASM_ldmiaeq:
1368 case TOK_ASM_stmdbeq:
1369 case TOK_ASM_ldmdbeq:
1370 case TOK_ASM_stmibeq:
1371 case TOK_ASM_ldmibeq:
1372 return asm_block_data_transfer_opcode(s1, token);
1373 case TOK_ASM_nopeq:
1374 case TOK_ASM_wfeeq:
1375 case TOK_ASM_wfieq:
1376 return asm_nullary_opcode(token);
1377 case TOK_ASM_swieq:
1378 return asm_unary_opcode(s1, token);
1379 case TOK_ASM_beq:
1380 case TOK_ASM_bleq:
1381 case TOK_ASM_bxeq:
1382 case TOK_ASM_blxeq:
1383 return asm_branch_opcode(s1, token);
1384 case TOK_ASM_clzeq:
1385 case TOK_ASM_sxtbeq:
1386 case TOK_ASM_sxtheq:
1387 case TOK_ASM_uxtbeq:
1388 case TOK_ASM_uxtheq:
1389 case TOK_ASM_movteq:
1390 case TOK_ASM_movweq:
1391 return asm_binary_opcode(s1, token);
1393 case TOK_ASM_ldreq:
1394 case TOK_ASM_ldrbeq:
1395 case TOK_ASM_streq:
1396 case TOK_ASM_strbeq:
1397 case TOK_ASM_ldrexeq:
1398 case TOK_ASM_ldrexbeq:
1399 case TOK_ASM_strexeq:
1400 case TOK_ASM_strexbeq:
1401 return asm_single_data_transfer_opcode(s1, token);
1403 case TOK_ASM_ldrheq:
1404 case TOK_ASM_ldrsheq:
1405 case TOK_ASM_ldrsbeq:
1406 case TOK_ASM_strheq:
1407 return asm_misc_single_data_transfer_opcode(s1, token);
1409 case TOK_ASM_andeq:
1410 case TOK_ASM_eoreq:
1411 case TOK_ASM_subeq:
1412 case TOK_ASM_rsbeq:
1413 case TOK_ASM_addeq:
1414 case TOK_ASM_adceq:
1415 case TOK_ASM_sbceq:
1416 case TOK_ASM_rsceq:
1417 case TOK_ASM_tsteq:
1418 case TOK_ASM_teqeq:
1419 case TOK_ASM_cmpeq:
1420 case TOK_ASM_cmneq:
1421 case TOK_ASM_orreq:
1422 case TOK_ASM_moveq:
1423 case TOK_ASM_biceq:
1424 case TOK_ASM_mvneq:
1425 case TOK_ASM_andseq:
1426 case TOK_ASM_eorseq:
1427 case TOK_ASM_subseq:
1428 case TOK_ASM_rsbseq:
1429 case TOK_ASM_addseq:
1430 case TOK_ASM_adcseq:
1431 case TOK_ASM_sbcseq:
1432 case TOK_ASM_rscseq:
1433 // case TOK_ASM_tstseq:
1434 // case TOK_ASM_teqseq:
1435 // case TOK_ASM_cmpseq:
1436 // case TOK_ASM_cmnseq:
1437 case TOK_ASM_orrseq:
1438 case TOK_ASM_movseq:
1439 case TOK_ASM_bicseq:
1440 case TOK_ASM_mvnseq:
1441 return asm_data_processing_opcode(s1, token);
1443 case TOK_ASM_lsleq:
1444 case TOK_ASM_lslseq:
1445 case TOK_ASM_lsreq:
1446 case TOK_ASM_lsrseq:
1447 case TOK_ASM_asreq:
1448 case TOK_ASM_asrseq:
1449 case TOK_ASM_roreq:
1450 case TOK_ASM_rorseq:
1451 case TOK_ASM_rrxseq:
1452 case TOK_ASM_rrxeq:
1453 return asm_shift_opcode(s1, token);
1455 case TOK_ASM_muleq:
1456 case TOK_ASM_mulseq:
1457 case TOK_ASM_mlaeq:
1458 case TOK_ASM_mlaseq:
1459 return asm_multiplication_opcode(s1, token);
1461 case TOK_ASM_smulleq:
1462 case TOK_ASM_smullseq:
1463 case TOK_ASM_umulleq:
1464 case TOK_ASM_umullseq:
1465 case TOK_ASM_smlaleq:
1466 case TOK_ASM_smlalseq:
1467 case TOK_ASM_umlaleq:
1468 case TOK_ASM_umlalseq:
1469 return asm_long_multiplication_opcode(s1, token);
1470 default:
1471 expect("known instruction");
1475 ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier)
1477 int r, reg, size, val;
1478 char buf[64];
1480 r = sv->r;
1481 if ((r & VT_VALMASK) == VT_CONST) {
1482 if (!(r & VT_LVAL) && modifier != 'c' && modifier != 'n' &&
1483 modifier != 'P')
1484 cstr_ccat(add_str, '#');
1485 if (r & VT_SYM) {
1486 const char *name = get_tok_str(sv->sym->v, NULL);
1487 if (sv->sym->v >= SYM_FIRST_ANOM) {
1488 /* In case of anonymous symbols ("L.42", used
1489 for static data labels) we can't find them
1490 in the C symbol table when later looking up
1491 this name. So enter them now into the asm label
1492 list when we still know the symbol. */
1493 get_asm_sym(tok_alloc(name, strlen(name))->tok, sv->sym);
1495 if (tcc_state->leading_underscore)
1496 cstr_ccat(add_str, '_');
1497 cstr_cat(add_str, name, -1);
1498 if ((uint32_t) sv->c.i == 0)
1499 goto no_offset;
1500 cstr_ccat(add_str, '+');
1502 val = sv->c.i;
1503 if (modifier == 'n')
1504 val = -val;
1505 snprintf(buf, sizeof(buf), "%d", (int) sv->c.i);
1506 cstr_cat(add_str, buf, -1);
1507 no_offset:;
1508 } else if ((r & VT_VALMASK) == VT_LOCAL) {
1509 snprintf(buf, sizeof(buf), "[fp,#%d]", (int) sv->c.i);
1510 cstr_cat(add_str, buf, -1);
1511 } else if (r & VT_LVAL) {
1512 reg = r & VT_VALMASK;
1513 if (reg >= VT_CONST)
1514 tcc_internal_error("");
1515 snprintf(buf, sizeof(buf), "[%s]",
1516 get_tok_str(TOK_ASM_r0 + reg, NULL));
1517 cstr_cat(add_str, buf, -1);
1518 } else {
1519 /* register case */
1520 reg = r & VT_VALMASK;
1521 if (reg >= VT_CONST)
1522 tcc_internal_error("");
1524 /* choose register operand size */
1525 if ((sv->type.t & VT_BTYPE) == VT_BYTE ||
1526 (sv->type.t & VT_BTYPE) == VT_BOOL)
1527 size = 1;
1528 else if ((sv->type.t & VT_BTYPE) == VT_SHORT)
1529 size = 2;
1530 else
1531 size = 4;
1533 if (modifier == 'b') {
1534 size = 1;
1535 } else if (modifier == 'w') {
1536 size = 2;
1537 } else if (modifier == 'k') {
1538 size = 4;
1541 switch (size) {
1542 default:
1543 reg = TOK_ASM_r0 + reg;
1544 break;
1546 snprintf(buf, sizeof(buf), "%s", get_tok_str(reg, NULL));
1547 cstr_cat(add_str, buf, -1);
1551 /* generate prolog and epilog code for asm statement */
1552 ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands,
1553 int nb_outputs, int is_output,
1554 uint8_t *clobber_regs,
1555 int out_reg)
1557 uint8_t regs_allocated[NB_ASM_REGS];
1558 ASMOperand *op;
1559 int i, reg;
1560 uint32_t saved_regset = 0;
1562 // TODO: Check non-E ABI.
1563 // Note: Technically, r13 (sp) is also callee-saved--but that does not matter yet
1564 static uint8_t reg_saved[] = { 4, 5, 6, 7, 8, 9 /* Note: sometimes special reg "sb" */ , 10, 11 };
1566 /* mark all used registers */
1567 memcpy(regs_allocated, clobber_regs, sizeof(regs_allocated));
1568 for(i = 0; i < nb_operands;i++) {
1569 op = &operands[i];
1570 if (op->reg >= 0)
1571 regs_allocated[op->reg] = 1;
1573 for(i = 0; i < sizeof(reg_saved)/sizeof(reg_saved[0]); i++) {
1574 reg = reg_saved[i];
1575 if (regs_allocated[reg])
1576 saved_regset |= 1 << reg;
1579 if (!is_output) { // prolog
1580 /* generate reg save code */
1581 if (saved_regset)
1582 gen_le32(0xe92d0000 | saved_regset); // push {...}
1584 /* generate load code */
1585 for(i = 0; i < nb_operands; i++) {
1586 op = &operands[i];
1587 if (op->reg >= 0) {
1588 if ((op->vt->r & VT_VALMASK) == VT_LLOCAL &&
1589 op->is_memory) {
1590 /* memory reference case (for both input and
1591 output cases) */
1592 SValue sv;
1593 sv = *op->vt;
1594 sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL | VT_LVAL;
1595 sv.type.t = VT_PTR;
1596 load(op->reg, &sv);
1597 } else if (i >= nb_outputs || op->is_rw) { // not write-only
1598 /* load value in register */
1599 load(op->reg, op->vt);
1600 if (op->is_llong)
1601 tcc_error("long long not implemented");
1605 } else { // epilog
1606 /* generate save code */
1607 for(i = 0 ; i < nb_outputs; i++) {
1608 op = &operands[i];
1609 if (op->reg >= 0) {
1610 if ((op->vt->r & VT_VALMASK) == VT_LLOCAL) {
1611 if (!op->is_memory) {
1612 SValue sv;
1613 sv = *op->vt;
1614 sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL;
1615 sv.type.t = VT_PTR;
1616 load(out_reg, &sv);
1618 sv = *op->vt;
1619 sv.r = (sv.r & ~VT_VALMASK) | out_reg;
1620 store(op->reg, &sv);
1622 } else {
1623 store(op->reg, op->vt);
1624 if (op->is_llong)
1625 tcc_error("long long not implemented");
1630 /* generate reg restore code */
1631 if (saved_regset)
1632 gen_le32(0xe8bd0000 | saved_regset); // pop {...}
1636 /* return the constraint priority (we allocate first the lowest
1637 numbered constraints) */
1638 static inline int constraint_priority(const char *str)
1640 int priority, c, pr;
1642 /* we take the lowest priority */
1643 priority = 0;
1644 for(;;) {
1645 c = *str;
1646 if (c == '\0')
1647 break;
1648 str++;
1649 switch(c) {
1650 case 'l': // in ARM mode, that's an alias for 'r' [ARM].
1651 case 'r': // register [general]
1652 case 'p': // valid memory address for load,store [general]
1653 pr = 3;
1654 break;
1655 case 'M': // integer constant for shifts [ARM]
1656 case 'I': // integer valid for data processing instruction immediate
1657 case 'J': // integer in range -4095...4095
1659 case 'i': // immediate integer operand, including symbolic constants [general]
1660 case 'm': // memory operand [general]
1661 case 'g': // general-purpose-register, memory, immediate integer [general]
1662 pr = 4;
1663 break;
1664 default:
1665 tcc_error("unknown constraint '%c'", c);
1666 pr = 0;
1668 if (pr > priority)
1669 priority = pr;
1671 return priority;
1674 static const char *skip_constraint_modifiers(const char *p)
1676 /* Constraint modifier:
1677 = Operand is written to by this instruction
1678 + Operand is both read and written to by this instruction
1679 % Instruction is commutative for this operand and the following operand.
1681 Per-alternative constraint modifier:
1682 & Operand is clobbered before the instruction is done using the input operands
1684 while (*p == '=' || *p == '&' || *p == '+' || *p == '%')
1685 p++;
1686 return p;
1689 #define REG_OUT_MASK 0x01
1690 #define REG_IN_MASK 0x02
1692 #define is_reg_allocated(reg) (regs_allocated[reg] & reg_mask)
1694 ST_FUNC void asm_compute_constraints(ASMOperand *operands,
1695 int nb_operands, int nb_outputs,
1696 const uint8_t *clobber_regs,
1697 int *pout_reg)
1699 /* overall format: modifier, then ,-seperated list of alternatives; all operands for a single instruction must have the same number of alternatives */
1700 /* TODO: Simple constraints
1701 whitespace ignored
1702 o memory operand that is offsetable
1703 V memory but not offsetable
1704 < memory operand with autodecrement addressing is allowed. Restrictions apply.
1705 > memory operand with autoincrement addressing is allowed. Restrictions apply.
1706 n immediate integer operand with a known numeric value
1707 E immediate floating operand (const_double) is allowed, but only if target=host
1708 F immediate floating operand (const_double or const_vector) is allowed
1709 s immediate integer operand whose value is not an explicit integer
1710 X any operand whatsoever
1711 0...9 (postfix); (can also be more than 1 digit number); an operand that matches the specified operand number is allowed
1714 /* TODO: ARM constraints:
1715 k the stack pointer register
1716 G the floating-point constant 0.0
1717 Q memory reference where the exact address is in a single register ("m" is preferable for asm statements)
1718 R an item in the constant pool
1719 S symbol in the text segment of the current file
1720 [ Uv memory reference suitable for VFP load/store insns (reg+constant offset)]
1721 [ Uy memory reference suitable for iWMMXt load/store instructions]
1722 Uq memory reference suitable for the ARMv4 ldrsb instruction
1724 ASMOperand *op;
1725 int sorted_op[MAX_ASM_OPERANDS];
1726 int i, j, k, p1, p2, tmp, reg, c, reg_mask;
1727 const char *str;
1728 uint8_t regs_allocated[NB_ASM_REGS];
1730 /* init fields */
1731 for (i = 0; i < nb_operands; i++) {
1732 op = &operands[i];
1733 op->input_index = -1;
1734 op->ref_index = -1;
1735 op->reg = -1;
1736 op->is_memory = 0;
1737 op->is_rw = 0;
1739 /* compute constraint priority and evaluate references to output
1740 constraints if input constraints */
1741 for (i = 0; i < nb_operands; i++) {
1742 op = &operands[i];
1743 str = op->constraint;
1744 str = skip_constraint_modifiers(str);
1745 if (isnum(*str) || *str == '[') {
1746 /* this is a reference to another constraint */
1747 k = find_constraint(operands, nb_operands, str, NULL);
1748 if ((unsigned) k >= i || i < nb_outputs)
1749 tcc_error("invalid reference in constraint %d ('%s')",
1750 i, str);
1751 op->ref_index = k;
1752 if (operands[k].input_index >= 0)
1753 tcc_error("cannot reference twice the same operand");
1754 operands[k].input_index = i;
1755 op->priority = 5;
1756 } else if ((op->vt->r & VT_VALMASK) == VT_LOCAL
1757 && op->vt->sym
1758 && (reg = op->vt->sym->r & VT_VALMASK) < VT_CONST) {
1759 op->priority = 1;
1760 op->reg = reg;
1761 } else {
1762 op->priority = constraint_priority(str);
1766 /* sort operands according to their priority */
1767 for (i = 0; i < nb_operands; i++)
1768 sorted_op[i] = i;
1769 for (i = 0; i < nb_operands - 1; i++) {
1770 for (j = i + 1; j < nb_operands; j++) {
1771 p1 = operands[sorted_op[i]].priority;
1772 p2 = operands[sorted_op[j]].priority;
1773 if (p2 < p1) {
1774 tmp = sorted_op[i];
1775 sorted_op[i] = sorted_op[j];
1776 sorted_op[j] = tmp;
1781 for (i = 0; i < NB_ASM_REGS; i++) {
1782 if (clobber_regs[i])
1783 regs_allocated[i] = REG_IN_MASK | REG_OUT_MASK;
1784 else
1785 regs_allocated[i] = 0;
1787 /* sp cannot be used */
1788 regs_allocated[13] = REG_IN_MASK | REG_OUT_MASK;
1789 /* fp cannot be used yet */
1790 regs_allocated[11] = REG_IN_MASK | REG_OUT_MASK;
1792 /* allocate registers and generate corresponding asm moves */
1793 for (i = 0; i < nb_operands; i++) {
1794 j = sorted_op[i];
1795 op = &operands[j];
1796 str = op->constraint;
1797 /* no need to allocate references */
1798 if (op->ref_index >= 0)
1799 continue;
1800 /* select if register is used for output, input or both */
1801 if (op->input_index >= 0) {
1802 reg_mask = REG_IN_MASK | REG_OUT_MASK;
1803 } else if (j < nb_outputs) {
1804 reg_mask = REG_OUT_MASK;
1805 } else {
1806 reg_mask = REG_IN_MASK;
1808 if (op->reg >= 0) {
1809 if (is_reg_allocated(op->reg))
1810 tcc_error
1811 ("asm regvar requests register that's taken already");
1812 reg = op->reg;
1813 goto reg_found;
1815 try_next:
1816 c = *str++;
1817 switch (c) {
1818 case '=': // Operand is written-to
1819 goto try_next;
1820 case '+': // Operand is both READ and written-to
1821 op->is_rw = 1;
1822 /* FALL THRU */
1823 case '&': // Operand is clobbered before the instruction is done using the input operands
1824 if (j >= nb_outputs)
1825 tcc_error("'%c' modifier can only be applied to outputs",
1827 reg_mask = REG_IN_MASK | REG_OUT_MASK;
1828 goto try_next;
1829 case 'l': // In non-thumb mode, alias for 'r'--otherwise r0-r7 [ARM]
1830 case 'r': // general-purpose register
1831 case 'p': // loadable/storable address
1832 /* any general register */
1833 for (reg = 0; reg <= 8; reg++) {
1834 if (!is_reg_allocated(reg))
1835 goto reg_found;
1837 goto try_next;
1838 reg_found:
1839 /* now we can reload in the register */
1840 op->is_llong = 0;
1841 op->reg = reg;
1842 regs_allocated[reg] |= reg_mask;
1843 break;
1844 case 'I': // integer that is valid as an data processing instruction immediate (0...255, rotated by a multiple of two)
1845 case 'J': // integer in the range -4095 to 4095 [ARM]
1846 case 'K': // integer that satisfies constraint I when inverted (one's complement)
1847 case 'L': // integer that satisfies constraint I when inverted (two's complement)
1848 case 'i': // immediate integer operand, including symbolic constants
1849 if (!((op->vt->r & (VT_VALMASK | VT_LVAL)) == VT_CONST))
1850 goto try_next;
1851 break;
1852 case 'M': // integer in the range 0 to 32
1853 if (!
1854 ((op->vt->r & (VT_VALMASK | VT_LVAL | VT_SYM)) ==
1855 VT_CONST))
1856 goto try_next;
1857 break;
1858 case 'm': // memory operand
1859 case 'g':
1860 /* nothing special to do because the operand is already in
1861 memory, except if the pointer itself is stored in a
1862 memory variable (VT_LLOCAL case) */
1863 /* XXX: fix constant case */
1864 /* if it is a reference to a memory zone, it must lie
1865 in a register, so we reserve the register in the
1866 input registers and a load will be generated
1867 later */
1868 if (j < nb_outputs || c == 'm') {
1869 if ((op->vt->r & VT_VALMASK) == VT_LLOCAL) {
1870 /* any general register */
1871 for (reg = 0; reg <= 8; reg++) {
1872 if (!(regs_allocated[reg] & REG_IN_MASK))
1873 goto reg_found1;
1875 goto try_next;
1876 reg_found1:
1877 /* now we can reload in the register */
1878 regs_allocated[reg] |= REG_IN_MASK;
1879 op->reg = reg;
1880 op->is_memory = 1;
1883 break;
1884 default:
1885 tcc_error("asm constraint %d ('%s') could not be satisfied",
1886 j, op->constraint);
1887 break;
1889 /* if a reference is present for that operand, we assign it too */
1890 if (op->input_index >= 0) {
1891 operands[op->input_index].reg = op->reg;
1892 operands[op->input_index].is_llong = op->is_llong;
1896 /* compute out_reg. It is used to store outputs registers to memory
1897 locations references by pointers (VT_LLOCAL case) */
1898 *pout_reg = -1;
1899 for (i = 0; i < nb_operands; i++) {
1900 op = &operands[i];
1901 if (op->reg >= 0 &&
1902 (op->vt->r & VT_VALMASK) == VT_LLOCAL && !op->is_memory) {
1903 for (reg = 0; reg <= 8; reg++) {
1904 if (!(regs_allocated[reg] & REG_OUT_MASK))
1905 goto reg_found2;
1907 tcc_error("could not find free output register for reloading");
1908 reg_found2:
1909 *pout_reg = reg;
1910 break;
1914 /* print sorted constraints */
1915 #ifdef ASM_DEBUG
1916 for (i = 0; i < nb_operands; i++) {
1917 j = sorted_op[i];
1918 op = &operands[j];
1919 printf("%%%d [%s]: \"%s\" r=0x%04x reg=%d\n",
1921 op->id ? get_tok_str(op->id, NULL) : "",
1922 op->constraint, op->vt->r, op->reg);
1924 if (*pout_reg >= 0)
1925 printf("out_reg=%d\n", *pout_reg);
1926 #endif
1929 ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str)
1931 int reg;
1932 TokenSym *ts;
1934 if (!strcmp(str, "memory") ||
1935 !strcmp(str, "cc") ||
1936 !strcmp(str, "flags"))
1937 return;
1938 ts = tok_alloc(str, strlen(str));
1939 reg = asm_parse_regvar(ts->tok);
1940 if (reg == -1) {
1941 tcc_error("invalid clobber register '%s'", str);
1943 clobber_regs[reg] = 1;
1946 /* If T refers to a register then return the register number and type.
1947 Otherwise return -1. */
1948 ST_FUNC int asm_parse_regvar (int t)
1950 if (t >= TOK_ASM_r0 && t <= TOK_ASM_pc) { /* register name */
1951 switch (t) {
1952 case TOK_ASM_fp:
1953 return TOK_ASM_r11 - TOK_ASM_r0;
1954 case TOK_ASM_ip:
1955 return TOK_ASM_r12 - TOK_ASM_r0;
1956 case TOK_ASM_sp:
1957 return TOK_ASM_r13 - TOK_ASM_r0;
1958 case TOK_ASM_lr:
1959 return TOK_ASM_r14 - TOK_ASM_r0;
1960 case TOK_ASM_pc:
1961 return TOK_ASM_r15 - TOK_ASM_r0;
1962 default:
1963 return t - TOK_ASM_r0;
1965 } else
1966 return -1;
1969 /*************************************************************/
1970 #endif /* ndef TARGET_DEFS_ONLY */