+/**
+ * Returns the target block for a control flow node.
+ */
+static ir_node *get_cfop_target_block(const ir_node *irn)
+{
+ return (ir_node*)get_irn_link(irn);
+}
+
+/**
+ * Emit the target label for a control flow node.
+ */
+static void arm_emit_cfop_target(const ir_node *irn)
+{
+ ir_node *block = get_cfop_target_block(irn);
+
+ be_gas_emit_block_name(block);
+}
+
+void arm_emitf(const ir_node *node, const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ be_emit_char('\t');
+ for (;;) {
+ const char *start = format;
+ while (*format != '%' && *format != '\n' && *format != '\0')
+ ++format;
+ be_emit_string_len(start, format - start);
+
+ if (*format == '\0')
+ break;
+
+ if (*format == '\n') {
+ ++format;
+ be_emit_char('\n');
+ be_emit_write_line();
+ be_emit_char('\t');
+ continue;
+ }
+
+ ++format;
+
+ switch (*format++) {
+ case '%':
+ be_emit_char('%');
+ break;
+
+ case 'S': {
+ if (*format < '0' || '9' <= *format)
+ goto unknown;
+ unsigned const pos = *format++ - '0';
+ arm_emit_source_register(node, pos);
+ break;
+ }
+
+ case 'D': {
+ if (*format < '0' || '9' <= *format)
+ goto unknown;
+ unsigned const pos = *format++ - '0';
+ arm_emit_dest_register(node, pos);
+ break;
+ }
+
+ case 'I':
+ arm_emit_symconst(node);
+ break;
+
+ case 'o':
+ arm_emit_offset(node);
+ break;
+
+ case 'O':
+ arm_emit_shifter_operand(node);
+ break;
+
+ case 'C': {
+ const sym_or_tv_t *name = va_arg(ap, const sym_or_tv_t*);
+ emit_constant_name(name);
+ break;
+ }
+
+ case 'm': {
+ ir_mode *mode = va_arg(ap, ir_mode*);
+ arm_emit_fpa_postfix(mode);
+ break;
+ }
+
+ case 'M':
+ switch (*format++) {
+ case 'L': arm_emit_load_mode(node); break;
+ case 'S': arm_emit_store_mode(node); break;
+ case 'A': arm_emit_float_arithmetic_mode(node); break;
+ case 'F': arm_emit_float_load_store_mode(node); break;
+ default:
+ --format;
+ goto unknown;
+ }
+ break;
+
+ case 'X': {
+ int num = va_arg(ap, int);
+ be_emit_irprintf("%X", num);
+ break;
+ }
+
+ case 'u': {
+ unsigned num = va_arg(ap, unsigned);
+ be_emit_irprintf("%u", num);
+ break;
+ }
+
+ case 'd': {
+ int num = va_arg(ap, int);
+ be_emit_irprintf("%d", num);
+ break;
+ }
+
+ case 's': {
+ const char *string = va_arg(ap, const char *);
+ be_emit_string(string);
+ break;
+ }
+
+ case 'r': {
+ arch_register_t *reg = va_arg(ap, arch_register_t*);
+ arm_emit_register(reg);
+ break;
+ }
+
+ case 't': {
+ const ir_node *n = va_arg(ap, const ir_node*);
+ arm_emit_cfop_target(n);
+ break;
+ }
+
+ default:
+unknown:
+ panic("unknown format conversion");
+ }
+ }
+ va_end(ap);
+ be_emit_finish_line_gas(node);
+}
+