Commit 04ca356a authored by Christian Würdig's avatar Christian Würdig
Browse files

added xCmp node (SSE compare with result in register)

added xAndNot (SSE And Not)
added SSE support for Psi nodes (transform and emit)
parent 51b9ece7
......@@ -334,7 +334,7 @@ const lc_arg_env_t *ia32_get_arg_env(void) {
return env;
}
static char *ia32_get_reg_name_for_mode(ia32_emit_env_t *env, ir_mode *mode, const arch_register_t *reg) {
static const char *ia32_get_reg_name_for_mode(ia32_emit_env_t *env, ir_mode *mode, const arch_register_t *reg) {
switch(get_mode_size_bits(mode)) {
case 8:
return ia32_get_mapped_reg_name(env->isa->regs_8bit, reg);
......@@ -1049,6 +1049,47 @@ static void emit_ia32_Set(ir_node *irn, ia32_emit_env_t *env) {
IA32_DO_EMIT(irn);
}
static void emit_ia32_xCmp(ir_node *irn, ia32_emit_env_t *env) {
FILE *F = env->out;
const lc_arg_env_t *arg_env = ia32_get_arg_env();
int sse_pnc = -1;
char cmd_buf[SNPRINTF_BUF_LEN];
char cmnt_buf[SNPRINTF_BUF_LEN];
switch (get_ia32_pncode(irn)) {
case pn_Cmp_Leg: /* odered */
sse_pnc = 7;
break;
case pn_Cmp_Uo: /* unordered */
sse_pnc = 3;
break;
case pn_Cmp_Ue: /* == */
sse_pnc = 0;
break;
case pn_Cmp_Ul: /* < */
sse_pnc = 1;
break;
case pn_Cmp_Ule: /* <= */
sse_pnc = 2;
break;
case pn_Cmp_Ug: /* > */
sse_pnc = 6;
break;
case pn_Cmp_Uge: /* >= */
sse_pnc = 5;
break;
case pn_Cmp_Ne: /* != */
sse_pnc = 4;
break;
}
lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "cmps%M %s, %d", irn, ia32_emit_binop(irn, env), sse_pnc);
lc_esnprintf(arg_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* SSE compare with result in %1D */", irn);
IA32_DO_EMIT(irn);
assert(sse_pnc >= 0 && "unsupported floating point compare");
}
/*********************************************************
* _ _ _
* (_) | (_)
......@@ -1643,6 +1684,7 @@ static void ia32_register_emitters(void) {
IA32_EMIT(Conv_I2I);
IA32_EMIT(Conv_I2I8Bit);
IA32_EMIT(Const);
IA32_EMIT(xCmp);
IA32_EMIT2(fcomJmp, x87CondJmp);
IA32_EMIT2(fcompJmp, x87CondJmp);
IA32_EMIT2(fcomppJmp, x87CondJmp);
......
......@@ -635,6 +635,15 @@ else {
# not commutative operations
"xAndNot" => {
"irn_flags" => "R",
"comment" => "construct SSE AndNot: AndNot(a, b) = a AND NOT b",
"cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3 !in_r4" ] },
"emit" => '. andnp%M %ia32_emit_binop /* SSE AndNot(%A3, %A4) -> %D1 */',
"outs" => [ "res", "M" ],
},
"xSub" => {
"irn_flags" => "R",
"comment" => "construct SSE Sub: Sub(a, b) = a - b",
......@@ -655,6 +664,13 @@ else {
# other operations
"xCmp" => {
"irn_flags" => "R",
"comment" => "construct SSE Compare: Cmp(a, b) == a = a cmp b",
"reg_req" => { "in" => [ "gp", "gp", "xmm", "xmm", "none" ], "out" => [ "in_r3 !in_r4" ] },
"outs" => [ "res", "M" ],
},
"xCondJmp" => {
"op_flags" => "L|X|Y",
"comment" => "construct conditional jump: UCOMIS A, B && JMPxx LABEL",
......
......@@ -1622,44 +1622,79 @@ static ir_node *gen_Mux(ia32_transform_env_t *env) {
* @return The transformed node.
*/
static ir_node *gen_Psi(ia32_transform_env_t *env) {
ir_node *node = env->irn;
ir_node *cmp_proj = get_Mux_sel(node);
ir_node *cmp, *cmp_a, *cmp_b, *new_op = NULL;
dbg_info *dbg = env->dbg;
ir_graph *irg = env->irg;
ir_mode *mode = env->mode;
ir_node *block = env->block;
ir_node *node = env->irn;
ir_node *cmp_proj = get_Mux_sel(node);
ir_node *psi_true = get_Psi_val(node, 0);
ir_node *psi_default = get_Psi_default(node);
ir_node *noreg_fp = ia32_new_NoReg_fp(env->cg);
ir_node *nomem = new_rd_NoMem(irg);
ir_node *cmp, *cmp_a, *cmp_b, *and1, *and2, *new_op = NULL;
assert(get_irn_mode(cmp_proj) == mode_b && "Condition for Psi must have mode_b");
if (mode_is_float(env->mode)) {
cmp = get_Proj_pred(cmp_proj);
cmp_a = get_Cmp_left(cmp);
cmp_b = get_Cmp_right(cmp);
if (mode_is_float(mode)) {
/* floating point psi */
if (USE_SSE2(env->cg)) {
/* unfortunately there is no conditional move for SSE */
/* psi(cmp(a, b), t, f) can be done as: */
/* tmp = cmp a, b */
/* tmp2 = t and tmp */
/* tmp3 = f and not tmp */
/* res = tmp2 or tmp3 */
new_op = new_rd_ia32_xCmp(dbg, irg, block, noreg_fp, noreg_fp, cmp_a, cmp_b, nomem);
set_ia32_pncode(new_op, get_Proj_proj(cmp_proj));
set_ia32_am_support(new_op, ia32_am_Source);
set_ia32_res_mode(new_op, mode);
SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, node));
new_op = new_rd_Proj(dbg, irg, block, new_op, mode, 0);
and1 = new_rd_ia32_xAnd(dbg, irg, block, noreg_fp, noreg_fp, psi_true, new_op, nomem);
set_ia32_am_support(and1, ia32_am_Source);
set_ia32_res_mode(and1, mode);
SET_IA32_ORIG_NODE(and1, ia32_get_old_node_name(env->cg, node));
and1 = new_rd_Proj(dbg, irg, block, and1, mode, 0);
and2 = new_rd_ia32_xAndNot(dbg, irg, block, noreg_fp, noreg_fp, psi_default, new_op, nomem);
set_ia32_am_support(and2, ia32_am_Source);
set_ia32_res_mode(and2, mode);
SET_IA32_ORIG_NODE(and2, ia32_get_old_node_name(env->cg, node));
and2 = new_rd_Proj(dbg, irg, block, and2, mode, 0);
new_op = new_rd_ia32_xOr(dbg, irg, block, noreg_fp, noreg_fp, and1, and2, nomem);
set_ia32_am_support(new_op, ia32_am_Source);
set_ia32_res_mode(new_op, mode);
SET_IA32_ORIG_NODE(new_op, ia32_get_old_node_name(env->cg, node));
new_op = new_rd_Proj(dbg, irg, block, new_op, mode, 0);
}
else {
}
}
else {
ir_node *psi_true = get_Psi_val(node, 0);
ir_node *psi_default = get_Psi_default(node);
/* integer psi */
cmp = get_Proj_pred(cmp_proj);
cmp_a = get_Cmp_left(cmp);
cmp_b = get_Cmp_right(cmp);
if (is_ia32_Const_1(psi_true) && is_ia32_Const_0(psi_default)) {
/* first case for SETcc: default is 0, set to 1 iff condition is true */
new_op = new_rd_ia32_Set(env->dbg, env->irg, env->block, cmp_a, cmp_b, env->mode);
new_op = new_rd_ia32_Set(dbg, irg, block, cmp_a, cmp_b, mode);
set_ia32_pncode(new_op, get_Proj_proj(cmp_proj));
}
else if (is_ia32_Const_0(psi_true) && is_ia32_Const_1(psi_default)) {
/* second case for SETcc: default is 1, set to 0 iff condition is true: */
/* we invert condition and set default to 0 */
new_op = new_rd_ia32_Set(env->dbg, env->irg, env->block, cmp_a, cmp_b, env->mode);
new_op = new_rd_ia32_Set(dbg, irg, block, cmp_a, cmp_b, mode);
set_ia32_pncode(new_op, get_inversed_pnc(get_Proj_proj(cmp_proj)));
}
else {
/* otherwise: use CMOVcc */
new_op = new_rd_ia32_CMov(env->dbg, env->irg, env->block, cmp_a, cmp_b, psi_true, psi_default, env->mode);
new_op = new_rd_ia32_CMov(dbg, irg, block, cmp_a, cmp_b, psi_true, psi_default, mode);
set_ia32_pncode(new_op, get_Proj_proj(cmp_proj));
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment