+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);
+ }
+}
+
+static void bemit_cmov(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_CMov_eflags, pnc);
+
+ in_true = arch_get_irn_register(get_irn_n(node, n_ia32_CMov_val_true));
+ in_false = arch_get_irn_register(get_irn_n(node, n_ia32_CMov_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);
+ }
+ }
+}
+