/*
- * Copyright (C) 1995-2007 University of Karlsruhe. All right reserved.
+ * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
*
* This file is part of libFirm.
*
#include "../beutil.h"
#include "../beirg_t.h"
#include "../betranshlp.h"
+#include "../be_t.h"
#include "bearch_ia32_t.h"
#include "ia32_nodes_attr.h"
ir_node *new_node;
ir_mode *mode;
ir_node *sign_extension;
- int has_exc;
ia32_address_mode_t am;
ia32_address_t *addr = &am.addr;
/* the upper bits have random contents for smaller modes */
- has_exc = 0;
switch (get_irn_opcode(node)) {
case iro_Div:
op1 = get_Div_left(node);
op2 = get_Div_right(node);
mem = get_Div_mem(node);
mode = get_Div_resmode(node);
- has_exc = be_get_Proj_for_pn(node, pn_Div_X_except) != NULL;
break;
case iro_Mod:
op1 = get_Mod_left(node);
op2 = get_Mod_right(node);
mem = get_Mod_mem(node);
mode = get_Mod_resmode(node);
- has_exc = be_get_Proj_for_pn(node, pn_Mod_X_except) != NULL;
break;
case iro_DivMod:
op1 = get_DivMod_left(node);
op2 = get_DivMod_right(node);
mem = get_DivMod_mem(node);
mode = get_DivMod_resmode(node);
- has_exc = be_get_Proj_for_pn(node, pn_DivMod_X_except) != NULL;
break;
default:
panic("invalid divmod node %+F", node);
match_arguments(&am, block, op1, op2, NULL, match_am);
- if(!is_NoMem(mem)) {
+ /* Beware: We don't need a Sync, if the memory predecessor of the Div node
+ is the memory of the consumed address. We can have only the second op as address
+ in Div nodes, so check only op2. */
+ if(!is_NoMem(mem) && skip_Proj(mem) != skip_Proj(op2)) {
new_mem = be_transform_node(mem);
if(!is_NoMem(addr->mem)) {
ir_node *in[2];
sign_extension, am.new_op2);
}
- set_ia32_exc_label(new_node, has_exc);
set_irn_pinned(new_node, get_irn_pinned(node));
set_am_attributes(new_node, &am);
add_irn_dep(new_node, get_irg_frame(irg));
}
- set_ia32_exc_label(new_node,
- be_get_Proj_for_pn(node, pn_Load_X_except) != NULL);
SET_IA32_ORIG_NODE(new_node, ia32_get_old_node_name(env_cg, node));
return new_node;
ir_node *mem = get_Store_mem(node);
ir_node *ptr = get_Store_ptr(node);
ir_mode *mode = get_irn_mode(val);
- int bits = get_mode_size_bits(mode);
+ unsigned bits = get_mode_size_bits(mode);
ir_node *op1;
ir_node *op2;
ir_node *new_node;
set_ia32_op_type(new_node, ia32_AddrModeD);
set_ia32_ls_mode(new_node, mode);
- set_ia32_exc_label(new_node,
- be_get_Proj_for_pn(node, pn_Store_X_except) != NULL);
set_address(new_node, &addr);
SET_IA32_ORIG_NODE(new_node, ia32_get_old_node_name(env_cg, node));
ir_node *res = NULL;
if (src_mode == mode_b) {
- assert(mode_is_int(tgt_mode));
+ assert(mode_is_int(tgt_mode) || mode_is_reference(tgt_mode));
/* nothing to do, we already model bools as 0/1 ints */
return be_transform_node(op);
}
/* a memory constraint: no need to do anything in backend about it
* (the dependencies are already respected by the memory edge of
* the node) */
- constraint->req = &no_register_req;
+ constraint->req = &no_register_req;
return;
}
}
static void parse_clobber(ir_node *node, int pos, constraint_t *constraint,
- const char *c)
+ const char *clobber)
{
- (void) node;
+ ir_graph *irg = get_irn_irg(node);
+ struct obstack *obst = get_irg_obstack(irg);
+ const arch_register_t *reg = NULL;
+ int c;
+ size_t r;
+ arch_register_req_t *req;
+ const arch_register_class_t *cls;
+ unsigned *limited;
+
(void) pos;
- (void) constraint;
- (void) c;
- panic("Clobbers not supported yet");
+
+ /* TODO: construct a hashmap instead of doing linear search for clobber
+ * register */
+ for(c = 0; c < N_CLASSES; ++c) {
+ cls = & ia32_reg_classes[c];
+ for(r = 0; r < cls->n_regs; ++r) {
+ const arch_register_t *temp_reg = arch_register_for_index(cls, r);
+ if(strcmp(temp_reg->name, clobber) == 0
+ || (c == CLASS_ia32_gp && strcmp(temp_reg->name+1, clobber) == 0)) {
+ reg = temp_reg;
+ break;
+ }
+ }
+ if(reg != NULL)
+ break;
+ }
+ if(reg == NULL) {
+ panic("Register '%s' mentioned in asm clobber is unknown\n", clobber);
+ return;
+ }
+
+ assert(reg->index < 32);
+
+ limited = obstack_alloc(obst, sizeof(limited[0]));
+ *limited = 1 << reg->index;
+
+ req = obstack_alloc(obst, sizeof(req[0]));
+ memset(req, 0, sizeof(req[0]));
+ req->type = arch_register_req_type_limited;
+ req->cls = cls;
+ req->limited = limited;
+
+ constraint->req = req;
+ constraint->immediate_possible = 0;
+ constraint->immediate_type = 0;
}
static int is_memory_op(const ir_asm_constraint *constraint)
n_out_constraints = get_ASM_n_output_constraints(node);
n_clobbers = get_ASM_n_clobbers(node);
out_arity = n_out_constraints + n_clobbers;
+ /* hack to keep space for mem proj */
+ if(n_clobbers > 0)
+ out_arity += 1;
in_constraints = get_ASM_input_constraints(node);
out_constraints = get_ASM_output_constraints(node);
if(constraint->pos > reg_map_size)
reg_map_size = constraint->pos;
- } else {
+
+ out_reg_reqs[i] = parsed_constraint.req;
+ } else if(i < out_arity - 1) {
ident *glob_id = clobbers [i - n_out_constraints];
+ assert(glob_id != NULL);
c = get_id_str(glob_id);
parse_clobber(node, i, &parsed_constraint, c);
- }
- out_reg_reqs[i] = parsed_constraint.req;
+ out_reg_reqs[i+1] = parsed_constraint.req;
+ }
}
+ if(n_clobbers > 1)
+ out_reg_reqs[n_out_constraints] = &no_register_req;
/* construct input constraints */
in_reg_reqs = obstack_alloc(obst, arity * sizeof(in_reg_reqs[0]));
return gen_lowered_64bit_shifts(node, high, low, count);
}
-/**
- * In case SSE Unit is used, the node is transformed into a vfst + xLoad.
- */
-static ir_node *gen_ia32_l_X87toSSE(ir_node *node) {
- ir_node *block = be_transform_node(get_nodes_block(node));
- ir_node *val = get_irn_n(node, 1);
- ir_node *new_val = be_transform_node(val);
- ir_node *res = NULL;
- ir_graph *irg = current_ir_graph;
- dbg_info *dbgi;
- ir_node *noreg, *new_ptr, *new_mem;
- ir_node *ptr, *mem;
+static ir_node *gen_ia32_l_LLtoFloat(ir_node *node) {
+ ir_node *src_block = get_nodes_block(node);
+ ir_node *block = be_transform_node(src_block);
+ ir_graph *irg = current_ir_graph;
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_node *frame = get_irg_frame(irg);
+ ir_node *noreg = ia32_new_NoReg_gp(env_cg);
+ ir_node *nomem = new_NoMem();
+ ir_node *val_low = get_irn_n(node, n_ia32_l_LLtoFloat_val_low);
+ ir_node *val_high = get_irn_n(node, n_ia32_l_LLtoFloat_val_high);
+ ir_node *new_val_low = be_transform_node(val_low);
+ ir_node *new_val_high = be_transform_node(val_high);
+ ir_node *in[2];
+ ir_node *sync;
+ ir_node *fild;
+ ir_node *store_low;
+ ir_node *store_high;
- if (ia32_cg_config.use_sse2) {
- return new_val;
- }
-
- mem = get_irn_n(node, 2);
- new_mem = be_transform_node(mem);
- ptr = get_irn_n(node, 0);
- new_ptr = be_transform_node(ptr);
- noreg = ia32_new_NoReg_gp(env_cg);
- dbgi = get_irn_dbg_info(node);
-
- /* Store x87 -> MEM */
- res = new_rd_ia32_vfst(dbgi, irg, block, new_ptr, noreg, new_mem, new_val,
- get_ia32_ls_mode(node));
- set_ia32_frame_ent(res, get_ia32_frame_ent(node));
- set_ia32_use_frame(res);
- set_ia32_ls_mode(res, get_ia32_ls_mode(node));
- set_ia32_op_type(res, ia32_AddrModeD);
-
- /* Load MEM -> SSE */
- res = new_rd_ia32_xLoad(dbgi, irg, block, new_ptr, noreg, res,
- get_ia32_ls_mode(node));
- set_ia32_frame_ent(res, get_ia32_frame_ent(node));
- set_ia32_use_frame(res);
- set_ia32_op_type(res, ia32_AddrModeS);
- res = new_rd_Proj(dbgi, irg, block, res, mode_xmm, pn_ia32_xLoad_res);
+ if(!mode_is_signed(get_irn_mode(val_high))) {
+ panic("unsigned long long -> float not supported yet (%+F)", node);
+ }
- return res;
+ /* do a store */
+ store_low = new_rd_ia32_Store(dbgi, irg, block, frame, noreg, nomem,
+ new_val_low);
+ store_high = new_rd_ia32_Store(dbgi, irg, block, frame, noreg, nomem,
+ new_val_high);
+ SET_IA32_ORIG_NODE(store_low, ia32_get_old_node_name(env_cg, node));
+ SET_IA32_ORIG_NODE(store_high, ia32_get_old_node_name(env_cg, node));
+
+ set_ia32_use_frame(store_low);
+ set_ia32_use_frame(store_high);
+ set_ia32_op_type(store_low, ia32_AddrModeD);
+ set_ia32_op_type(store_high, ia32_AddrModeD);
+ set_ia32_ls_mode(store_low, mode_Iu);
+ set_ia32_ls_mode(store_high, mode_Is);
+ add_ia32_am_offs_int(store_high, 4);
+
+ in[0] = store_low;
+ in[1] = store_high;
+ sync = new_rd_Sync(dbgi, irg, block, 2, in);
+
+ /* do a fild */
+ fild = new_rd_ia32_vfild(dbgi, irg, block, frame, noreg, sync);
+
+ set_ia32_use_frame(fild);
+ set_ia32_op_type(fild, ia32_AddrModeS);
+ set_ia32_ls_mode(fild, mode_Ls);
+
+ SET_IA32_ORIG_NODE(fild, ia32_get_old_node_name(env_cg, node));
+
+ return new_r_Proj(irg, block, fild, mode_vfp, pn_ia32_vfild_res);
}
-/**
- * In case SSE Unit is used, the node is transformed into a xStore + vfld.
- */
-static ir_node *gen_ia32_l_SSEtoX87(ir_node *node) {
- ir_node *block = be_transform_node(get_nodes_block(node));
- ir_node *val = get_irn_n(node, 1);
- ir_node *new_val = be_transform_node(val);
- ir_graph *irg = current_ir_graph;
- ir_node *res = NULL;
- ir_entity *fent = get_ia32_frame_ent(node);
- ir_mode *lsmode = get_ia32_ls_mode(node);
- int offs = 0;
- ir_node *noreg, *new_ptr, *new_mem;
- ir_node *ptr, *mem;
- dbg_info *dbgi;
-
- if (! ia32_cg_config.use_sse2) {
- /* SSE unit is not used -> skip this node. */
- return new_val;
- }
-
- ptr = get_irn_n(node, 0);
- new_ptr = be_transform_node(ptr);
- mem = get_irn_n(node, 2);
- new_mem = be_transform_node(mem);
- noreg = ia32_new_NoReg_gp(env_cg);
- dbgi = get_irn_dbg_info(node);
-
- /* Store SSE -> MEM */
- if (is_ia32_xLoad(skip_Proj(new_val))) {
- ir_node *ld = skip_Proj(new_val);
-
- /* we can vfld the value directly into the fpu */
- fent = get_ia32_frame_ent(ld);
- ptr = get_irn_n(ld, 0);
- offs = get_ia32_am_offs_int(ld);
- } else {
- res = new_rd_ia32_xStore(dbgi, irg, block, new_ptr, noreg, new_mem,
- new_val);
- set_ia32_frame_ent(res, fent);
- set_ia32_use_frame(res);
- set_ia32_ls_mode(res, lsmode);
- set_ia32_op_type(res, ia32_AddrModeD);
- mem = res;
- }
-
- /* Load MEM -> x87 */
- res = new_rd_ia32_vfld(dbgi, irg, block, new_ptr, noreg, new_mem, lsmode);
- set_ia32_frame_ent(res, fent);
- set_ia32_use_frame(res);
- add_ia32_am_offs_int(res, offs);
- set_ia32_op_type(res, ia32_AddrModeS);
- res = new_rd_Proj(dbgi, irg, block, res, mode_vfp, pn_ia32_vfld_res);
+static ir_node *gen_ia32_l_FloattoLL(ir_node *node) {
+ ir_node *src_block = get_nodes_block(node);
+ ir_node *block = be_transform_node(src_block);
+ ir_graph *irg = current_ir_graph;
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_node *frame = get_irg_frame(irg);
+ ir_node *noreg = ia32_new_NoReg_gp(env_cg);
+ ir_node *nomem = new_NoMem();
+ ir_node *val = get_irn_n(node, n_ia32_l_FloattoLL_val);
+ ir_node *new_val = be_transform_node(val);
+ ir_node *trunc_mode = ia32_new_Fpu_truncate(env_cg);
- return res;
+ ir_node *fist;
+
+ /* do a fist */
+ fist = new_rd_ia32_vfist(dbgi, irg, block, frame, noreg, nomem, new_val,
+ trunc_mode);
+ SET_IA32_ORIG_NODE(fist, ia32_get_old_node_name(env_cg, node));
+ set_ia32_use_frame(fist);
+ set_ia32_op_type(fist, ia32_AddrModeD);
+ set_ia32_ls_mode(fist, mode_Ls);
+
+ return fist;
}
/**
return NULL;
}
+static ir_node *gen_Proj_l_FloattoLL(ir_node *node) {
+ ir_graph *irg = current_ir_graph;
+ ir_node *block = be_transform_node(get_nodes_block(node));
+ ir_node *pred = get_Proj_pred(node);
+ ir_node *new_pred = be_transform_node(pred);
+ ir_node *frame = get_irg_frame(irg);
+ ir_node *noreg = ia32_new_NoReg_gp(env_cg);
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ long pn = get_Proj_proj(node);
+ ir_node *load;
+ ir_node *proj;
+ ia32_attr_t *attr;
+
+ load = new_rd_ia32_Load(dbgi, irg, block, frame, noreg, new_pred);
+ SET_IA32_ORIG_NODE(load, ia32_get_old_node_name(env_cg, node));
+ set_ia32_use_frame(load);
+ set_ia32_op_type(load, ia32_AddrModeS);
+ set_ia32_ls_mode(load, mode_Iu);
+ /* we need a 64bit stackslot (fist stores 64bit) even though we only load
+ * 32 bit from it with this particular load */
+ attr = get_ia32_attr(load);
+ attr->data.need_64bit_stackent = 1;
+
+ if (pn == pn_ia32_l_FloattoLL_res_high) {
+ add_ia32_am_offs_int(load, 4);
+ } else {
+ assert(pn == pn_ia32_l_FloattoLL_res_low);
+ }
+
+ proj = new_r_Proj(irg, block, load, mode_Iu, pn_ia32_Load_res);
+
+ return proj;
+}
+
/**
* Transform the Projs of an AddSP.
*/
/* renumber the proj */
new_pred = be_transform_node(pred);
if (is_ia32_Load(new_pred)) {
- if (proj == pn_Load_res) {
- return new_rd_Proj(dbgi, irg, block, new_pred, mode_Iu,
- pn_ia32_Load_res);
- } else if (proj == pn_Load_M) {
- return new_rd_Proj(dbgi, irg, block, new_pred, mode_M,
- pn_ia32_Load_M);
+ switch (proj) {
+ case pn_Load_res:
+ return new_rd_Proj(dbgi, irg, block, new_pred, mode_Iu, pn_ia32_Load_res);
+ case pn_Load_M:
+ return new_rd_Proj(dbgi, irg, block, new_pred, mode_M, pn_ia32_Load_M);
+ case pn_Load_X_regular:
+ return new_rd_Jmp(dbgi, irg, block);
+ case pn_Load_X_except:
+ /* This Load might raise an exception. Mark it. */
+ set_ia32_exc_label(new_pred, 1);
+ return new_rd_Proj(dbgi, irg, block, new_pred, mode_X, pn_ia32_Load_X_exc);
+ default:
+ break;
}
- } else if(is_ia32_Conv_I2I(new_pred)
- || is_ia32_Conv_I2I8Bit(new_pred)) {
+ } else if (is_ia32_Conv_I2I(new_pred) ||
+ is_ia32_Conv_I2I8Bit(new_pred)) {
set_irn_mode(new_pred, mode_T);
if (proj == pn_Load_res) {
return new_rd_Proj(dbgi, irg, block, new_pred, mode_Iu, pn_ia32_res);
return new_rd_Proj(dbgi, irg, block, new_pred, mode_M, pn_ia32_mem);
}
} else if (is_ia32_xLoad(new_pred)) {
- if (proj == pn_Load_res) {
- return new_rd_Proj(dbgi, irg, block, new_pred, mode_xmm,
- pn_ia32_xLoad_res);
- } else if (proj == pn_Load_M) {
- return new_rd_Proj(dbgi, irg, block, new_pred, mode_M,
- pn_ia32_xLoad_M);
+ switch (proj) {
+ case pn_Load_res:
+ return new_rd_Proj(dbgi, irg, block, new_pred, mode_xmm, pn_ia32_xLoad_res);
+ case pn_Load_M:
+ return new_rd_Proj(dbgi, irg, block, new_pred, mode_M, pn_ia32_xLoad_M);
+ case pn_Load_X_regular:
+ return new_rd_Jmp(dbgi, irg, block);
+ case pn_Load_X_except:
+ /* This Load might raise an exception. Mark it. */
+ set_ia32_exc_label(new_pred, 1);
+ return new_rd_Proj(dbgi, irg, block, new_pred, mode_X, pn_ia32_xLoad_X_exc);
+ default:
+ break;
}
} else if (is_ia32_vfld(new_pred)) {
- if (proj == pn_Load_res) {
- return new_rd_Proj(dbgi, irg, block, new_pred, mode_vfp,
- pn_ia32_vfld_res);
- } else if (proj == pn_Load_M) {
- return new_rd_Proj(dbgi, irg, block, new_pred, mode_M,
- pn_ia32_vfld_M);
+ switch (proj) {
+ case pn_Load_res:
+ return new_rd_Proj(dbgi, irg, block, new_pred, mode_vfp, pn_ia32_vfld_res);
+ case pn_Load_M:
+ return new_rd_Proj(dbgi, irg, block, new_pred, mode_M, pn_ia32_vfld_M);
+ case pn_Load_X_regular:
+ return new_rd_Jmp(dbgi, irg, block);
+ case pn_Load_X_except:
+ /* This Load might raise an exception. Mark it. */
+ set_ia32_exc_label(new_pred, 1);
+ return new_rd_Proj(dbgi, irg, block, new_pred, mode_X, pn_ia32_xLoad_X_exc);
+ default:
+ break;
}
} else {
/* can happen for ProJMs when source address mode happened for the
/* however it should not be the result proj, as that would mean the
load had multiple users and should not have been used for
SourceAM */
- if(proj != pn_Load_M) {
+ if (proj != pn_Load_M) {
panic("internal error: transformed node not a Load");
}
return new_rd_Proj(dbgi, irg, block, new_pred, mode_M, 1);
return new_rd_Proj(dbgi, irg, block, new_pred, mode_M, pn_ia32_Div_M);
case pn_Div_res:
return new_rd_Proj(dbgi, irg, block, new_pred, mode_Iu, pn_ia32_Div_div_res);
+ case pn_Div_X_regular:
+ return new_rd_Jmp(dbgi, irg, block);
+ case pn_Div_X_except:
+ set_ia32_exc_label(new_pred, 1);
+ return new_rd_Proj(dbgi, irg, block, new_pred, mode_X, pn_ia32_Div_X_exc);
default:
break;
}
return new_rd_Proj(dbgi, irg, block, new_pred, mode_M, pn_ia32_Div_M);
case pn_Mod_res:
return new_rd_Proj(dbgi, irg, block, new_pred, mode_Iu, pn_ia32_Div_mod_res);
+ case pn_Mod_X_except:
+ set_ia32_exc_label(new_pred, 1);
+ return new_rd_Proj(dbgi, irg, block, new_pred, mode_X, pn_ia32_Div_X_exc);
default:
break;
}
return new_rd_Proj(dbgi, irg, block, new_pred, mode_Iu, pn_ia32_Div_div_res);
case pn_DivMod_res_mod:
return new_rd_Proj(dbgi, irg, block, new_pred, mode_Iu, pn_ia32_Div_mod_res);
+ case pn_DivMod_X_regular:
+ return new_rd_Jmp(dbgi, irg, block);
+ case pn_DivMod_X_except:
+ set_ia32_exc_label(new_pred, 1);
+ return new_rd_Proj(dbgi, irg, block, new_pred, mode_X, pn_ia32_Div_X_exc);
default:
break;
}
if (node == be_get_old_anchor(anchor_tls)) {
return gen_Proj_tls(node);
}
+ } else if (is_ia32_l_FloattoLL(pred)) {
+ return gen_Proj_l_FloattoLL(node);
#ifdef FIRM_EXT_GRS
} else if(!is_ia32_irn(pred)) { // Quick hack for SIMD optimization
#else
GEN(ia32_l_Load);
GEN(ia32_l_vfist);
GEN(ia32_l_Store);
- GEN(ia32_l_X87toSSE);
- GEN(ia32_l_SSEtoX87);
+ GEN(ia32_l_LLtoFloat);
+ GEN(ia32_l_FloattoLL);
GEN(Const);
GEN(SymConst);
env_cg = cg;
initial_fpcw = NULL;
+BE_TIMER_PUSH(t_heights);
heights = heights_new(irg);
+BE_TIMER_POP(t_heights);
ia32_calculate_non_address_mode_nodes(cg->birg);
/* the transform phase is not safe for CSE (yet) because several nodes get