+ mode = get_irn_mode(call_res);
+
+ /* in case there is no memory output: create one to serialize the copy FPU -> SSE */
+ if (! call_mem)
+ call_mem = new_r_Proj(env->irg, env->block, env->irn, mode_M, pn_be_Call_M_regular);
+
+ if (mode_is_float(mode)) {
+ /* store st(0) onto stack */
+ ir_node *frame = get_irg_frame(env->irg);
+ ir_node *fstp = new_rd_ia32_GetST0(env->dbg, env->irg, env->block, frame, call_mem);
+ ir_node *mproj = new_r_Proj(env->irg, env->block, fstp, mode_M, pn_ia32_GetST0_M);
+ entity *ent = frame_alloc_area(get_irg_frame_type(env->irg), get_mode_size_bytes(mode), 16, 0);
+ ir_node *sse_load;
+
+ set_ia32_ls_mode(fstp, mode);
+ set_ia32_op_type(fstp, ia32_AddrModeD);
+ set_ia32_use_frame(fstp);
+ set_ia32_frame_ent(fstp, ent);
+ set_ia32_am_flavour(fstp, ia32_B);
+ set_ia32_am_support(fstp, ia32_am_Dest);
+
+ /* load into SSE register */
+ sse_load = new_rd_ia32_xLoad(env->dbg, env->irg, env->block, frame, ia32_new_NoReg_gp(env->cg), mproj);
+ set_ia32_ls_mode(sse_load, mode);
+ set_ia32_op_type(sse_load, ia32_AddrModeS);
+ set_ia32_use_frame(sse_load);
+ set_ia32_frame_ent(sse_load, ent);
+ set_ia32_am_flavour(sse_load, ia32_B);
+ set_ia32_am_support(sse_load, ia32_am_Source);
+ sse_load = new_r_Proj(env->irg, env->block, sse_load, mode, pn_ia32_xLoad_res);
+
+ /* reroute all users of the result proj to the sse load */
+ edges_reroute(call_res, sse_load, env->irg);
+ }
+
+ return NULL;
+}
+
+/**
+ * In case SSE is used we need to copy the result from XMM0 to FPU TOS before return.
+ */
+static ir_node *gen_be_Return(ia32_transform_env_t *env) {
+ ir_node *ret_val = get_irn_n(env->irn, be_pos_Return_val);
+ ir_node *ret_mem = get_irn_n(env->irn, be_pos_Return_mem);
+ entity *ent = get_irg_entity(get_irn_irg(ret_val));
+ ir_type *tp = get_entity_type(ent);
+
+ if (be_Return_get_n_rets(env->irn) < 1 || ! ret_val || ! USE_SSE2(env->cg))
+ return NULL;
+
+
+ if (get_method_n_ress(tp) == 1) {
+ ir_type *res_type = get_method_res_type(tp, 0);
+ ir_mode *mode;
+
+ if(is_Primitive_type(res_type)) {
+ mode = get_type_mode(res_type);
+ if(mode_is_float(mode)) {
+ ir_node *frame = get_irg_frame(env->irg);
+ entity *ent = frame_alloc_area(get_irg_frame_type(env->irg), get_mode_size_bytes(mode), 16, 0);
+ ir_node *sse_store, *fld, *mproj;
+
+ /* store xmm0 onto stack */
+ sse_store = new_rd_ia32_xStoreSimple(env->dbg, env->irg, env->block, frame, ret_val, ret_mem);
+ set_ia32_ls_mode(sse_store, mode);
+ set_ia32_op_type(sse_store, ia32_AddrModeD);
+ set_ia32_use_frame(sse_store);
+ set_ia32_frame_ent(sse_store, ent);
+ set_ia32_am_flavour(sse_store, ia32_B);
+ set_ia32_am_support(sse_store, ia32_am_Dest);
+ sse_store = new_r_Proj(env->irg, env->block, sse_store, mode_M, pn_ia32_xStore_M);
+
+ /* load into st0 */
+ fld = new_rd_ia32_SetST0(env->dbg, env->irg, env->block, frame, sse_store);
+ set_ia32_ls_mode(fld, mode);
+ set_ia32_op_type(fld, ia32_AddrModeS);
+ set_ia32_use_frame(fld);
+ set_ia32_frame_ent(fld, ent);
+ set_ia32_am_flavour(fld, ia32_B);
+ set_ia32_am_support(fld, ia32_am_Source);
+ mproj = new_r_Proj(env->irg, env->block, fld, mode_M, pn_ia32_SetST0_M);
+ fld = new_r_Proj(env->irg, env->block, fld, mode, pn_ia32_SetST0_res);
+
+ /* set new return value */
+ set_irn_n(env->irn, be_pos_Return_val, fld);
+ set_irn_n(env->irn, be_pos_Return_mem, mproj);
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Transform a be_AddSP into an ia32_AddSP. Eat up const sizes.
+ */
+static ir_node *gen_be_AddSP(ia32_transform_env_t *env) {
+ ir_node *new_op;
+ const ir_edge_t *edge;
+ ir_node *sz = get_irn_n(env->irn, be_pos_AddSP_size);
+ ir_node *sp = get_irn_n(env->irn, be_pos_AddSP_old_sp);
+
+ new_op = new_rd_ia32_AddSP(env->dbg, env->irg, env->block, sp, sz);
+
+ if (is_ia32_Const(sz)) {
+ set_ia32_Immop_attr(new_op, sz);
+ set_irn_n(new_op, 1, ia32_new_NoReg_gp(env->cg));
+ }
+ else if (is_ia32_Load(sz) && get_ia32_am_flavour(sz) == ia32_O) {
+ set_ia32_immop_type(new_op, ia32_ImmSymConst);
+ set_ia32_op_type(new_op, ia32_AddrModeS);
+ set_ia32_am_sc(new_op, get_ia32_am_sc(sz));
+ add_ia32_am_offs(new_op, get_ia32_am_offs(sz));
+ set_irn_n(new_op, 1, ia32_new_NoReg_gp(env->cg));
+ }
+
+ /* fix proj nums */
+ foreach_out_edge(env->irn, edge) {
+ ir_node *proj = get_edge_src_irn(edge);
+
+ assert(is_Proj(proj));
+
+ if (get_Proj_proj(proj) == pn_be_AddSP_res) {
+ /* the node is not yet exchanged: we need to set the register manually */
+ ia32_attr_t *attr = get_ia32_attr(new_op);
+ attr->slots[pn_ia32_AddSP_stack] = &ia32_gp_regs[REG_ESP];
+ set_Proj_proj(proj, pn_ia32_AddSP_stack);
+ }
+ else if (get_Proj_proj(proj) == pn_be_AddSP_M) {
+ set_Proj_proj(proj, pn_ia32_AddSP_M);
+ }
+ else {
+ assert(0);
+ }
+ }
+
+ SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, env->irn));
+
+ return new_op;
+}
+
+/**
+ * This function just sets the register for the Unknown node
+ * as this is not done during register allocation because Unknown
+ * is an "ignore" node.
+ */
+static ir_node *gen_Unknown(ia32_transform_env_t *env) {
+ ir_mode *mode = env->mode;
+ ir_node *irn = env->irn;
+
+ if (mode_is_float(mode)) {
+ if (USE_SSE2(env->cg))
+ arch_set_irn_register(env->cg->arch_env, irn, &ia32_xmm_regs[REG_XMM_UKNWN]);
+ else
+ arch_set_irn_register(env->cg->arch_env, irn, &ia32_vfp_regs[REG_VFP_UKNWN]);
+ }
+ else if (mode_is_int(mode) || mode_is_reference(mode)) {
+ arch_set_irn_register(env->cg->arch_env, irn, &ia32_gp_regs[REG_GP_UKNWN]);
+ }
+ else {
+ assert(0 && "unsupported Unknown-Mode");
+ }
+
+ return NULL;
+}
+
+/**********************************************************************
+ * _ _ _
+ * | | | | | |
+ * | | _____ _____ _ __ ___ __| | _ __ ___ __| | ___ ___
+ * | |/ _ \ \ /\ / / _ \ '__/ _ \/ _` | | '_ \ / _ \ / _` |/ _ \/ __|
+ * | | (_) \ V V / __/ | | __/ (_| | | | | | (_) | (_| | __/\__ \
+ * |_|\___/ \_/\_/ \___|_| \___|\__,_| |_| |_|\___/ \__,_|\___||___/