Implement proper floating point negation
[tinycc.git] / arm-asm.c
blobfc92898d95c2f1d3089c5ebde8ab3e1f735c323a
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 static uint32_t asm_encode_shift(Operand* shift)
438 uint64_t amount;
439 uint32_t operands = 0;
440 switch (shift->type) {
441 case OP_REG32:
442 if (shift->reg == 15)
443 tcc_error("r15 cannot be used as a shift count");
444 else {
445 operands = ENCODE_BARREL_SHIFTER_SHIFT_BY_REGISTER;
446 operands |= ENCODE_BARREL_SHIFTER_REGISTER(shift->reg);
448 break;
449 case OP_IM8:
450 amount = shift->e.v;
451 if (amount > 0 && amount < 32)
452 operands = ENCODE_BARREL_SHIFTER_IMMEDIATE(amount);
453 else
454 tcc_error("shift count out of range");
455 break;
456 default:
457 tcc_error("unknown shift amount");
459 return operands;
462 static void asm_data_processing_opcode(TCCState *s1, int token)
464 Operand ops[3];
465 int nb_ops;
466 Operand shift = {};
467 int nb_shift = 0;
468 uint32_t operands = 0;
470 /* modulo 16 entries per instruction for the different condition codes */
471 uint32_t opcode_idx = (ARM_INSTRUCTION_GROUP(token) - TOK_ASM_andeq) >> 4;
472 uint32_t opcode_nos = opcode_idx >> 1; // without "s"; "OpCode" in ARM docs
474 for (nb_ops = 0; nb_ops < sizeof(ops)/sizeof(ops[0]); ) {
475 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)
476 break;
477 parse_operand(s1, &ops[nb_ops]);
478 ++nb_ops;
479 if (tok != ',')
480 break;
481 next(); // skip ','
483 if (tok == ',')
484 next();
485 switch (tok) {
486 case TOK_ASM_asl:
487 case TOK_ASM_lsl:
488 case TOK_ASM_asr:
489 case TOK_ASM_lsr:
490 case TOK_ASM_ror:
491 switch (tok) {
492 case TOK_ASM_asl:
493 /* fallthrough */
494 case TOK_ASM_lsl:
495 operands |= ENCODE_BARREL_SHIFTER_MODE_LSL;
496 break;
497 case TOK_ASM_asr:
498 operands |= ENCODE_BARREL_SHIFTER_MODE_ASR;
499 break;
500 case TOK_ASM_lsr:
501 operands |= ENCODE_BARREL_SHIFTER_MODE_LSR;
502 break;
503 case TOK_ASM_ror:
504 operands |= ENCODE_BARREL_SHIFTER_MODE_ROR;
505 break;
507 next();
508 parse_operand(s1, &shift);
509 nb_shift = 1;
510 break;
511 case TOK_ASM_rrx:
512 next();
513 operands |= ENCODE_BARREL_SHIFTER_MODE_ROR;
514 break;
516 if (nb_ops < 2)
517 expect("at least two operands");
518 else if (nb_ops == 2) {
519 memcpy(&ops[2], &ops[1], sizeof(ops[1])); // move ops[2]
520 memcpy(&ops[1], &ops[0], sizeof(ops[0])); // ops[1] was implicit
521 nb_ops = 3;
522 } else if (nb_ops == 3) {
523 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
524 tcc_error("'%s' cannot be used with three operands", get_tok_str(token, NULL));
525 return;
528 if (nb_ops != 3) {
529 expect("two or three operands");
530 return;
531 } else {
532 uint32_t opcode = 0;
533 uint32_t immediate_value;
534 uint8_t half_immediate_rotation;
535 if (nb_shift && shift.type == OP_REG32) {
536 if ((ops[0].type == OP_REG32 && ops[0].reg == 15) ||
537 (ops[1].type == OP_REG32 && ops[1].reg == 15)) {
538 tcc_error("Using the 'pc' register in data processing instructions that have a register-controlled shift is not implemented by ARM");
539 return;
543 // data processing (general case):
544 // operands:
545 // Rn: bits 19...16 (first operand)
546 // Rd: bits 15...12 (destination)
547 // Operand2: bits 11...0 (second operand); depending on I that's either a register or an immediate
548 // operator:
549 // bits 24...21: "OpCode"--see below
551 /* operations in the token list are ordered by opcode */
552 opcode = opcode_nos << 21; // drop "s"
553 if (ops[0].type != OP_REG32)
554 expect("(destination operand) register");
555 else if (opcode_nos == 0xa || opcode_nos == 0xb || opcode_nos == 0x8 || opcode_nos == 0x9) // cmp, cmn, tst, teq
556 operands |= ENCODE_SET_CONDITION_CODES; // force S set, otherwise it's a completely different instruction.
557 else
558 operands |= ENCODE_RD(ops[0].reg);
559 if (ops[1].type != OP_REG32)
560 expect("(first source operand) register");
561 else if (!(opcode_nos == 0xd || opcode_nos == 0xf)) // not: mov, mvn (those have only one source operand)
562 operands |= ENCODE_RN(ops[1].reg);
563 switch (ops[2].type) {
564 case OP_REG32:
565 operands |= ops[2].reg;
566 break;
567 case OP_IM8:
568 case OP_IM32:
569 operands |= ENCODE_IMMEDIATE_FLAG;
570 immediate_value = ops[2].e.v;
571 for (half_immediate_rotation = 0; half_immediate_rotation < 16; ++half_immediate_rotation) {
572 if (immediate_value >= 0x00 && immediate_value < 0x100)
573 break;
574 // rotate left by two
575 immediate_value = ((immediate_value & 0x3FFFFFFF) << 2) | ((immediate_value & 0xC0000000) >> 30);
577 if (half_immediate_rotation >= 16) {
578 /* fallthrough */
579 } else {
580 operands |= immediate_value;
581 operands |= half_immediate_rotation << 8;
582 break;
584 case OP_IM8N: // immediate negative value
585 operands |= ENCODE_IMMEDIATE_FLAG;
586 immediate_value = ops[2].e.v;
587 /* Instruction swapping:
588 0001 = EOR - Rd:= Op1 EOR Op2 -> difficult
589 0011 = RSB - Rd:= Op2 - Op1 -> difficult
590 0111 = RSC - Rd:= Op2 - Op1 + C -> difficult
591 1000 = TST - CC on: Op1 AND Op2 -> difficult
592 1001 = TEQ - CC on: Op1 EOR Op2 -> difficult
593 1100 = ORR - Rd:= Op1 OR Op2 -> difficult
595 switch (opcode_nos) {
596 case 0x0: // AND - Rd:= Op1 AND Op2
597 opcode = 0xe << 21; // BIC
598 immediate_value = ~immediate_value;
599 break;
600 case 0x2: // SUB - Rd:= Op1 - Op2
601 opcode = 0x4 << 21; // ADD
602 immediate_value = -immediate_value;
603 break;
604 case 0x4: // ADD - Rd:= Op1 + Op2
605 opcode = 0x2 << 21; // SUB
606 immediate_value = -immediate_value;
607 break;
608 case 0x5: // ADC - Rd:= Op1 + Op2 + C
609 opcode = 0x6 << 21; // SBC
610 immediate_value = ~immediate_value;
611 break;
612 case 0x6: // SBC - Rd:= Op1 - Op2 + C
613 opcode = 0x5 << 21; // ADC
614 immediate_value = ~immediate_value;
615 break;
616 case 0xa: // CMP - CC on: Op1 - Op2
617 opcode = 0xb << 21; // CMN
618 immediate_value = -immediate_value;
619 break;
620 case 0xb: // CMN - CC on: Op1 + Op2
621 opcode = 0xa << 21; // CMP
622 immediate_value = -immediate_value;
623 break;
624 case 0xd: // MOV - Rd:= Op2
625 opcode = 0xf << 21; // MVN
626 immediate_value = ~immediate_value;
627 break;
628 case 0xe: // BIC - Rd:= Op1 AND NOT Op2
629 opcode = 0x0 << 21; // AND
630 immediate_value = ~immediate_value;
631 break;
632 case 0xf: // MVN - Rd:= NOT Op2
633 opcode = 0xd << 21; // MOV
634 immediate_value = ~immediate_value;
635 break;
636 default:
637 tcc_error("cannot use '%s' with a negative immediate value", get_tok_str(token, NULL));
639 for (half_immediate_rotation = 0; half_immediate_rotation < 16; ++half_immediate_rotation) {
640 if (immediate_value >= 0x00 && immediate_value < 0x100)
641 break;
642 // rotate left by two
643 immediate_value = ((immediate_value & 0x3FFFFFFF) << 2) | ((immediate_value & 0xC0000000) >> 30);
645 if (half_immediate_rotation >= 16) {
646 immediate_value = ops[2].e.v;
647 tcc_error("immediate value 0x%X cannot be encoded into ARM immediate", (unsigned) immediate_value);
648 return;
650 operands |= immediate_value;
651 operands |= half_immediate_rotation << 8;
652 break;
653 default:
654 expect("(second source operand) register or immediate value");
657 if (nb_shift) {
658 if (operands & ENCODE_IMMEDIATE_FLAG)
659 tcc_error("immediate rotation not implemented");
660 else
661 operands |= asm_encode_shift(&shift);
664 /* S=0 and S=1 entries alternate one after another, in that order */
665 opcode |= (opcode_idx & 1) ? ENCODE_SET_CONDITION_CODES : 0;
666 asm_emit_opcode(token, opcode | operands);
670 static void asm_shift_opcode(TCCState *s1, int token)
672 Operand ops[3];
673 int nb_ops;
674 int definitely_neutral = 0;
675 uint32_t opcode = 0xd << 21; // MOV
676 uint32_t operands = 0;
678 for (nb_ops = 0; nb_ops < sizeof(ops)/sizeof(ops[0]); ++nb_ops) {
679 parse_operand(s1, &ops[nb_ops]);
680 if (tok != ',') {
681 ++nb_ops;
682 break;
684 next(); // skip ','
686 if (nb_ops < 2) {
687 expect("at least two operands");
688 return;
691 if (ops[0].type != OP_REG32) {
692 expect("(destination operand) register");
693 return;
694 } else
695 operands |= ENCODE_RD(ops[0].reg);
697 if (nb_ops == 2) {
698 switch (ARM_INSTRUCTION_GROUP(token)) {
699 case TOK_ASM_rrxseq:
700 opcode |= ENCODE_SET_CONDITION_CODES;
701 /* fallthrough */
702 case TOK_ASM_rrxeq:
703 if (ops[1].type == OP_REG32) {
704 operands |= ops[1].reg;
705 operands |= ENCODE_BARREL_SHIFTER_MODE_ROR;
706 asm_emit_opcode(token, opcode | operands);
707 } else
708 tcc_error("(first source operand) register");
709 return;
710 default:
711 memcpy(&ops[2], &ops[1], sizeof(ops[1])); // move ops[2]
712 memcpy(&ops[1], &ops[0], sizeof(ops[0])); // ops[1] was implicit
713 nb_ops = 3;
716 if (nb_ops != 3) {
717 expect("two or three operands");
718 return;
721 switch (ARM_INSTRUCTION_GROUP(token)) {
722 case TOK_ASM_lslseq:
723 case TOK_ASM_lsrseq:
724 case TOK_ASM_asrseq:
725 case TOK_ASM_rorseq:
726 opcode |= ENCODE_SET_CONDITION_CODES;
727 break;
730 switch (ops[1].type) {
731 case OP_REG32:
732 operands |= ops[1].reg;
733 break;
734 case OP_IM8:
735 operands |= ENCODE_IMMEDIATE_FLAG;
736 operands |= ops[1].e.v;
737 break;
740 switch (ops[2].type) {
741 case OP_REG32:
742 if ((ops[0].type == OP_REG32 && ops[0].reg == 15) ||
743 (ops[1].type == OP_REG32 && ops[1].reg == 15)) {
744 tcc_error("Using the 'pc' register in data processing instructions that have a register-controlled shift is not implemented by ARM");
746 operands |= asm_encode_shift(&ops[2]);
747 break;
748 case OP_IM8:
749 if (ops[2].e.v)
750 operands |= asm_encode_shift(&ops[2]);
751 else
752 definitely_neutral = 1;
753 break;
756 if (!definitely_neutral) switch (ARM_INSTRUCTION_GROUP(token)) {
757 case TOK_ASM_lslseq:
758 case TOK_ASM_lsleq:
759 operands |= ENCODE_BARREL_SHIFTER_MODE_LSL;
760 break;
761 case TOK_ASM_lsrseq:
762 case TOK_ASM_lsreq:
763 operands |= ENCODE_BARREL_SHIFTER_MODE_LSR;
764 break;
765 case TOK_ASM_asrseq:
766 case TOK_ASM_asreq:
767 operands |= ENCODE_BARREL_SHIFTER_MODE_ASR;
768 break;
769 case TOK_ASM_rorseq:
770 case TOK_ASM_roreq:
771 operands |= ENCODE_BARREL_SHIFTER_MODE_ROR;
772 break;
773 default:
774 expect("shift instruction");
775 return;
777 asm_emit_opcode(token, opcode | operands);
780 static void asm_multiplication_opcode(TCCState *s1, int token)
782 Operand ops[4];
783 int nb_ops = 0;
784 uint32_t opcode = 0x90;
786 for (nb_ops = 0; nb_ops < sizeof(ops)/sizeof(ops[0]); ++nb_ops) {
787 parse_operand(s1, &ops[nb_ops]);
788 if (tok != ',') {
789 ++nb_ops;
790 break;
792 next(); // skip ','
794 if (nb_ops < 2)
795 expect("at least two operands");
796 else if (nb_ops == 2) {
797 switch (ARM_INSTRUCTION_GROUP(token)) {
798 case TOK_ASM_mulseq:
799 case TOK_ASM_muleq:
800 memcpy(&ops[2], &ops[0], sizeof(ops[1])); // ARM is actually like this!
801 break;
802 default:
803 expect("at least three operands");
804 return;
806 nb_ops = 3;
809 // multiply (special case):
810 // operands:
811 // Rd: bits 19...16
812 // Rm: bits 3...0
813 // Rs: bits 11...8
814 // Rn: bits 15...12
816 if (ops[0].type == OP_REG32)
817 opcode |= ops[0].reg << 16;
818 else
819 expect("(destination operand) register");
820 if (ops[1].type == OP_REG32)
821 opcode |= ops[1].reg;
822 else
823 expect("(first source operand) register");
824 if (ops[2].type == OP_REG32)
825 opcode |= ops[2].reg << 8;
826 else
827 expect("(second source operand) register");
828 if (nb_ops > 3) {
829 if (ops[3].type == OP_REG32)
830 opcode |= ops[3].reg << 12;
831 else
832 expect("(third source operand) register");
835 switch (ARM_INSTRUCTION_GROUP(token)) {
836 case TOK_ASM_mulseq:
837 opcode |= 1 << 20; // Status
838 /* fallthrough */
839 case TOK_ASM_muleq:
840 if (nb_ops != 3)
841 expect("three operands");
842 else {
843 asm_emit_opcode(token, opcode);
845 break;
846 case TOK_ASM_mlaseq:
847 opcode |= 1 << 20; // Status
848 /* fallthrough */
849 case TOK_ASM_mlaeq:
850 if (nb_ops != 4)
851 expect("four operands");
852 else {
853 opcode |= 1 << 21; // Accumulate
854 asm_emit_opcode(token, opcode);
856 break;
857 default:
858 expect("known multiplication instruction");
862 static void asm_long_multiplication_opcode(TCCState *s1, int token)
864 Operand ops[4];
865 int nb_ops = 0;
866 uint32_t opcode = 0x90 | (1 << 23);
868 for (nb_ops = 0; nb_ops < sizeof(ops)/sizeof(ops[0]); ++nb_ops) {
869 parse_operand(s1, &ops[nb_ops]);
870 if (tok != ',') {
871 ++nb_ops;
872 break;
874 next(); // skip ','
876 if (nb_ops != 4) {
877 expect("four operands");
878 return;
881 // long multiply (special case):
882 // operands:
883 // RdLo: bits 15...12
884 // RdHi: bits 19...16
885 // Rs: bits 11...8
886 // Rm: bits 3...0
888 if (ops[0].type == OP_REG32)
889 opcode |= ops[0].reg << 12;
890 else
891 expect("(destination lo accumulator) register");
892 if (ops[1].type == OP_REG32)
893 opcode |= ops[1].reg << 16;
894 else
895 expect("(destination hi accumulator) register");
896 if (ops[2].type == OP_REG32)
897 opcode |= ops[2].reg;
898 else
899 expect("(first source operand) register");
900 if (ops[3].type == OP_REG32)
901 opcode |= ops[3].reg << 8;
902 else
903 expect("(second source operand) register");
905 switch (ARM_INSTRUCTION_GROUP(token)) {
906 case TOK_ASM_smullseq:
907 opcode |= 1 << 20; // Status
908 /* fallthrough */
909 case TOK_ASM_smulleq:
910 opcode |= 1 << 22; // signed
911 asm_emit_opcode(token, opcode);
912 break;
913 case TOK_ASM_umullseq:
914 opcode |= 1 << 20; // Status
915 /* fallthrough */
916 case TOK_ASM_umulleq:
917 asm_emit_opcode(token, opcode);
918 break;
919 case TOK_ASM_smlalseq:
920 opcode |= 1 << 20; // Status
921 /* fallthrough */
922 case TOK_ASM_smlaleq:
923 opcode |= 1 << 22; // signed
924 opcode |= 1 << 21; // Accumulate
925 asm_emit_opcode(token, opcode);
926 break;
927 case TOK_ASM_umlalseq:
928 opcode |= 1 << 20; // Status
929 /* fallthrough */
930 case TOK_ASM_umlaleq:
931 opcode |= 1 << 21; // Accumulate
932 asm_emit_opcode(token, opcode);
933 break;
934 default:
935 expect("known long multiplication instruction");
939 static void asm_single_data_transfer_opcode(TCCState *s1, int token)
941 Operand ops[3];
942 int exclam = 0;
943 int closed_bracket = 0;
944 int op2_minus = 0;
945 uint32_t opcode = 1 << 26;
946 // Note: ldr r0, [r4, #4] ; simple offset: r0 = *(int*)(r4+4); r4 unchanged
947 // Note: ldr r0, [r4, #4]! ; pre-indexed: r0 = *(int*)(r4+4); r4 = r4+4
948 // Note: ldr r0, [r4], #4 ; post-indexed: r0 = *(int*)(r4+0); r4 = r4+4
950 parse_operand(s1, &ops[0]);
951 if (ops[0].type == OP_REG32)
952 opcode |= ENCODE_RD(ops[0].reg);
953 else {
954 expect("(destination operand) register");
955 return;
957 if (tok != ',')
958 expect("two arguments");
959 else
960 next(); // skip ','
961 if (tok != '[')
962 expect("'['");
963 else
964 next(); // skip '['
966 parse_operand(s1, &ops[1]);
967 if (ops[1].type == OP_REG32)
968 opcode |= ENCODE_RN(ops[1].reg);
969 else {
970 expect("(first source operand) register");
971 return;
973 if (tok == ']') {
974 next();
975 closed_bracket = 1;
976 // exclam = 1; // implicit in hardware; don't do it in software
978 if (tok != ',')
979 expect("','");
980 else
981 next(); // skip ','
982 if (tok == '-') {
983 op2_minus = 1;
984 next();
986 parse_operand(s1, &ops[2]);
987 if (!closed_bracket) {
988 if (tok != ']')
989 expect("']'");
990 else
991 next(); // skip ']'
992 opcode |= 1 << 24; // add offset before transfer
993 if (tok == '!') {
994 exclam = 1;
995 next(); // skip '!'
999 // single data transfer: 0 1 I P U B W L << 20 (general case):
1000 // operands:
1001 // Rd: destination operand [ok]
1002 // Rn: first source operand [ok]
1003 // Operand2: bits 11...0 [ok]
1004 // I: immediate operand? [ok]
1005 // P: Pre/post indexing is PRE: Add offset before transfer [ok]
1006 // U: Up/down is up? (*adds* offset to base) [ok]
1007 // B: Byte/word is byte? TODO
1008 // W: Write address back into base? [ok]
1009 // L: Load/store is load? [ok]
1010 if (exclam)
1011 opcode |= 1 << 21; // write offset back into register
1013 if (ops[2].type == OP_IM32 || ops[2].type == OP_IM8 || ops[2].type == OP_IM8N) {
1014 int v = ops[2].e.v;
1015 if (op2_minus)
1016 tcc_error("minus before '#' not supported for immediate values");
1017 if (v >= 0) {
1018 opcode |= 1 << 23; // up
1019 if (v >= 0x1000)
1020 tcc_error("offset out of range for '%s'", get_tok_str(token, NULL));
1021 else
1022 opcode |= v;
1023 } else { // down
1024 if (v <= -0x1000)
1025 tcc_error("offset out of range for '%s'", get_tok_str(token, NULL));
1026 else
1027 opcode |= -v;
1029 } else if (ops[2].type == OP_REG32) {
1030 if (!op2_minus)
1031 opcode |= 1 << 23; // up
1032 opcode |= ENCODE_IMMEDIATE_FLAG; /* if set, it means it's NOT immediate */
1033 opcode |= ops[2].reg;
1034 } else
1035 expect("register");
1037 switch (ARM_INSTRUCTION_GROUP(token)) {
1038 case TOK_ASM_strbeq:
1039 opcode |= 1 << 22; // B
1040 /* fallthrough */
1041 case TOK_ASM_streq:
1042 asm_emit_opcode(token, opcode);
1043 break;
1044 case TOK_ASM_ldrbeq:
1045 opcode |= 1 << 22; // B
1046 /* fallthrough */
1047 case TOK_ASM_ldreq:
1048 opcode |= 1 << 20; // L
1049 asm_emit_opcode(token, opcode);
1050 break;
1051 default:
1052 expect("data transfer instruction");
1056 /* Note: almost dupe of encbranch in arm-gen.c */
1057 static uint32_t encbranchoffset(int pos, int addr, int fail)
1059 addr-=pos+8;
1060 addr/=4;
1061 if(addr>=0x1000000 || addr<-0x1000000) { // FIXME: Is that correct?
1062 if(fail)
1063 tcc_error("function bigger than 32MB");
1064 return 0;
1066 return /*not 0x0A000000|*/(addr&0xffffff);
1069 static void asm_branch_opcode(TCCState *s1, int token)
1071 int jmp_disp = 0;
1072 Operand op;
1073 parse_operand(s1, &op);
1074 if (op.type == OP_IM32 || op.type == OP_IM8 || op.type == OP_IM8N) {
1075 jmp_disp = encbranchoffset(ind, op.e.v, 0);
1076 if (jmp_disp < -0x800000 || jmp_disp > 0x7fffff) {
1077 tcc_error("branch is too far");
1078 return;
1081 switch (ARM_INSTRUCTION_GROUP(token)) {
1082 case TOK_ASM_beq:
1083 if (op.type == OP_IM32 || op.type == OP_IM8 || op.type == OP_IM8N)
1084 asm_emit_opcode(token, (0xa << 24) | (jmp_disp & 0xffffff));
1085 else
1086 expect("branch target");
1087 break;
1088 case TOK_ASM_bleq:
1089 if (op.type == OP_IM32 || op.type == OP_IM8 || op.type == OP_IM8N)
1090 asm_emit_opcode(token, (0xb << 24) | (jmp_disp & 0xffffff));
1091 else
1092 expect("branch target");
1093 break;
1094 case TOK_ASM_bxeq:
1095 if (op.type != OP_REG32)
1096 expect("register");
1097 else
1098 asm_emit_opcode(token, (0x12fff1 << 4) | op.reg);
1099 break;
1100 case TOK_ASM_blxeq:
1101 if (op.type != OP_REG32)
1102 expect("register");
1103 else
1104 asm_emit_opcode(token, (0x12fff3 << 4) | op.reg);
1105 break;
1106 default:
1107 expect("branch instruction");
1111 ST_FUNC void asm_opcode(TCCState *s1, int token)
1113 while (token == TOK_LINEFEED) {
1114 next();
1115 token = tok;
1117 if (token == TOK_EOF)
1118 return;
1119 if (token < TOK_ASM_nopeq) {
1120 expect("instruction");
1121 return;
1124 switch (ARM_INSTRUCTION_GROUP(token)) {
1125 case TOK_ASM_pusheq:
1126 case TOK_ASM_popeq:
1127 case TOK_ASM_stmdaeq:
1128 case TOK_ASM_ldmdaeq:
1129 case TOK_ASM_stmeq:
1130 case TOK_ASM_ldmeq:
1131 case TOK_ASM_stmiaeq:
1132 case TOK_ASM_ldmiaeq:
1133 case TOK_ASM_stmdbeq:
1134 case TOK_ASM_ldmdbeq:
1135 case TOK_ASM_stmibeq:
1136 case TOK_ASM_ldmibeq:
1137 return asm_block_data_transfer_opcode(s1, token);
1138 case TOK_ASM_nopeq:
1139 case TOK_ASM_wfeeq:
1140 case TOK_ASM_wfieq:
1141 return asm_nullary_opcode(token);
1142 case TOK_ASM_swieq:
1143 return asm_unary_opcode(s1, token);
1144 case TOK_ASM_beq:
1145 case TOK_ASM_bleq:
1146 case TOK_ASM_bxeq:
1147 case TOK_ASM_blxeq:
1148 return asm_branch_opcode(s1, token);
1149 case TOK_ASM_clzeq:
1150 case TOK_ASM_sxtbeq:
1151 case TOK_ASM_sxtheq:
1152 case TOK_ASM_uxtbeq:
1153 case TOK_ASM_uxtheq:
1154 case TOK_ASM_movteq:
1155 case TOK_ASM_movweq:
1156 return asm_binary_opcode(s1, token);
1158 case TOK_ASM_ldreq:
1159 case TOK_ASM_ldrbeq:
1160 case TOK_ASM_streq:
1161 case TOK_ASM_strbeq:
1162 return asm_single_data_transfer_opcode(s1, token);
1164 case TOK_ASM_andeq:
1165 case TOK_ASM_eoreq:
1166 case TOK_ASM_subeq:
1167 case TOK_ASM_rsbeq:
1168 case TOK_ASM_addeq:
1169 case TOK_ASM_adceq:
1170 case TOK_ASM_sbceq:
1171 case TOK_ASM_rsceq:
1172 case TOK_ASM_tsteq:
1173 case TOK_ASM_teqeq:
1174 case TOK_ASM_cmpeq:
1175 case TOK_ASM_cmneq:
1176 case TOK_ASM_orreq:
1177 case TOK_ASM_moveq:
1178 case TOK_ASM_biceq:
1179 case TOK_ASM_mvneq:
1180 case TOK_ASM_andseq:
1181 case TOK_ASM_eorseq:
1182 case TOK_ASM_subseq:
1183 case TOK_ASM_rsbseq:
1184 case TOK_ASM_addseq:
1185 case TOK_ASM_adcseq:
1186 case TOK_ASM_sbcseq:
1187 case TOK_ASM_rscseq:
1188 // case TOK_ASM_tstseq:
1189 // case TOK_ASM_teqseq:
1190 // case TOK_ASM_cmpseq:
1191 // case TOK_ASM_cmnseq:
1192 case TOK_ASM_orrseq:
1193 case TOK_ASM_movseq:
1194 case TOK_ASM_bicseq:
1195 case TOK_ASM_mvnseq:
1196 return asm_data_processing_opcode(s1, token);
1198 case TOK_ASM_lsleq:
1199 case TOK_ASM_lslseq:
1200 case TOK_ASM_lsreq:
1201 case TOK_ASM_lsrseq:
1202 case TOK_ASM_asreq:
1203 case TOK_ASM_asrseq:
1204 case TOK_ASM_roreq:
1205 case TOK_ASM_rorseq:
1206 case TOK_ASM_rrxseq:
1207 case TOK_ASM_rrxeq:
1208 return asm_shift_opcode(s1, token);
1210 case TOK_ASM_muleq:
1211 case TOK_ASM_mulseq:
1212 case TOK_ASM_mlaeq:
1213 case TOK_ASM_mlaseq:
1214 return asm_multiplication_opcode(s1, token);
1216 case TOK_ASM_smulleq:
1217 case TOK_ASM_smullseq:
1218 case TOK_ASM_umulleq:
1219 case TOK_ASM_umullseq:
1220 case TOK_ASM_smlaleq:
1221 case TOK_ASM_smlalseq:
1222 case TOK_ASM_umlaleq:
1223 case TOK_ASM_umlalseq:
1224 return asm_long_multiplication_opcode(s1, token);
1225 default:
1226 expect("known instruction");
1230 ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier)
1232 int r, reg, size, val;
1233 char buf[64];
1235 r = sv->r;
1236 if ((r & VT_VALMASK) == VT_CONST) {
1237 if (!(r & VT_LVAL) && modifier != 'c' && modifier != 'n' &&
1238 modifier != 'P')
1239 cstr_ccat(add_str, '#');
1240 if (r & VT_SYM) {
1241 const char *name = get_tok_str(sv->sym->v, NULL);
1242 if (sv->sym->v >= SYM_FIRST_ANOM) {
1243 /* In case of anonymous symbols ("L.42", used
1244 for static data labels) we can't find them
1245 in the C symbol table when later looking up
1246 this name. So enter them now into the asm label
1247 list when we still know the symbol. */
1248 get_asm_sym(tok_alloc(name, strlen(name))->tok, sv->sym);
1250 if (tcc_state->leading_underscore)
1251 cstr_ccat(add_str, '_');
1252 cstr_cat(add_str, name, -1);
1253 if ((uint32_t) sv->c.i == 0)
1254 goto no_offset;
1255 cstr_ccat(add_str, '+');
1257 val = sv->c.i;
1258 if (modifier == 'n')
1259 val = -val;
1260 snprintf(buf, sizeof(buf), "%d", (int) sv->c.i);
1261 cstr_cat(add_str, buf, -1);
1262 no_offset:;
1263 } else if ((r & VT_VALMASK) == VT_LOCAL) {
1264 snprintf(buf, sizeof(buf), "[fp,#%d]", (int) sv->c.i);
1265 cstr_cat(add_str, buf, -1);
1266 } else if (r & VT_LVAL) {
1267 reg = r & VT_VALMASK;
1268 if (reg >= VT_CONST)
1269 tcc_internal_error("");
1270 snprintf(buf, sizeof(buf), "[%s]",
1271 get_tok_str(TOK_ASM_r0 + reg, NULL));
1272 cstr_cat(add_str, buf, -1);
1273 } else {
1274 /* register case */
1275 reg = r & VT_VALMASK;
1276 if (reg >= VT_CONST)
1277 tcc_internal_error("");
1279 /* choose register operand size */
1280 if ((sv->type.t & VT_BTYPE) == VT_BYTE ||
1281 (sv->type.t & VT_BTYPE) == VT_BOOL)
1282 size = 1;
1283 else if ((sv->type.t & VT_BTYPE) == VT_SHORT)
1284 size = 2;
1285 else
1286 size = 4;
1288 if (modifier == 'b') {
1289 size = 1;
1290 } else if (modifier == 'w') {
1291 size = 2;
1292 } else if (modifier == 'k') {
1293 size = 4;
1296 switch (size) {
1297 default:
1298 reg = TOK_ASM_r0 + reg;
1299 break;
1301 snprintf(buf, sizeof(buf), "%s", get_tok_str(reg, NULL));
1302 cstr_cat(add_str, buf, -1);
1306 /* generate prolog and epilog code for asm statement */
1307 ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands,
1308 int nb_outputs, int is_output,
1309 uint8_t *clobber_regs,
1310 int out_reg)
1312 uint8_t regs_allocated[NB_ASM_REGS];
1313 ASMOperand *op;
1314 int i, reg;
1315 uint32_t saved_regset = 0;
1317 // TODO: Check non-E ABI.
1318 // Note: Technically, r13 (sp) is also callee-saved--but that does not matter yet
1319 static uint8_t reg_saved[] = { 4, 5, 6, 7, 8, 9 /* Note: sometimes special reg "sb" */ , 10, 11 };
1321 /* mark all used registers */
1322 memcpy(regs_allocated, clobber_regs, sizeof(regs_allocated));
1323 for(i = 0; i < nb_operands;i++) {
1324 op = &operands[i];
1325 if (op->reg >= 0)
1326 regs_allocated[op->reg] = 1;
1328 for(i = 0; i < sizeof(reg_saved)/sizeof(reg_saved[0]); i++) {
1329 reg = reg_saved[i];
1330 if (regs_allocated[reg])
1331 saved_regset |= 1 << reg;
1334 if (!is_output) { // prolog
1335 /* generate reg save code */
1336 if (saved_regset)
1337 gen_le32(0xe92d0000 | saved_regset); // push {...}
1339 /* generate load code */
1340 for(i = 0; i < nb_operands; i++) {
1341 op = &operands[i];
1342 if (op->reg >= 0) {
1343 if ((op->vt->r & VT_VALMASK) == VT_LLOCAL &&
1344 op->is_memory) {
1345 /* memory reference case (for both input and
1346 output cases) */
1347 SValue sv;
1348 sv = *op->vt;
1349 sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL | VT_LVAL;
1350 sv.type.t = VT_PTR;
1351 load(op->reg, &sv);
1352 } else if (i >= nb_outputs || op->is_rw) { // not write-only
1353 /* load value in register */
1354 load(op->reg, op->vt);
1355 if (op->is_llong)
1356 tcc_error("long long not implemented");
1360 } else { // epilog
1361 /* generate save code */
1362 for(i = 0 ; i < nb_outputs; i++) {
1363 op = &operands[i];
1364 if (op->reg >= 0) {
1365 if ((op->vt->r & VT_VALMASK) == VT_LLOCAL) {
1366 if (!op->is_memory) {
1367 SValue sv;
1368 sv = *op->vt;
1369 sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL;
1370 sv.type.t = VT_PTR;
1371 load(out_reg, &sv);
1373 sv = *op->vt;
1374 sv.r = (sv.r & ~VT_VALMASK) | out_reg;
1375 store(op->reg, &sv);
1377 } else {
1378 store(op->reg, op->vt);
1379 if (op->is_llong)
1380 tcc_error("long long not implemented");
1385 /* generate reg restore code */
1386 if (saved_regset)
1387 gen_le32(0xe8bd0000 | saved_regset); // pop {...}
1391 /* return the constraint priority (we allocate first the lowest
1392 numbered constraints) */
1393 static inline int constraint_priority(const char *str)
1395 int priority, c, pr;
1397 /* we take the lowest priority */
1398 priority = 0;
1399 for(;;) {
1400 c = *str;
1401 if (c == '\0')
1402 break;
1403 str++;
1404 switch(c) {
1405 case 'l': // in ARM mode, that's an alias for 'r' [ARM].
1406 case 'r': // register [general]
1407 case 'p': // valid memory address for load,store [general]
1408 pr = 3;
1409 break;
1410 case 'M': // integer constant for shifts [ARM]
1411 case 'I': // integer valid for data processing instruction immediate
1412 case 'J': // integer in range -4095...4095
1414 case 'i': // immediate integer operand, including symbolic constants [general]
1415 case 'm': // memory operand [general]
1416 case 'g': // general-purpose-register, memory, immediate integer [general]
1417 pr = 4;
1418 break;
1419 default:
1420 tcc_error("unknown constraint '%c'", c);
1421 pr = 0;
1423 if (pr > priority)
1424 priority = pr;
1426 return priority;
1429 static const char *skip_constraint_modifiers(const char *p)
1431 /* Constraint modifier:
1432 = Operand is written to by this instruction
1433 + Operand is both read and written to by this instruction
1434 % Instruction is commutative for this operand and the following operand.
1436 Per-alternative constraint modifier:
1437 & Operand is clobbered before the instruction is done using the input operands
1439 while (*p == '=' || *p == '&' || *p == '+' || *p == '%')
1440 p++;
1441 return p;
1444 #define REG_OUT_MASK 0x01
1445 #define REG_IN_MASK 0x02
1447 #define is_reg_allocated(reg) (regs_allocated[reg] & reg_mask)
1449 ST_FUNC void asm_compute_constraints(ASMOperand *operands,
1450 int nb_operands, int nb_outputs,
1451 const uint8_t *clobber_regs,
1452 int *pout_reg)
1454 /* overall format: modifier, then ,-seperated list of alternatives; all operands for a single instruction must have the same number of alternatives */
1455 /* TODO: Simple constraints
1456 whitespace ignored
1457 o memory operand that is offsetable
1458 V memory but not offsetable
1459 < memory operand with autodecrement addressing is allowed. Restrictions apply.
1460 > memory operand with autoincrement addressing is allowed. Restrictions apply.
1461 n immediate integer operand with a known numeric value
1462 E immediate floating operand (const_double) is allowed, but only if target=host
1463 F immediate floating operand (const_double or const_vector) is allowed
1464 s immediate integer operand whose value is not an explicit integer
1465 X any operand whatsoever
1466 0...9 (postfix); (can also be more than 1 digit number); an operand that matches the specified operand number is allowed
1469 /* TODO: ARM constraints:
1470 k the stack pointer register
1471 G the floating-point constant 0.0
1472 Q memory reference where the exact address is in a single register ("m" is preferable for asm statements)
1473 R an item in the constant pool
1474 S symbol in the text segment of the current file
1475 [ Uv memory reference suitable for VFP load/store insns (reg+constant offset)]
1476 [ Uy memory reference suitable for iWMMXt load/store instructions]
1477 Uq memory reference suitable for the ARMv4 ldrsb instruction
1479 ASMOperand *op;
1480 int sorted_op[MAX_ASM_OPERANDS];
1481 int i, j, k, p1, p2, tmp, reg, c, reg_mask;
1482 const char *str;
1483 uint8_t regs_allocated[NB_ASM_REGS];
1485 /* init fields */
1486 for (i = 0; i < nb_operands; i++) {
1487 op = &operands[i];
1488 op->input_index = -1;
1489 op->ref_index = -1;
1490 op->reg = -1;
1491 op->is_memory = 0;
1492 op->is_rw = 0;
1494 /* compute constraint priority and evaluate references to output
1495 constraints if input constraints */
1496 for (i = 0; i < nb_operands; i++) {
1497 op = &operands[i];
1498 str = op->constraint;
1499 str = skip_constraint_modifiers(str);
1500 if (isnum(*str) || *str == '[') {
1501 /* this is a reference to another constraint */
1502 k = find_constraint(operands, nb_operands, str, NULL);
1503 if ((unsigned) k >= i || i < nb_outputs)
1504 tcc_error("invalid reference in constraint %d ('%s')",
1505 i, str);
1506 op->ref_index = k;
1507 if (operands[k].input_index >= 0)
1508 tcc_error("cannot reference twice the same operand");
1509 operands[k].input_index = i;
1510 op->priority = 5;
1511 } else if ((op->vt->r & VT_VALMASK) == VT_LOCAL
1512 && op->vt->sym
1513 && (reg = op->vt->sym->r & VT_VALMASK) < VT_CONST) {
1514 op->priority = 1;
1515 op->reg = reg;
1516 } else {
1517 op->priority = constraint_priority(str);
1521 /* sort operands according to their priority */
1522 for (i = 0; i < nb_operands; i++)
1523 sorted_op[i] = i;
1524 for (i = 0; i < nb_operands - 1; i++) {
1525 for (j = i + 1; j < nb_operands; j++) {
1526 p1 = operands[sorted_op[i]].priority;
1527 p2 = operands[sorted_op[j]].priority;
1528 if (p2 < p1) {
1529 tmp = sorted_op[i];
1530 sorted_op[i] = sorted_op[j];
1531 sorted_op[j] = tmp;
1536 for (i = 0; i < NB_ASM_REGS; i++) {
1537 if (clobber_regs[i])
1538 regs_allocated[i] = REG_IN_MASK | REG_OUT_MASK;
1539 else
1540 regs_allocated[i] = 0;
1542 /* sp cannot be used */
1543 regs_allocated[13] = REG_IN_MASK | REG_OUT_MASK;
1544 /* fp cannot be used yet */
1545 regs_allocated[11] = REG_IN_MASK | REG_OUT_MASK;
1547 /* allocate registers and generate corresponding asm moves */
1548 for (i = 0; i < nb_operands; i++) {
1549 j = sorted_op[i];
1550 op = &operands[j];
1551 str = op->constraint;
1552 /* no need to allocate references */
1553 if (op->ref_index >= 0)
1554 continue;
1555 /* select if register is used for output, input or both */
1556 if (op->input_index >= 0) {
1557 reg_mask = REG_IN_MASK | REG_OUT_MASK;
1558 } else if (j < nb_outputs) {
1559 reg_mask = REG_OUT_MASK;
1560 } else {
1561 reg_mask = REG_IN_MASK;
1563 if (op->reg >= 0) {
1564 if (is_reg_allocated(op->reg))
1565 tcc_error
1566 ("asm regvar requests register that's taken already");
1567 reg = op->reg;
1568 goto reg_found;
1570 try_next:
1571 c = *str++;
1572 switch (c) {
1573 case '=': // Operand is written-to
1574 goto try_next;
1575 case '+': // Operand is both READ and written-to
1576 op->is_rw = 1;
1577 /* FALL THRU */
1578 case '&': // Operand is clobbered before the instruction is done using the input operands
1579 if (j >= nb_outputs)
1580 tcc_error("'%c' modifier can only be applied to outputs",
1582 reg_mask = REG_IN_MASK | REG_OUT_MASK;
1583 goto try_next;
1584 case 'l': // In non-thumb mode, alias for 'r'--otherwise r0-r7 [ARM]
1585 case 'r': // general-purpose register
1586 case 'p': // loadable/storable address
1587 /* any general register */
1588 for (reg = 0; reg <= 8; reg++) {
1589 if (!is_reg_allocated(reg))
1590 goto reg_found;
1592 goto try_next;
1593 reg_found:
1594 /* now we can reload in the register */
1595 op->is_llong = 0;
1596 op->reg = reg;
1597 regs_allocated[reg] |= reg_mask;
1598 break;
1599 case 'I': // integer that is valid as an data processing instruction immediate (0...255, rotated by a multiple of two)
1600 case 'J': // integer in the range -4095 to 4095 [ARM]
1601 case 'K': // integer that satisfies constraint I when inverted (one's complement)
1602 case 'L': // integer that satisfies constraint I when inverted (two's complement)
1603 case 'i': // immediate integer operand, including symbolic constants
1604 if (!((op->vt->r & (VT_VALMASK | VT_LVAL)) == VT_CONST))
1605 goto try_next;
1606 break;
1607 case 'M': // integer in the range 0 to 32
1608 if (!
1609 ((op->vt->r & (VT_VALMASK | VT_LVAL | VT_SYM)) ==
1610 VT_CONST))
1611 goto try_next;
1612 break;
1613 case 'm': // memory operand
1614 case 'g':
1615 /* nothing special to do because the operand is already in
1616 memory, except if the pointer itself is stored in a
1617 memory variable (VT_LLOCAL case) */
1618 /* XXX: fix constant case */
1619 /* if it is a reference to a memory zone, it must lie
1620 in a register, so we reserve the register in the
1621 input registers and a load will be generated
1622 later */
1623 if (j < nb_outputs || c == 'm') {
1624 if ((op->vt->r & VT_VALMASK) == VT_LLOCAL) {
1625 /* any general register */
1626 for (reg = 0; reg <= 8; reg++) {
1627 if (!(regs_allocated[reg] & REG_IN_MASK))
1628 goto reg_found1;
1630 goto try_next;
1631 reg_found1:
1632 /* now we can reload in the register */
1633 regs_allocated[reg] |= REG_IN_MASK;
1634 op->reg = reg;
1635 op->is_memory = 1;
1638 break;
1639 default:
1640 tcc_error("asm constraint %d ('%s') could not be satisfied",
1641 j, op->constraint);
1642 break;
1644 /* if a reference is present for that operand, we assign it too */
1645 if (op->input_index >= 0) {
1646 operands[op->input_index].reg = op->reg;
1647 operands[op->input_index].is_llong = op->is_llong;
1651 /* compute out_reg. It is used to store outputs registers to memory
1652 locations references by pointers (VT_LLOCAL case) */
1653 *pout_reg = -1;
1654 for (i = 0; i < nb_operands; i++) {
1655 op = &operands[i];
1656 if (op->reg >= 0 &&
1657 (op->vt->r & VT_VALMASK) == VT_LLOCAL && !op->is_memory) {
1658 for (reg = 0; reg <= 8; reg++) {
1659 if (!(regs_allocated[reg] & REG_OUT_MASK))
1660 goto reg_found2;
1662 tcc_error("could not find free output register for reloading");
1663 reg_found2:
1664 *pout_reg = reg;
1665 break;
1669 /* print sorted constraints */
1670 #ifdef ASM_DEBUG
1671 for (i = 0; i < nb_operands; i++) {
1672 j = sorted_op[i];
1673 op = &operands[j];
1674 printf("%%%d [%s]: \"%s\" r=0x%04x reg=%d\n",
1676 op->id ? get_tok_str(op->id, NULL) : "",
1677 op->constraint, op->vt->r, op->reg);
1679 if (*pout_reg >= 0)
1680 printf("out_reg=%d\n", *pout_reg);
1681 #endif
1684 ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str)
1686 int reg;
1687 TokenSym *ts;
1689 if (!strcmp(str, "memory") ||
1690 !strcmp(str, "cc") ||
1691 !strcmp(str, "flags"))
1692 return;
1693 ts = tok_alloc(str, strlen(str));
1694 reg = asm_parse_regvar(ts->tok);
1695 if (reg == -1) {
1696 tcc_error("invalid clobber register '%s'", str);
1698 clobber_regs[reg] = 1;
1701 /* If T refers to a register then return the register number and type.
1702 Otherwise return -1. */
1703 ST_FUNC int asm_parse_regvar (int t)
1705 if (t >= TOK_ASM_r0 && t <= TOK_ASM_pc) { /* register name */
1706 switch (t) {
1707 case TOK_ASM_fp:
1708 return TOK_ASM_r11 - TOK_ASM_r0;
1709 case TOK_ASM_ip:
1710 return TOK_ASM_r12 - TOK_ASM_r0;
1711 case TOK_ASM_sp:
1712 return TOK_ASM_r13 - TOK_ASM_r0;
1713 case TOK_ASM_lr:
1714 return TOK_ASM_r14 - TOK_ASM_r0;
1715 case TOK_ASM_pc:
1716 return TOK_ASM_r15 - TOK_ASM_r0;
1717 default:
1718 return t - TOK_ASM_r0;
1720 } else
1721 return -1;
1724 /*************************************************************/
1725 #endif /* ndef TARGET_DEFS_ONLY */