2 * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
4 * This file is part of libFirm.
6 * This file may be distributed and/or modified under the terms of the
7 * GNU General Public License version 2 as published by the Free Software
8 * Foundation and appearing in the file LICENSE.GPL included in the
9 * packaging of this file.
11 * Licensees holding valid libFirm Professional Edition licenses may use
12 * this file in accordance with the libFirm Commercial License.
13 * Agreement provided with the Software.
15 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * @author Oliver Richter, Tobias Gneist, Michael Beck
41 #include "raw_bitset.h"
45 #include "beblocksched.h"
50 #include "arm_emitter.h"
51 #include "arm_optimize.h"
52 #include "gen_arm_emitter.h"
53 #include "arm_nodes_attr.h"
54 #include "arm_new_nodes.h"
55 #include "arm_map_regs.h"
56 #include "gen_arm_regalloc_if.h"
60 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
62 static set *sym_or_tv;
63 static arm_isa_t *isa;
65 static void arm_emit_register(const arch_register_t *reg)
67 be_emit_string(arch_register_get_name(reg));
70 static void arm_emit_source_register(const ir_node *node, int pos)
72 const arch_register_t *reg = arch_get_irn_register_in(node, pos);
73 arm_emit_register(reg);
76 static void arm_emit_dest_register(const ir_node *node, int pos)
78 const arch_register_t *reg = arch_get_irn_register_out(node, pos);
79 arm_emit_register(reg);
82 static void arm_emit_offset(const ir_node *node)
84 const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node);
85 assert(attr->base.is_load_store);
87 be_emit_irprintf("0x%X", attr->offset);
91 * Emit the arm fpa instruction suffix depending on the mode.
93 static void arm_emit_fpa_postfix(const ir_mode *mode)
95 int bits = get_mode_size_bits(mode);
105 static void arm_emit_float_load_store_mode(const ir_node *node)
107 const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node);
108 arm_emit_fpa_postfix(attr->load_store_mode);
111 static void arm_emit_float_arithmetic_mode(const ir_node *node)
113 const arm_farith_attr_t *attr = get_arm_farith_attr_const(node);
114 arm_emit_fpa_postfix(attr->mode);
117 static void arm_emit_symconst(const ir_node *node)
119 const arm_SymConst_attr_t *symconst = get_arm_SymConst_attr_const(node);
120 ir_entity *entity = symconst->entity;
122 be_gas_emit_entity(entity);
124 /* TODO do something with offset */
127 static void arm_emit_load_mode(const ir_node *node)
129 const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node);
130 ir_mode *mode = attr->load_store_mode;
131 int bits = get_mode_size_bits(mode);
132 bool is_signed = mode_is_signed(mode);
134 be_emit_string(is_signed ? "sh" : "h");
135 } else if (bits == 8) {
136 be_emit_string(is_signed ? "sb" : "b");
142 static void arm_emit_store_mode(const ir_node *node)
144 const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node);
145 ir_mode *mode = attr->load_store_mode;
146 int bits = get_mode_size_bits(mode);
148 be_emit_cstring("h");
149 } else if (bits == 8) {
150 be_emit_cstring("b");
156 static void emit_shf_mod_name(arm_shift_modifier_t mod)
159 case ARM_SHF_ASR_REG:
160 case ARM_SHF_ASR_IMM:
161 be_emit_cstring("asr");
163 case ARM_SHF_LSL_REG:
164 case ARM_SHF_LSL_IMM:
165 be_emit_cstring("lsl");
167 case ARM_SHF_LSR_REG:
168 case ARM_SHF_LSR_IMM:
169 be_emit_cstring("lsr");
171 case ARM_SHF_ROR_REG:
172 case ARM_SHF_ROR_IMM:
173 be_emit_cstring("ror");
178 panic("can't emit this shf_mod_name %d", (int) mod);
181 static void arm_emit_shifter_operand(const ir_node *node)
183 const arm_shifter_operand_t *attr = get_arm_shifter_operand_attr_const(node);
185 switch (attr->shift_modifier) {
187 arm_emit_source_register(node, get_irn_arity(node) - 1);
190 unsigned val = attr->immediate_value;
191 val = (val >> attr->shift_immediate)
192 | (val << (32-attr->shift_immediate));
194 be_emit_irprintf("#0x%X", val);
197 case ARM_SHF_ASR_IMM:
198 case ARM_SHF_LSL_IMM:
199 case ARM_SHF_LSR_IMM:
200 case ARM_SHF_ROR_IMM:
201 arm_emit_source_register(node, get_irn_arity(node) - 1);
202 be_emit_cstring(", ");
203 emit_shf_mod_name(attr->shift_modifier);
204 be_emit_irprintf(" #0x%X", attr->shift_immediate);
207 case ARM_SHF_ASR_REG:
208 case ARM_SHF_LSL_REG:
209 case ARM_SHF_LSR_REG:
210 case ARM_SHF_ROR_REG:
211 arm_emit_source_register(node, get_irn_arity(node) - 2);
212 be_emit_cstring(", ");
213 emit_shf_mod_name(attr->shift_modifier);
214 be_emit_cstring(" ");
215 arm_emit_source_register(node, get_irn_arity(node) - 1);
219 arm_emit_source_register(node, get_irn_arity(node) - 1);
220 panic("RRX shifter emitter TODO");
222 case ARM_SHF_INVALID:
225 panic("Invalid shift_modifier while emitting %+F", node);
228 /** An entry in the sym_or_tv set. */
229 typedef struct sym_or_tv_t {
231 ir_entity *entity; /**< An entity. */
232 ir_tarval *tv; /**< A tarval. */
233 const void *generic; /**< For generic compare. */
235 unsigned label; /**< the associated label. */
236 bool is_entity; /**< true if an entity is stored. */
240 * Returns a unique label. This number will not be used a second time.
242 static unsigned get_unique_label(void)
244 static unsigned id = 0;
248 static void emit_constant_name(const sym_or_tv_t *entry)
250 be_emit_irprintf("%sC%u", be_gas_get_private_prefix(), entry->label);
254 * Returns the target block for a control flow node.
256 static ir_node *get_cfop_target_block(const ir_node *irn)
258 return (ir_node*)get_irn_link(irn);
262 * Emit the target label for a control flow node.
264 static void arm_emit_cfop_target(const ir_node *irn)
266 ir_node *block = get_cfop_target_block(irn);
268 be_gas_emit_block_name(block);
271 void arm_emitf(const ir_node *node, const char *format, ...)
274 va_start(ap, format);
277 const char *start = format;
278 while (*format != '%' && *format != '\n' && *format != '\0')
280 be_emit_string_len(start, format - start);
285 if (*format == '\n') {
288 be_emit_write_line();
301 if (*format < '0' || '9' <= *format)
303 unsigned const pos = *format++ - '0';
304 arm_emit_source_register(node, pos);
309 if (*format < '0' || '9' <= *format)
311 unsigned const pos = *format++ - '0';
312 arm_emit_dest_register(node, pos);
317 arm_emit_symconst(node);
321 arm_emit_offset(node);
325 arm_emit_shifter_operand(node);
329 const sym_or_tv_t *name = va_arg(ap, const sym_or_tv_t*);
330 emit_constant_name(name);
335 ir_mode *mode = va_arg(ap, ir_mode*);
336 arm_emit_fpa_postfix(mode);
342 case 'L': arm_emit_load_mode(node); break;
343 case 'S': arm_emit_store_mode(node); break;
344 case 'A': arm_emit_float_arithmetic_mode(node); break;
345 case 'F': arm_emit_float_load_store_mode(node); break;
353 int num = va_arg(ap, int);
354 be_emit_irprintf("%X", num);
359 unsigned num = va_arg(ap, unsigned);
360 be_emit_irprintf("%u", num);
365 int num = va_arg(ap, int);
366 be_emit_irprintf("%d", num);
371 const char *string = va_arg(ap, const char *);
372 be_emit_string(string);
377 arch_register_t *reg = va_arg(ap, arch_register_t*);
378 arm_emit_register(reg);
383 const ir_node *n = va_arg(ap, const ir_node*);
384 arm_emit_cfop_target(n);
390 panic("unknown format conversion");
394 be_emit_finish_line_gas(node);
400 static void emit_arm_SymConst(const ir_node *irn)
402 const arm_SymConst_attr_t *attr = get_arm_SymConst_attr_const(irn);
403 sym_or_tv_t key, *entry;
405 key.u.entity = attr->entity;
406 key.is_entity = true;
408 entry = set_insert(sym_or_tv_t, sym_or_tv, &key, sizeof(key), hash_ptr(key.u.generic));
409 if (entry->label == 0) {
410 /* allocate a label */
411 entry->label = get_unique_label();
414 /* load the symbol indirect */
415 arm_emitf(irn, "ldr %D0, %C", entry);
418 static void emit_arm_FrameAddr(const ir_node *irn)
420 const arm_SymConst_attr_t *attr = get_arm_SymConst_attr_const(irn);
421 arm_emitf(irn, "add %D0, %S0, #0x%X", attr->fp_offset);
425 * Emit a floating point fpa constant.
427 static void emit_arm_fConst(const ir_node *irn)
431 key.u.tv = get_fConst_value(irn);
432 key.is_entity = false;
434 sym_or_tv_t *entry = set_insert(sym_or_tv_t, sym_or_tv, &key, sizeof(key), hash_ptr(key.u.generic));
435 if (entry->label == 0) {
436 /* allocate a label */
437 entry->label = get_unique_label();
440 /* load the tarval indirect */
441 ir_mode *mode = get_irn_mode(irn);
442 arm_emitf(irn, "ldf%m %D0, %C", mode, entry);
446 * Returns the next block in a block schedule.
448 static ir_node *sched_next_block(const ir_node *block)
450 return (ir_node*)get_irn_link(block);
454 * Emit a Compare with conditional branch.
456 static void emit_arm_B(const ir_node *irn)
458 const ir_node *proj_true = NULL;
459 const ir_node *proj_false = NULL;
460 const ir_node *block;
461 const ir_node *next_block;
462 ir_node *op1 = get_irn_n(irn, 0);
464 ir_relation relation = get_arm_CondJmp_relation(irn);
465 const arm_cmp_attr_t *cmp_attr = get_arm_cmp_attr_const(op1);
466 bool is_signed = !cmp_attr->is_unsigned;
468 assert(is_arm_Cmp(op1) || is_arm_Tst(op1));
470 foreach_out_edge(irn, edge) {
471 ir_node *proj = get_edge_src_irn(edge);
472 long nr = get_Proj_proj(proj);
473 if (nr == pn_Cond_true) {
480 if (cmp_attr->ins_permuted) {
481 relation = get_inversed_relation(relation);
484 /* for now, the code works for scheduled and non-schedules blocks */
485 block = get_nodes_block(irn);
487 /* we have a block schedule */
488 next_block = sched_next_block(block);
490 assert(relation != ir_relation_false);
491 assert(relation != ir_relation_true);
493 if (get_cfop_target_block(proj_true) == next_block) {
494 /* exchange both proj's so the second one can be omitted */
495 const ir_node *t = proj_true;
497 proj_true = proj_false;
499 relation = get_negated_relation(relation);
502 switch (relation & (ir_relation_less_equal_greater)) {
503 case ir_relation_equal: suffix = "eq"; break;
504 case ir_relation_less: suffix = is_signed ? "lt" : "lo"; break;
505 case ir_relation_less_equal: suffix = is_signed ? "le" : "ls"; break;
506 case ir_relation_greater: suffix = is_signed ? "gt" : "hi"; break;
507 case ir_relation_greater_equal: suffix = is_signed ? "ge" : "hs"; break;
508 case ir_relation_less_greater: suffix = "ne"; break;
509 case ir_relation_less_equal_greater: suffix = "al"; break;
510 default: panic("Cmp has unsupported relation");
513 /* emit the true proj */
514 arm_emitf(irn, "b%s %t", suffix, proj_true);
516 if (get_cfop_target_block(proj_false) == next_block) {
517 if (be_options.verbose_asm) {
518 arm_emitf(irn, "/* fallthrough to %t */", proj_false);
521 arm_emitf(irn, "b %t", proj_false);
525 /** Sort register in ascending order. */
526 static int reg_cmp(const void *a, const void *b)
528 const arch_register_t * const *ra = (const arch_register_t**)a;
529 const arch_register_t * const *rb = (const arch_register_t**)b;
531 return *ra < *rb ? -1 : (*ra != *rb);
535 * Create the CopyB instruction sequence.
537 static void emit_arm_CopyB(const ir_node *irn)
539 const arm_CopyB_attr_t *attr = get_arm_CopyB_attr_const(irn);
540 unsigned size = attr->size;
541 const arch_register_t *tmpregs[4];
543 /* collect the temporary registers and sort them, we need ascending order */
544 tmpregs[0] = arch_get_irn_register_in(irn, 2);
545 tmpregs[1] = arch_get_irn_register_in(irn, 3);
546 tmpregs[2] = arch_get_irn_register_in(irn, 4);
547 tmpregs[3] = &arm_registers[REG_R12];
549 /* Note: R12 is always the last register because the RA did not assign higher ones */
550 qsort((void *)tmpregs, 3, sizeof(tmpregs[0]), reg_cmp);
552 if (be_options.verbose_asm) {
553 arm_emitf(irn, "/* MemCopy (%S1)->(%S0) [%u bytes], Uses %r, %r, %r and %r */",
554 size, tmpregs[0], tmpregs[1], tmpregs[2], tmpregs[3]);
557 assert(size > 0 && "CopyB needs size > 0" );
560 fprintf(stderr, "strange hack enabled: copy more bytes than needed!");
569 arm_emitf(irn, "ldr %r, [%S1, #0]", tmpregs[3]);
570 arm_emitf(irn, "str %r, [%S0, #0]", tmpregs[3]);
573 arm_emitf(irn, "ldmia %S1!, {%r, %r}", tmpregs[0], tmpregs[1]);
574 arm_emitf(irn, "stmia %S0!, {%r, %r}", tmpregs[0], tmpregs[1]);
577 arm_emitf(irn, "ldmia %S1!, {%r, %r, %r}", tmpregs[0], tmpregs[1], tmpregs[2]);
578 arm_emitf(irn, "stmia %S0!, {%r, %r, %r}", tmpregs[0], tmpregs[1], tmpregs[2]);
583 arm_emitf(irn, "ldmia %S1!, {%r, %r, %r}", tmpregs[0], tmpregs[1], tmpregs[2], tmpregs[3]);
584 arm_emitf(irn, "stmia %S0!, {%r, %r, %r}", tmpregs[0], tmpregs[1], tmpregs[2], tmpregs[3]);
589 static void emit_arm_SwitchJmp(const ir_node *irn)
591 const arm_SwitchJmp_attr_t *attr = get_arm_SwitchJmp_attr_const(irn);
592 arm_emitf(irn, "ldrls pc, [pc, %S0, asl #2]");
594 be_emit_jump_table(irn, attr->table, NULL, get_cfop_target_block);
597 /** Emit an IncSP node */
598 static void emit_be_IncSP(const ir_node *irn)
600 int offs = -be_get_IncSP_offset(irn);
605 const char *op = "add";
610 arm_emitf(irn, "%s %D0, %S0, #0x%X", op, offs);
613 static void emit_be_Copy(const ir_node *irn)
615 ir_mode *mode = get_irn_mode(irn);
617 if (arch_get_irn_register_in(irn, 0) == arch_get_irn_register_out(irn, 0)) {
622 if (mode_is_float(mode)) {
624 arm_emitf(irn, "mvf %D0, %S0");
626 panic("move not supported for this mode");
628 } else if (mode_is_data(mode)) {
629 arm_emitf(irn, "mov %D0, %S0");
631 panic("move not supported for this mode");
635 static void emit_be_Perm(const ir_node *irn)
638 "eor %S0, %S0, %S1\n"
639 "eor %S1, %S0, %S1\n"
640 "eor %S0, %S0, %S1");
643 static void emit_be_MemPerm(const ir_node *node)
649 /* TODO: this implementation is slower than necessary.
650 The longterm goal is however to avoid the memperm node completely */
652 memperm_arity = be_get_MemPerm_entity_arity(node);
653 if (memperm_arity > 12)
654 panic("memperm with more than 12 inputs not supported yet");
656 for (i = 0; i < memperm_arity; ++i) {
658 arm_emitf(node, "str r%d, [sp, #-4]!", i);
660 /* load from entity */
661 ir_entity *entity = be_get_MemPerm_in_entity(node, i);
662 int offset = get_entity_offset(entity) + sp_change;
663 arm_emitf(node, "ldr r%d, [sp, #%d]", i, offset);
666 for (i = memperm_arity-1; i >= 0; --i) {
667 /* store to new entity */
668 ir_entity *entity = be_get_MemPerm_out_entity(node, i);
669 int offset = get_entity_offset(entity) + sp_change;
670 arm_emitf(node, "str r%d, [sp, #%d]", i, offset);
671 /* restore register */
672 arm_emitf(node, "ldr r%d, [sp], #4", i);
675 assert(sp_change == 0);
678 static void emit_be_Start(const ir_node *node)
680 ir_graph *irg = get_irn_irg(node);
681 ir_type *frame_type = get_irg_frame_type(irg);
682 unsigned size = get_type_size_bytes(frame_type);
684 /* allocate stackframe */
686 arm_emitf(node, "sub sp, sp, #0x%X", size);
690 static void emit_be_Return(const ir_node *node)
692 ir_graph *irg = get_irn_irg(node);
693 ir_type *frame_type = get_irg_frame_type(irg);
694 unsigned size = get_type_size_bytes(frame_type);
696 /* deallocate stackframe */
698 arm_emitf(node, "add sp, sp, #0x%X", size);
700 arm_emitf(node, "mov pc, lr");
704 static void emit_arm_Jmp(const ir_node *node)
706 ir_node *block, *next_block;
708 /* for now, the code works for scheduled and non-schedules blocks */
709 block = get_nodes_block(node);
711 /* we have a block schedule */
712 next_block = sched_next_block(block);
713 if (get_cfop_target_block(node) != next_block) {
714 arm_emitf(node, "b %t", node);
716 if (be_options.verbose_asm) {
717 arm_emitf(node, "/* fallthrough to %t */", node);
722 static void emit_nothing(const ir_node *irn)
728 * The type of a emitter function.
730 typedef void (emit_func)(const ir_node *irn);
733 * Set a node emitter. Make it a bit more type safe.
735 static inline void set_emitter(ir_op *op, emit_func arm_emit_node)
737 op->ops.generic = (op_func)arm_emit_node;
741 * Enters the emitter functions for handled nodes into the generic
742 * pointer of an opcode.
744 static void arm_register_emitters(void)
746 /* first clear the generic function pointer for all ops */
747 ir_clear_opcodes_generic_func();
749 /* register all emitter functions defined in spec */
750 arm_register_spec_emitters();
753 set_emitter(op_arm_B, emit_arm_B);
754 set_emitter(op_arm_CopyB, emit_arm_CopyB);
755 set_emitter(op_arm_fConst, emit_arm_fConst);
756 set_emitter(op_arm_FrameAddr, emit_arm_FrameAddr);
757 set_emitter(op_arm_Jmp, emit_arm_Jmp);
758 set_emitter(op_arm_SwitchJmp, emit_arm_SwitchJmp);
759 set_emitter(op_arm_SymConst, emit_arm_SymConst);
760 set_emitter(op_be_Copy, emit_be_Copy);
761 set_emitter(op_be_CopyKeep, emit_be_Copy);
762 set_emitter(op_be_IncSP, emit_be_IncSP);
763 set_emitter(op_be_MemPerm, emit_be_MemPerm);
764 set_emitter(op_be_Perm, emit_be_Perm);
765 set_emitter(op_be_Return, emit_be_Return);
766 set_emitter(op_be_Start, emit_be_Start);
768 /* no need to emit anything for the following nodes */
769 set_emitter(op_Phi, emit_nothing);
770 set_emitter(op_be_Keep, emit_nothing);
774 * Emits code for a node.
776 static void arm_emit_node(const ir_node *irn)
778 ir_op *op = get_irn_op(irn);
780 if (op->ops.generic) {
781 emit_func *emit = (emit_func *)op->ops.generic;
782 be_dwarf_location(get_irn_dbg_info(irn));
785 panic("Error: No emit handler for node %+F (graph %+F)\n",
786 irn, get_irn_irg(irn));
791 * emit the block label if needed.
793 static void arm_emit_block_header(ir_node *block, ir_node *prev)
795 bool need_label = false;
798 n_cfgpreds = get_Block_n_cfgpreds(block);
799 if (n_cfgpreds == 1) {
800 ir_node *pred = get_Block_cfgpred(block, 0);
801 ir_node *pred_block = get_nodes_block(pred);
803 /* we don't need labels for fallthrough blocks, however switch-jmps
804 * are no fallthroughs */
805 if (pred_block == prev &&
806 !(is_Proj(pred) && is_arm_SwitchJmp(get_Proj_pred(pred)))) {
815 be_gas_begin_block(block, need_label);
819 * Walks over the nodes in a block connected by scheduling edges
820 * and emits code for each node.
822 static void arm_gen_block(ir_node *block, ir_node *prev_block)
824 arm_emit_block_header(block, prev_block);
825 be_dwarf_location(get_irn_dbg_info(block));
826 sched_foreach(block, irn) {
833 * Sets labels for control flow nodes (jump target)
835 static void arm_gen_labels(ir_node *block, void *env)
838 int n = get_Block_n_cfgpreds(block);
841 for (n--; n >= 0; n--) {
842 pred = get_Block_cfgpred(block, n);
843 set_irn_link(pred, block);
848 * Compare two entries of the symbol or tarval set.
850 static int cmp_sym_or_tv(const void *elt, const void *key, size_t size)
852 const sym_or_tv_t *p1 = (const sym_or_tv_t*)elt;
853 const sym_or_tv_t *p2 = (const sym_or_tv_t*)key;
856 /* as an identifier NEVER can point to a tarval, it's enough
857 to compare it this way */
858 return p1->u.generic != p2->u.generic;
861 void arm_gen_routine(ir_graph *irg)
863 ir_node *last_block = NULL;
864 ir_entity *entity = get_irg_entity(irg);
865 const arch_env_t *arch_env = be_get_irg_arch_env(irg);
869 isa = (arm_isa_t*) arch_env;
870 sym_or_tv = new_set(cmp_sym_or_tv, 8);
872 be_gas_elf_type_char = '%';
874 arm_register_emitters();
876 /* create the block schedule */
877 blk_sched = be_create_block_schedule(irg);
879 be_gas_emit_function_prolog(entity, 4, NULL);
881 irg_block_walk_graph(irg, arm_gen_labels, NULL, NULL);
883 n = ARR_LEN(blk_sched);
884 for (i = 0; i < n;) {
885 ir_node *block, *next_bl;
887 block = blk_sched[i];
889 next_bl = i < n ? blk_sched[i] : NULL;
891 /* set here the link. the emitter expects to find the next block here */
892 set_irn_link(block, next_bl);
893 arm_gen_block(block, last_block);
897 /* emit SymConst values */
898 if (set_count(sym_or_tv) > 0) {
899 be_emit_cstring("\t.align 2\n");
901 foreach_set(sym_or_tv, sym_or_tv_t, entry) {
902 emit_constant_name(entry);
903 be_emit_cstring(":\n");
904 be_emit_write_line();
906 if (entry->is_entity) {
907 be_emit_cstring("\t.word\t");
908 be_gas_emit_entity(entry->u.entity);
910 be_emit_write_line();
912 ir_tarval *tv = entry->u.tv;
914 int size = get_mode_size_bytes(get_tarval_mode(tv));
916 /* beware: ARM fpa uses big endian format */
917 for (vi = ((size + 3) & ~3) - 4; vi >= 0; vi -= 4) {
920 v = get_tarval_sub_bits(tv, vi+3);
921 v = (v << 8) | get_tarval_sub_bits(tv, vi+2);
922 v = (v << 8) | get_tarval_sub_bits(tv, vi+1);
923 v = (v << 8) | get_tarval_sub_bits(tv, vi+0);
924 be_emit_irprintf("\t.word\t%u\n", v);
925 be_emit_write_line();
930 be_emit_write_line();
934 be_gas_emit_function_epilog(entity);
937 void arm_init_emitter(void)
939 FIRM_DBG_REGISTER(dbg, "firm.be.arm.emit");