+
+static void pre_transform_node(ir_node **place, ia32_transform_env_t *env)
+{
+ if (*place == NULL)
+ return;
+
+ *place = transform_node(env, *place);
+}
+
+/**
+ * Transforms all nodes. Deletes the old obstack and creates a new one.
+ */
+static void transform_nodes(ia32_code_gen_t *cg) {
+ int i;
+ ir_graph *irg = cg->irg;
+ ir_node *old_end;
+ ia32_transform_env_t env;
+
+ hook_dead_node_elim(irg, 1);
+
+ inc_irg_visited(irg);
+
+ env.irg = irg;
+ env.cg = cg;
+ env.visited = get_irg_visited(irg);
+ env.worklist = new_pdeq();
+ env.old_anchors = alloca(anchor_max * sizeof(env.old_anchors[0]));
+
+ old_end = get_irg_end(irg);
+
+ /* put all anchor nodes in the worklist */
+ for (i = 0; i < anchor_max; ++i) {
+ ir_node *anchor = irg->anchors[i];
+
+ if (anchor == NULL)
+ continue;
+ pdeq_putr(env.worklist, anchor);
+
+ /* remember anchor */
+ env.old_anchors[i] = anchor;
+ /* and set it to NULL to make sure we don't accidently use it */
+ irg->anchors[i] = NULL;
+ }
+
+ /* pre transform some anchors (so they are available in the other transform
+ * functions) */
+ set_irg_bad(irg, transform_node(&env, env.old_anchors[anchor_bad]));
+ set_irg_no_mem(irg, transform_node(&env, env.old_anchors[anchor_no_mem]));
+ set_irg_start_block(irg, transform_node(&env, env.old_anchors[anchor_start_block]));
+ set_irg_start(irg, transform_node(&env, env.old_anchors[anchor_start]));
+ set_irg_frame(irg, transform_node(&env, env.old_anchors[anchor_frame]));
+
+ pre_transform_node(&cg->unknown_gp, &env);
+ pre_transform_node(&cg->unknown_vfp, &env);
+ pre_transform_node(&cg->unknown_xmm, &env);
+ pre_transform_node(&cg->noreg_gp, &env);
+ pre_transform_node(&cg->noreg_vfp, &env);
+ pre_transform_node(&cg->noreg_xmm, &env);
+
+ /* process worklist (this should transform all nodes in the graph) */
+ while (! pdeq_empty(env.worklist)) {
+ ir_node *node = pdeq_getl(env.worklist);
+ transform_node(&env, node);
+ }
+
+ /* fix loops and set new anchors*/
+ inc_irg_visited(irg);
+ for (i = 0; i < anchor_max; ++i) {
+ ir_node *anchor = env.old_anchors[i];
+
+ if (anchor == NULL)
+ continue;
+
+ anchor = get_irn_link(anchor);
+ fix_loops(&env, anchor);
+ assert(irg->anchors[i] == NULL || irg->anchors[i] == anchor);
+ irg->anchors[i] = anchor;
+ }
+
+ del_pdeq(env.worklist);
+ free_End(old_end);
+ hook_dead_node_elim(irg, 0);
+}
+
+void ia32_transform_graph(ia32_code_gen_t *cg)
+{
+ ir_graph *irg = cg->irg;
+ be_irg_t *birg = cg->birg;
+ ir_graph *old_current_ir_graph = current_ir_graph;
+ int old_interprocedural_view = get_interprocedural_view();
+ struct obstack *old_obst = NULL;
+ struct obstack *new_obst = NULL;
+
+ current_ir_graph = irg;
+ set_interprocedural_view(0);
+ register_transformers();
+
+ /* most analysis info is wrong after transformation */
+ free_callee_info(irg);
+ free_irg_outs(irg);
+ irg->outs_state = outs_none;
+ free_trouts();
+ free_loop_information(irg);
+ set_irg_doms_inconsistent(irg);
+ be_invalidate_liveness(birg);
+ be_invalidate_dom_front(birg);
+
+ /* create a new obstack */
+ old_obst = irg->obst;
+ new_obst = xmalloc(sizeof(*new_obst));
+ obstack_init(new_obst);
+ irg->obst = new_obst;
+ irg->last_node_idx = 0;
+
+ /* create new value table for CSE */
+ del_identities(irg->value_table);
+ irg->value_table = new_identities();
+
+ /* do the main transformation */
+ transform_nodes(cg);
+
+ /* we don't want the globals anchor anymore */
+ set_irg_globals(irg, new_r_Bad(irg));
+
+ /* free the old obstack */
+ obstack_free(old_obst, 0);
+ xfree(old_obst);
+
+ /* restore state */
+ current_ir_graph = old_current_ir_graph;
+ set_interprocedural_view(old_interprocedural_view);
+
+ /* recalculate edges */
+ edges_deactivate(irg);
+ edges_activate(irg);
+}
+
+/**
+ * Transforms a psi condition.
+ */
+static void transform_psi_cond(ir_node *cond, ir_mode *mode, ia32_code_gen_t *cg) {
+ int i;
+
+ /* if the mode is target mode, we have already seen this part of the tree */
+ if (get_irn_mode(cond) == mode)
+ return;
+
+ assert(get_irn_mode(cond) == mode_b && "logical operator for condition must be mode_b");
+
+ set_irn_mode(cond, mode);
+
+ for (i = get_irn_arity(cond) - 1; i >= 0; i--) {
+ ir_node *in = get_irn_n(cond, i);
+
+ /* if in is a compare: transform into Set/xCmp */
+ if (is_Proj(in)) {
+ ir_node *new_op = NULL;
+ ir_node *cmp = get_Proj_pred(in);
+ ir_node *cmp_a = get_Cmp_left(cmp);
+ ir_node *cmp_b = get_Cmp_right(cmp);
+ dbg_info *dbgi = get_irn_dbg_info(cmp);
+ ir_graph *irg = get_irn_irg(cmp);
+ ir_node *block = get_nodes_block(cmp);
+ ir_node *noreg = ia32_new_NoReg_gp(cg);
+ ir_node *nomem = new_rd_NoMem(irg);
+ int pnc = get_Proj_proj(in);
+
+ /* this is a compare */
+ if (mode_is_float(mode)) {
+ /* Psi is float, we need a floating point compare */
+
+ if (USE_SSE2(cg)) {
+ ir_mode *m = get_irn_mode(cmp_a);
+ /* SSE FPU */
+ if (! mode_is_float(m)) {
+ cmp_a = gen_sse_conv_int2float(cg, dbgi, irg, block, cmp_a, cmp_a, mode);
+ cmp_b = gen_sse_conv_int2float(cg, dbgi, irg, block, cmp_b, cmp_b, mode);
+ } else if (m == mode_F) {
+ /* we convert cmp values always to double, to get correct bitmask with cmpsd */
+ cmp_a = gen_sse_conv_f2d(cg, dbgi, irg, block, cmp_a, cmp_a);
+ cmp_b = gen_sse_conv_f2d(cg, dbgi, irg, block, cmp_b, cmp_b);
+ }
+
+ new_op = new_rd_ia32_xCmp(dbgi, irg, block, noreg, noreg, cmp_a, cmp_b, nomem);
+ set_ia32_pncode(new_op, pnc);
+ SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(cg, cmp));
+ } else {
+ /* x87 FPU */
+ assert(0);
+ }
+ } else {
+ /* integer Psi */
+ construct_binop_func *set_func = NULL;
+
+ if (mode_is_float(get_irn_mode(cmp_a))) {
+ /* 1st case: compare operands are floats */
+ FP_USED(cg);
+
+ if (USE_SSE2(cg)) {
+ /* SSE FPU */
+ set_func = new_rd_ia32_xCmpSet;
+ } else {
+ /* x87 FPU */
+ set_func = new_rd_ia32_vfCmpSet;
+ }
+
+ pnc &= 7; /* fp compare -> int compare */
+ } else {
+ /* 2nd case: compare operand are integer too */
+ set_func = new_rd_ia32_CmpSet;
+ }
+
+ new_op = set_func(dbgi, irg, block, noreg, noreg, cmp_a, cmp_b, nomem);
+ if (! mode_is_signed(mode))
+ pnc |= ia32_pn_Cmp_Unsigned;
+
+ set_ia32_pncode(new_op, pnc);
+ set_ia32_am_support(new_op, ia32_am_Source);
+ }
+
+ /* the the new compare as in */
+ set_irn_n(cond, i, new_op);
+ } else {
+ /* another complex condition */
+ transform_psi_cond(in, mode, cg);
+ }
+ }
+}
+
+/**
+ * The Psi selector can be a tree of compares combined with "And"s and "Or"s.
+ * We create a Set node, respectively a xCmp in case the Psi is a float, for
+ * each compare, which causes the compare result to be stored in a register. The
+ * "And"s and "Or"s are transformed later, we just have to set their mode right.
+ */
+void ia32_transform_psi_cond_tree(ir_node *node, void *env) {
+ ia32_code_gen_t *cg = env;
+ ir_node *psi_sel, *new_cmp, *block;
+ ir_graph *irg;
+ ir_mode *mode;
+
+ /* check for Psi */
+ if (get_irn_opcode(node) != iro_Psi)
+ return;
+
+ psi_sel = get_Psi_cond(node, 0);
+
+ /* if psi_cond is a cmp: do nothing, this case is covered by gen_Psi */
+ if (is_Proj(psi_sel)) {
+ assert(is_Cmp(get_Proj_pred(psi_sel)));
+ return;
+ }
+
+ //mode = get_irn_mode(node);
+ // TODO probably wrong...
+ mode = mode_Iu;
+
+ transform_psi_cond(psi_sel, mode, cg);
+
+ irg = get_irn_irg(node);
+ block = get_nodes_block(node);
+
+ /* we need to compare the evaluated condition tree with 0 */
+ mode = get_irn_mode(node);
+ if (mode_is_float(mode)) {
+ /* BEWARE: new_r_Const_long works for floating point as well */
+ ir_node *zero = new_r_Const_long(irg, block, mode, 0);
+
+ psi_sel = gen_sse_conv_int2float(cg, NULL, irg, block, psi_sel, NULL, mode);
+ new_cmp = new_r_Cmp(irg, block, psi_sel, zero);
+ new_cmp = new_r_Proj(irg, block, new_cmp, mode_b, pn_Cmp_Ne);
+ } else {
+ ir_node *zero = new_r_Const_long(irg, block, mode_Iu, 0);
+ new_cmp = new_r_Cmp(irg, block, psi_sel, zero);
+ new_cmp = new_r_Proj(irg, block, new_cmp, mode_b, pn_Cmp_Gt | pn_Cmp_Lt);
+ }
+
+ set_Psi_cond(node, 0, new_cmp);
+}
+
+void ia32_init_transform(void)
+{
+ FIRM_DBG_REGISTER(dbg, "firm.be.ia32.transform");
+}