+void TEMPLATE_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 != '\0')
+ ++format;
+ be_emit_string_len(start, format-start);
+ if (*format == '\0')
+ break;
+ ++format;
+
+ switch (*format++) {
+ case '%':
+ be_emit_char('%');
+ break;
+
+ case 'S': {
+ if (*format < '0' || '9' <= *format)
+ goto unknown;
+ unsigned const pos = *format++ - '0';
+ TEMPLATE_emit_source_register(node, pos);
+ break;
+ }
+
+ case 'D': {
+ if (*format < '0' || '9' <= *format)
+ goto unknown;
+ unsigned const pos = *format++ - '0';
+ TEMPLATE_emit_dest_register(node, pos);
+ break;
+ }
+
+ case 'I':
+ TEMPLATE_emit_immediate(node);
+ 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 'L': {
+ TEMPLATE_emit_cfop_target(node);
+ break;
+ }
+
+ case '\n':
+ be_emit_char('\n');
+ be_emit_write_line();
+ be_emit_char('\t');
+ break;
+
+ default:
+unknown:
+ panic("unknown format conversion in arm_emitf()");
+ }
+ }
+ va_end(ap);
+ be_emit_finish_line_gas(node);