+static
+void emit_ia32_Immediate(ia32_emit_env_t *env, const ir_node *node)
+{
+ const ia32_immediate_attr_t *attr = get_ia32_immediate_attr_const(node);
+
+ be_emit_char(env, '$');
+ if(attr->symconst != NULL) {
+ ident *id = get_entity_ld_ident(attr->symconst);
+
+ if(attr->attr.data.am_sc_sign)
+ be_emit_char(env, '-');
+ be_emit_ident(env, id);
+ }
+ if(attr->symconst == NULL || attr->offset != 0) {
+ if(attr->symconst != NULL)
+ be_emit_char(env, '+');
+ be_emit_irprintf(env->emit, "%d", attr->offset);
+ }
+}
+
+static
+const char* emit_asm_operand(ia32_emit_env_t *env, const ir_node *node,
+ const char *s)
+{
+ const arch_register_t *reg;
+ const char *reg_name;
+ char c;
+ char modifier = 0;
+ int num = -1;
+ const ia32_attr_t *attr;
+ int n_outs;
+ int p;
+
+ assert(*s == '%');
+ c = *(++s);
+
+ /* parse modifiers */
+ switch(c) {
+ case 0:
+ ir_fprintf(stderr, "Warning: asm text (%+F) ends with %\n", node);
+ be_emit_char(env, '%');
+ return s + 1;
+ case '%':
+ be_emit_char(env, '%');
+ return s + 1;
+ case 'w':
+ case 'b':
+ case 'h':
+ modifier = c;
+ ++s;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ break;
+ default:
+ ir_fprintf(stderr, "Warning: asm text (%+F) contains unknown modifier "
+ "'%c' for asm op\n", node, c);
+ ++s;
+ break;
+ }
+
+ /* parse number */
+ sscanf(s, "%d%n", &num, &p);
+ if(num < 0) {
+ ir_fprintf(stderr, "Warning: Couldn't parse assembler operand (%+F)\n",
+ node);
+ return s;
+ } else {
+ s += p;
+ }
+
+ /* get register */
+ attr = get_ia32_attr_const(node);
+ n_outs = ARR_LEN(attr->slots);
+ if(num < n_outs) {
+ reg = get_out_reg(env, node, num);
+ } else {
+ ir_node *pred;
+ int in = num - n_outs;
+ if(in >= get_irn_arity(node)) {
+ ir_fprintf(stderr, "Warning: Invalid input %d specified in asm "
+ "op (%+F)\n", num, node);
+ return s;
+ }
+ pred = get_irn_n(node, in);
+ /* might be an immediate value */
+ if(is_ia32_Immediate(pred)) {
+ emit_ia32_Immediate(env, pred);
+ return s;
+ }
+ reg = get_in_reg(env, node, in);
+ }
+ if(reg == NULL) {
+ ir_fprintf(stderr, "Warning: no register assigned for %d asm op "
+ "(%+F)\n", num, node);
+ return s;
+ }
+
+ /* emit it */
+ be_emit_char(env, '%');
+ switch(modifier) {
+ case 0:
+ reg_name = arch_register_get_name(reg);
+ break;
+ case 'b':
+ reg_name = ia32_get_mapped_reg_name(env->isa->regs_8bit, reg);
+ break;
+ case 'h':
+ reg_name = ia32_get_mapped_reg_name(env->isa->regs_8bit_high, reg);
+ break;
+ case 'w':
+ reg_name = ia32_get_mapped_reg_name(env->isa->regs_16bit, reg);
+ break;
+ default:
+ panic("Invalid asm op modifier");
+ }
+ be_emit_string(env, reg_name);
+
+ return s;
+}
+
+/**
+ * Emits code for an ASM pseudo op.
+ */
+static
+void emit_ia32_Asm(ia32_emit_env_t *env, const ir_node *node)
+{
+ const void *gen_attr = get_irn_generic_attr_const(node);
+ const ia32_asm_attr_t *attr
+ = CONST_CAST_IA32_ATTR(ia32_asm_attr_t, gen_attr);
+ ident *asm_text = attr->asm_text;
+ const char *s = get_id_str(asm_text);
+
+ be_emit_cstring(env, "# Begin ASM \t");
+ be_emit_finish_line_gas(env, node);
+
+ if (s[0] != '\t')
+ be_emit_char(env, '\t');
+
+ while(*s != 0) {
+ if(*s == '%') {
+ s = emit_asm_operand(env, node, s);
+ continue;
+ } else {
+ be_emit_char(env, *s);
+ }
+ ++s;
+ }
+
+ be_emit_char(env, '\n');
+ be_emit_write_line(env);
+
+ be_emit_cstring(env, "# End ASM\n");
+ be_emit_write_line(env);
+}
+