+UNOP(not, 0xF7, 2, n_ia32_Not_val)
+UNOP(neg, 0xF7, 3, n_ia32_Neg_val)
+UNOP(mul, 0xF7, 4, n_ia32_Mul_right)
+UNOP(imul1op, 0xF7, 5, n_ia32_IMul1OP_right)
+UNOP(div, 0xF7, 6, n_ia32_Div_divisor)
+UNOP(idiv, 0xF7, 7, n_ia32_IDiv_divisor)
+
+/* TODO: am support for IJmp */
+UNOP(ijmp, 0xFF, 4, n_ia32_IJmp_target)
+
+#define SHIFT(op, ext) \
+static void bemit_##op(const ir_node *node) \
+{ \
+ const arch_register_t *out = get_out_reg(node, 0); \
+ ir_node *count = get_irn_n(node, 1); \
+ if (is_ia32_Immediate(count)) { \
+ int offset = get_ia32_immediate_attr_const(count)->offset; \
+ if (offset == 1) { \
+ bemit8(0xD1); \
+ bemit_modru(out, ext); \
+ } else { \
+ bemit8(0xC1); \
+ bemit_modru(out, ext); \
+ bemit8(offset); \
+ } \
+ } else { \
+ bemit8(0xD3); \
+ bemit_modru(out, ext); \
+ } \
+} \
+ \
+static void bemit_##op##mem(const ir_node *node) \
+{ \
+ ir_node *count; \
+ unsigned size = get_mode_size_bits(get_ia32_ls_mode(node)); \
+ if (size == 16) \
+ bemit8(0x66); \
+ count = get_irn_n(node, 1); \
+ if (is_ia32_Immediate(count)) { \
+ int offset = get_ia32_immediate_attr_const(count)->offset; \
+ if (offset == 1) { \
+ bemit8(size == 8 ? 0xD0 : 0xD1); \
+ bemit_mod_am(ext, node); \
+ } else { \
+ bemit8(size == 8 ? 0xC0 : 0xC1); \
+ bemit_mod_am(ext, node); \
+ bemit8(offset); \
+ } \
+ } else { \
+ bemit8(size == 8 ? 0xD2 : 0xD3); \
+ bemit_mod_am(ext, node); \
+ } \
+}
+
+SHIFT(rol, 0)
+SHIFT(ror, 1)
+SHIFT(shl, 4)
+SHIFT(shr, 5)
+SHIFT(sar, 7)
+
+static void bemit_shld(const ir_node *node)
+{
+ const arch_register_t *in = get_in_reg(node, n_ia32_ShlD_val_low);
+ const arch_register_t *out = get_out_reg(node, pn_ia32_ShlD_res);
+ ir_node *count = get_irn_n(node, n_ia32_ShlD_count);
+ bemit8(0x0F);
+ if (is_ia32_Immediate(count)) {
+ bemit8(0xA4);
+ bemit_modrr(out, in);
+ bemit8(get_ia32_immediate_attr_const(count)->offset);
+ } else {
+ bemit8(0xA5);
+ bemit_modrr(out, in);
+ }
+}
+
+static void bemit_shrd(const ir_node *node)
+{
+ const arch_register_t *in = get_in_reg(node, n_ia32_ShrD_val_low);
+ const arch_register_t *out = get_out_reg(node, pn_ia32_ShrD_res);
+ ir_node *count = get_irn_n(node, n_ia32_ShrD_count);
+ bemit8(0x0F);
+ if (is_ia32_Immediate(count)) {
+ bemit8(0xAC);
+ bemit_modrr(out, in);
+ bemit8(get_ia32_immediate_attr_const(count)->offset);
+ } else {
+ bemit8(0xAD);
+ bemit_modrr(out, in);
+ }
+}
+
+/**
+ * binary emitter for setcc.
+ */
+static void bemit_setcc(const ir_node *node)
+{
+ const arch_register_t *dreg = get_out_reg(node, pn_ia32_Setcc_res);
+
+ pn_Cmp pnc = get_ia32_condcode(node);
+ pnc = determine_final_pnc(node, n_ia32_Setcc_eflags, pnc);
+ if (pnc & ia32_pn_Cmp_float) {
+ switch (pnc & 0x0f) {
+ case pn_Cmp_Uo:
+ /* setp <dreg */
+ bemit8(0x0F);
+ bemit8(0x9A);
+ bemit_modrm8(REG_LOW, dreg);
+ return;
+
+ case pn_Cmp_Leg:
+ /* setnp <dreg*/
+ bemit8(0x0F);
+ bemit8(0x9B);
+ bemit_modrm8(REG_LOW, dreg);
+ return;
+
+ case pn_Cmp_Eq:
+ case pn_Cmp_Lt:
+ case pn_Cmp_Le:
+ /* set%PNC <dreg */
+ bemit8(0x0F);
+ bemit8(0x90 | pnc2cc(pnc));
+ bemit_modrm8(REG_LOW, dreg);
+
+ /* setnp >dreg */
+ bemit8(0x0F);
+ bemit8(0x9B);
+ bemit_modrm8(REG_HIGH, dreg);
+
+ /* andb %>dreg, %<dreg */
+ bemit8(0x20);
+ bemit_modrr8(REG_LOW, dreg, REG_HIGH, dreg);
+ return;
+
+ case pn_Cmp_Ug:
+ case pn_Cmp_Uge:
+ case pn_Cmp_Ne:
+ /* set%PNC <dreg */
+ bemit8(0x0F);
+ bemit8(0x90 | pnc2cc(pnc));
+ bemit_modrm8(REG_LOW, dreg);
+
+ /* setp >dreg */
+ bemit8(0x0F);
+ bemit8(0x9A);
+ bemit_modrm8(REG_HIGH, dreg);
+
+ /* orb %>dreg, %<dreg */
+ bemit8(0x08);
+ bemit_modrr8(REG_LOW, dreg, REG_HIGH, dreg);
+ return;
+
+ default:
+ break;
+ }
+ }
+ /* set%PNC <dreg */
+ bemit8(0x0F);
+ bemit8(0x90 | pnc2cc(pnc));
+ bemit_modrm8(REG_LOW, dreg);
+}
+
+static void bemit_cmovcc(const ir_node *node)
+{
+ const ia32_attr_t *attr = get_ia32_attr_const(node);
+ int ins_permuted = attr->data.ins_permuted;
+ const arch_register_t *out = arch_irn_get_register(node, pn_ia32_res);
+ pn_Cmp pnc = get_ia32_condcode(node);
+ const arch_register_t *in_true;
+ const arch_register_t *in_false;
+
+ pnc = determine_final_pnc(node, n_ia32_CMovcc_eflags, pnc);
+
+ in_true = arch_get_irn_register(get_irn_n(node, n_ia32_CMovcc_val_true));
+ in_false = arch_get_irn_register(get_irn_n(node, n_ia32_CMovcc_val_false));
+
+ /* should be same constraint fullfilled? */
+ if (out == in_false) {
+ /* yes -> nothing to do */
+ } else if (out == in_true) {
+ assert(get_ia32_op_type(node) == ia32_Normal);
+ ins_permuted = !ins_permuted;
+ in_true = in_false;
+ } else {
+ /* we need a mov */
+ bemit8(0x8B); // mov %in_false, %out
+ bemit_modrr(in_false, out);
+ }
+
+ if (ins_permuted)
+ pnc = ia32_get_negated_pnc(pnc);
+
+ /* TODO: handling of Nans isn't correct yet */
+
+ bemit8(0x0F);
+ bemit8(0x40 | pnc2cc(pnc));
+ if (get_ia32_op_type(node) == ia32_Normal) {
+ bemit_modrr(in_true, out);
+ } else {
+ bemit_mod_am(reg_gp_map[out->index], node);
+ }
+}
+
+static void bemit_cmp(const ir_node *node)
+{
+ unsigned ls_size = get_mode_size_bits(get_ia32_ls_mode(node));
+ ir_node *right;
+
+ if (ls_size == 16)
+ bemit8(0x66);
+
+ right = get_irn_n(node, n_ia32_binary_right);
+ if (is_ia32_Immediate(right)) {
+ /* Use in-reg, because some instructions (cmp, test) have no out-reg. */
+ const ir_node *op = get_irn_n(node, n_ia32_binary_right);
+ const ia32_immediate_attr_t *attr = get_ia32_immediate_attr_const(op);
+ unsigned size;
+
+ if (attr->symconst != NULL) {
+ size = 4;
+ } else {
+ /* check for sign extension */
+ size = get_signed_imm_size(attr->offset);
+ }
+
+ switch (size) {
+ case 1:
+ bemit8(0x81 | SIGNEXT_IMM);
+ /* cmp has this special mode */
+ if (get_ia32_op_type(node) == ia32_AddrModeS) {
+ bemit_mod_am(7, node);
+ } else {
+ const arch_register_t *reg = get_in_reg(node, n_ia32_binary_left);
+ bemit_modru(reg, 7);
+ }
+ bemit8((unsigned char)attr->offset);
+ return;
+ case 2:
+ case 4:
+ /* check for eax variant: this variant is shorter for 32bit immediates only */
+ if (get_ia32_op_type(node) == ia32_AddrModeS) {
+ bemit8(0x81);
+ bemit_mod_am(7, node);
+ } else {
+ const arch_register_t *reg = get_in_reg(node, n_ia32_binary_left);
+ if (reg->index == REG_EAX) {
+ bemit8(0x3D);
+ } else {
+ bemit8(0x81);
+ bemit_modru(reg, 7);
+ }
+ }
+ if (ls_size == 16) {
+ bemit16(attr->offset);
+ } else {
+ bemit_entity(attr->symconst, attr->sc_sign, attr->offset, false);
+ }
+ return;
+ }
+ panic("invalid imm size?!?");
+ } else {
+ const arch_register_t *out = get_in_reg(node, n_ia32_binary_left);
+ bemit8(0x3B);
+ if (get_ia32_op_type(node) == ia32_Normal) {
+ const arch_register_t *op2 = get_in_reg(node, n_ia32_binary_right);
+ bemit_modrr(op2, out);
+ } else {
+ bemit_mod_am(reg_gp_map[out->index], node);
+ }
+ }
+}
+
+static void bemit_cmp8bit(const ir_node *node)
+{
+ ir_node *right = get_irn_n(node, n_ia32_binary_right);
+ if (is_ia32_Immediate(right)) {
+ if (get_ia32_op_type(node) == ia32_Normal) {
+ const arch_register_t *out = get_in_reg(node, n_ia32_Cmp_left);
+ if (out->index == REG_EAX) {
+ bemit8(0x3C);
+ } else {
+ bemit8(0x80);
+ bemit_modru(out, 7);
+ }
+ } else {
+ bemit8(0x80);
+ bemit_mod_am(7, node);
+ }
+ bemit8(get_ia32_immediate_attr_const(right)->offset);
+ } else {
+ const arch_register_t *out = get_in_reg(node, n_ia32_Cmp_left);
+ bemit8(0x3A);
+ if (get_ia32_op_type(node) == ia32_Normal) {
+ const arch_register_t *in = get_in_reg(node, n_ia32_Cmp_right);
+ bemit_modrr(out, in);
+ } else {
+ bemit_mod_am(reg_gp_map[out->index], node);
+ }
+ }
+}
+
+static void bemit_test8bit(const ir_node *node)
+{
+ ir_node *right = get_irn_n(node, n_ia32_Test8Bit_right);
+ if (is_ia32_Immediate(right)) {
+ if (get_ia32_op_type(node) == ia32_Normal) {
+ const arch_register_t *out = get_in_reg(node, n_ia32_Test8Bit_left);
+ if (out->index == REG_EAX) {
+ bemit8(0xA8);
+ } else {
+ bemit8(0xF6);
+ bemit_modru(out, 0);
+ }
+ } else {
+ bemit8(0xF6);
+ bemit_mod_am(0, node);
+ }
+ bemit8(get_ia32_immediate_attr_const(right)->offset);
+ } else {
+ const arch_register_t *out = get_in_reg(node, n_ia32_Test8Bit_left);
+ bemit8(0x84);
+ if (get_ia32_op_type(node) == ia32_Normal) {
+ const arch_register_t *in = get_in_reg(node, n_ia32_Test8Bit_right);
+ bemit_modrr(out, in);
+ } else {
+ bemit_mod_am(reg_gp_map[out->index], node);
+ }
+ }
+}
+
+static void bemit_imul(const ir_node *node)
+{
+ ir_node *right = get_irn_n(node, n_ia32_IMul_right);
+ /* Do we need the immediate form? */
+ if (is_ia32_Immediate(right)) {
+ int imm = get_ia32_immediate_attr_const(right)->offset;
+ if (get_signed_imm_size(imm) == 1) {
+ bemit_unop_reg(node, 0x6B, n_ia32_IMul_left);
+ bemit8(imm);
+ } else {
+ bemit_unop_reg(node, 0x69, n_ia32_IMul_left);
+ bemit32(imm);
+ }
+ } else {
+ bemit8(0x0F);
+ bemit_unop_reg(node, 0xAF, n_ia32_IMul_right);
+ }
+}
+
+static void bemit_dec(const ir_node *node)
+{
+ const arch_register_t *out = get_out_reg(node, pn_ia32_Dec_res);
+ bemit8(0x48 + reg_gp_map[out->index]);
+}
+
+static void bemit_inc(const ir_node *node)
+{
+ const arch_register_t *out = get_out_reg(node, pn_ia32_Inc_res);
+ bemit8(0x40 + reg_gp_map[out->index]);
+}
+
+#define UNOPMEM(op, code, ext) \
+static void bemit_##op(const ir_node *node) \
+{ \
+ bemit_unop_mem(node, code, ext); \
+}
+
+UNOPMEM(notmem, 0xF6, 2)
+UNOPMEM(negmem, 0xF6, 3)
+UNOPMEM(incmem, 0xFE, 0)
+UNOPMEM(decmem, 0xFE, 1)
+
+static void bemit_ldtls(const ir_node *node)
+{
+ const arch_register_t *out = get_out_reg(node, 0);