+ ir_graph *irg;
+ ir_mode *mode;
+ ir_node *block, *noreg, *nomem;
+ int pnc;
+
+ /* we cannot invert non-ia32 irns */
+ if (! is_ia32_irn(irn))
+ return NULL;
+
+ /* operand must always be a real operand (not base, index or mem) */
+ if (i != 2 && i != 3)
+ return NULL;
+
+ /* we don't invert address mode operations */
+ if (get_ia32_op_type(irn) != ia32_Normal)
+ return NULL;
+
+ irg = get_irn_irg(irn);
+ block = get_nodes_block(irn);
+ mode = get_ia32_res_mode(irn);
+ noreg = get_irn_n(irn, 0);
+ nomem = new_r_NoMem(irg);
+
+ /* initialize structure */
+ inverse->nodes = obstack_alloc(obst, 2 * sizeof(inverse->nodes[0]));
+ inverse->costs = 0;
+ inverse->n = 2;
+
+ switch (get_ia32_irn_opcode(irn)) {
+ case iro_ia32_Add:
+ if (get_ia32_immop_type(irn) == ia32_ImmConst) {
+ /* we have an add with a const here */
+ /* invers == add with negated const */
+ inverse->nodes[0] = new_rd_ia32_Add(NULL, irg, block, noreg, noreg, get_irn_n(irn, i), noreg, nomem);
+ pnc = pn_ia32_Add_res;
+ inverse->costs += 1;
+ copy_ia32_Immop_attr(inverse->nodes[0], (ir_node *)irn);
+ set_ia32_Immop_tarval(inverse->nodes[0], tarval_neg(get_ia32_Immop_tarval(irn)));
+ set_ia32_commutative(inverse->nodes[0]);
+ }
+ else if (get_ia32_immop_type(irn) == ia32_ImmSymConst) {
+ /* we have an add with a symconst here */
+ /* invers == sub with const */
+ inverse->nodes[0] = new_rd_ia32_Sub(NULL, irg, block, noreg, noreg, get_irn_n(irn, i), noreg, nomem);
+ pnc = pn_ia32_Sub_res;
+ inverse->costs += 2;
+ copy_ia32_Immop_attr(inverse->nodes[0], (ir_node *)irn);
+ }
+ else {
+ /* normal add: inverse == sub */
+ ir_node *proj = ia32_get_res_proj(irn);
+ assert(proj);
+
+ inverse->nodes[0] = new_rd_ia32_Sub(NULL, irg, block, noreg, noreg, proj, get_irn_n(irn, i ^ 1), nomem);
+ pnc = pn_ia32_Sub_res;
+ inverse->costs += 2;
+ }
+ break;
+ case iro_ia32_Sub:
+ if (get_ia32_immop_type(irn) != ia32_ImmNone) {
+ /* we have a sub with a const/symconst here */
+ /* invers == add with this const */
+ inverse->nodes[0] = new_rd_ia32_Add(NULL, irg, block, noreg, noreg, get_irn_n(irn, i), noreg, nomem);
+ pnc = pn_ia32_Add_res;
+ inverse->costs += (get_ia32_immop_type(irn) == ia32_ImmSymConst) ? 5 : 1;
+ copy_ia32_Immop_attr(inverse->nodes[0], (ir_node *)irn);
+ }
+ else {
+ /* normal sub */
+ ir_node *proj = ia32_get_res_proj(irn);
+ assert(proj);
+
+ if (i == 2) {
+ inverse->nodes[0] = new_rd_ia32_Add(NULL, irg, block, noreg, noreg, proj, get_irn_n(irn, 3), nomem);
+ }
+ else {
+ inverse->nodes[0] = new_rd_ia32_Sub(NULL, irg, block, noreg, noreg, get_irn_n(irn, 2), proj, nomem);
+ }
+ pnc = pn_ia32_Sub_res;
+ inverse->costs += 1;
+ }
+ break;
+ case iro_ia32_Eor:
+ if (get_ia32_immop_type(irn) != ia32_ImmNone) {
+ /* xor with const: inverse = xor */
+ inverse->nodes[0] = new_rd_ia32_Eor(NULL, irg, block, noreg, noreg, get_irn_n(irn, i), noreg, nomem);
+ pnc = pn_ia32_Eor_res;
+ inverse->costs += (get_ia32_immop_type(irn) == ia32_ImmSymConst) ? 5 : 1;
+ copy_ia32_Immop_attr(inverse->nodes[0], (ir_node *)irn);
+ }
+ else {
+ /* normal xor */
+ inverse->nodes[0] = new_rd_ia32_Eor(NULL, irg, block, noreg, noreg, (ir_node *)irn, get_irn_n(irn, i), nomem);
+ pnc = pn_ia32_Eor_res;
+ inverse->costs += 1;
+ }
+ break;
+ case iro_ia32_Not: {
+ ir_node *proj = ia32_get_res_proj(irn);
+ assert(proj);
+
+ inverse->nodes[0] = new_rd_ia32_Not(NULL, irg, block, noreg, noreg, proj, nomem);
+ pnc = pn_ia32_Not_res;
+ inverse->costs += 1;
+ break;
+ }
+ case iro_ia32_Minus: {
+ ir_node *proj = ia32_get_res_proj(irn);
+ assert(proj);
+
+ inverse->nodes[0] = new_rd_ia32_Minus(NULL, irg, block, noreg, noreg, proj, nomem);
+ pnc = pn_ia32_Minus_res;
+ inverse->costs += 1;
+ break;
+ }
+ default:
+ /* inverse operation not supported */
+ return NULL;
+ }
+
+ set_ia32_res_mode(inverse->nodes[0], mode);
+ inverse->nodes[1] = new_r_Proj(irg, block, inverse->nodes[0], mode, pnc);
+
+ return inverse;
+}
+
+/**
+ * Check if irn can load it's operand at position i from memory (source addressmode).
+ * @param self Pointer to irn ops itself
+ * @param irn The irn to be checked
+ * @param i The operands position
+ * @return Non-Zero if operand can be loaded
+ */
+static int ia32_possible_memory_operand(const void *self, const ir_node *irn, unsigned int i) {
+ if (! is_ia32_irn(irn) || /* must be an ia32 irn */
+ get_irn_arity(irn) != 5 || /* must be a binary operation */
+ get_ia32_op_type(irn) != ia32_Normal || /* must not already be a addressmode irn */
+ ! (get_ia32_am_support(irn) & ia32_am_Source) || /* must be capable of source addressmode */
+ (i != 2 && i != 3) || /* a "real" operand position must be requested */
+ (i == 2 && ! is_ia32_commutative(irn)) || /* if first operand requested irn must be commutative */
+ is_ia32_use_frame(irn)) /* must not already use frame */
+ return 0;
+
+ return 1;
+}
+
+static void ia32_perform_memory_operand(const void *self, ir_node *irn, ir_node *spill, unsigned int i) {
+ const ia32_irn_ops_t *ops = self;
+ ia32_code_gen_t *cg = ops->cg;
+
+ assert(ia32_possible_memory_operand(self, irn, i) && "Cannot perform memory operand change");
+
+ if (i == 2) {
+ ir_node *tmp = get_irn_n(irn, 3);
+ set_irn_n(irn, 3, get_irn_n(irn, 2));
+ set_irn_n(irn, 2, tmp);
+ }
+
+ set_ia32_am_support(irn, ia32_am_Source);
+ set_ia32_op_type(irn, ia32_AddrModeS);
+ set_ia32_am_flavour(irn, ia32_B);
+ set_ia32_ls_mode(irn, get_irn_mode(get_irn_n(irn, i)));
+ set_ia32_use_frame(irn);
+ set_ia32_got_reload(irn);
+
+ set_irn_n(irn, 0, get_irg_frame(get_irn_irg(irn)));
+ set_irn_n(irn, 4, spill);
+
+ /*
+ Input at position one is index register, which is NoReg.
+ We would need cg object to get a real noreg, but we cannot
+ access it from here.
+ */
+ set_irn_n(irn, 3, ia32_get_admissible_noreg(cg, irn, 3));
+
+ //FIXME DBG_OPT_AM_S(reload, irn);