* @version $Id$
*
* Summary table for x86 floatingpoint compares:
+ * (remember effect of unordered on x86: ZF=1, PF=1, CF=1)
+ *
* pnc_Eq => !P && E
* pnc_Lt => !P && B
* pnc_Le => !P && BE
* pnc_Gt => A
* pnc_Ge => AE
- * pnc_Lg => P || NE
+ * pnc_Lg => NE
* pnc_Leg => NP (ordered)
* pnc_Uo => P
* pnc_Ue => E
* pnc_Ule => BE
* pnc_Ug => P || A
* pnc_Uge => P || AE
- * pnc_Ne => NE
+ * pnc_Ne => P || NE
*/
#include "config.h"
be_gas_emit_block_name(block);
}
-/*
- * positive conditions for signed compares
- */
-static const char *const cmp2condition_s[] = {
- NULL, /* always false */
- "e", /* == */
- "l", /* < */
- "le", /* <= */
- "g", /* > */
- "ge", /* >= */
- "ne", /* != */
- NULL /* always true */
-};
-
-/*
- * positive conditions for unsigned compares
- */
-static const char *const cmp2condition_u[] = {
- NULL, /* always false */
- "e", /* == */
- "b", /* < */
- "be", /* <= */
- "a", /* > */
- "ae", /* >= */
- "ne", /* != */
- NULL /* always true */
-};
-
/**
* Emit the suffix for a compare instruction.
*/
-static void ia32_emit_cmp_suffix(int pnc)
-{
- const char *str;
-
- if (pnc == ia32_pn_Cmp_parity) {
- be_emit_char('p');
- return;
- }
-
- if (pnc & ia32_pn_Cmp_float || pnc & ia32_pn_Cmp_unsigned) {
- str = cmp2condition_u[pnc & 7];
- } else {
- str = cmp2condition_s[pnc & 7];
+static void ia32_emit_condition_code(ia32_condition_code_t cc)
+{
+ switch (cc) {
+ case ia32_cc_overflow: be_emit_cstring("o"); return;
+ case ia32_cc_not_overflow: be_emit_cstring("no"); return;
+ case ia32_cc_float_below:
+ case ia32_cc_float_unordered_below:
+ case ia32_cc_below: be_emit_cstring("b"); return;
+ case ia32_cc_float_above_equal:
+ case ia32_cc_float_unordered_above_equal:
+ case ia32_cc_above_equal: be_emit_cstring("ae"); return;
+ case ia32_cc_float_equal:
+ case ia32_cc_equal: be_emit_cstring("e"); return;
+ case ia32_cc_float_not_equal:
+ case ia32_cc_not_equal: be_emit_cstring("ne"); return;
+ case ia32_cc_float_below_equal:
+ case ia32_cc_float_unordered_below_equal:
+ case ia32_cc_below_equal: be_emit_cstring("be"); return;
+ case ia32_cc_float_above:
+ case ia32_cc_float_unordered_above:
+ case ia32_cc_above: be_emit_cstring("a"); return;
+ case ia32_cc_sign: be_emit_cstring("s"); return;
+ case ia32_cc_not_sign: be_emit_cstring("ns"); return;
+ case ia32_cc_parity: be_emit_cstring("p"); return;
+ case ia32_cc_not_parity: be_emit_cstring("np"); return;
+ case ia32_cc_less: be_emit_cstring("l"); return;
+ case ia32_cc_greater_equal: be_emit_cstring("ge"); return;
+ case ia32_cc_less_equal: be_emit_cstring("le"); return;
+ case ia32_cc_greater: be_emit_cstring("g"); return;
+ case ia32_cc_float_parity_cases:
+ case ia32_cc_additional_float_cases:
+ break;
}
-
- be_emit_string(str);
+ panic("Invalid ia32 condition code");
}
typedef enum ia32_emit_mod_t {
}
case 'P': {
- int pnc = va_arg(ap, int);
- ia32_emit_cmp_suffix(pnc);
+ ia32_condition_code_t cc = va_arg(ap, ia32_condition_code_t);
+ ia32_emit_condition_code(cc);
break;
}
}
}
-static int determine_final_pnc(const ir_node *node, int flags_pos, int pnc)
+static int determine_final_cc(const ir_node *node, int flags_pos, int cc)
{
ir_node *flags = get_irn_n(node, flags_pos);
const ia32_attr_t *flags_attr;
}
flags_attr = get_ia32_attr_const(cmp);
- if (flags_attr->data.ins_permuted)
- pnc = get_mirrored_pnc(pnc);
- pnc |= ia32_pn_Cmp_float;
- } else if (is_ia32_Ucomi(flags) || is_ia32_Fucomi(flags)
- || is_ia32_Fucompi(flags)) {
- flags_attr = get_ia32_attr_const(flags);
-
- if (flags_attr->data.ins_permuted)
- pnc = get_mirrored_pnc(pnc);
- pnc |= ia32_pn_Cmp_float;
} else {
flags_attr = get_ia32_attr_const(flags);
-
- if (flags_attr->data.ins_permuted)
- pnc = get_mirrored_pnc(pnc);
- if (flags_attr->data.cmp_unsigned)
- pnc |= ia32_pn_Cmp_unsigned;
}
- return pnc;
-}
-
-static int ia32_get_negated_pnc(int pnc)
-{
- ir_mode *mode = pnc & ia32_pn_Cmp_float ? mode_F : mode_Iu;
- return get_negated_pnc(pnc, mode);
+ if (flags_attr->data.ins_permuted)
+ cc = ia32_invert_condition_code(cc);
+ return cc;
}
void ia32_emit_cmp_suffix_node(const ir_node *node, int flags_pos)
{
- int pnc = get_ia32_condcode(node);
- pnc = determine_final_pnc(node, flags_pos, pnc);
+ ia32_condition_code_t cc = get_ia32_condcode(node);
+ cc = determine_final_cc(node, flags_pos, cc);
- ia32_emit_cmp_suffix(pnc);
+ ia32_emit_condition_code(cc);
}
/**
*/
static void emit_ia32_Jcc(const ir_node *node)
{
- int need_parity_label = 0;
- const ir_node *proj_true;
- const ir_node *proj_false;
- int pnc = get_ia32_condcode(node);
+ int need_parity_label = 0;
+ ia32_condition_code_t cc = get_ia32_condcode(node);
+ const ir_node *proj_true;
+ const ir_node *proj_false;
- pnc = determine_final_pnc(node, 0, pnc);
+ cc = determine_final_cc(node, 0, cc);
/* get both Projs */
proj_true = get_proj(node, pn_ia32_Jcc_true);
proj_true = proj_false;
proj_false = t;
- pnc = ia32_get_negated_pnc(pnc);
+ cc = ia32_negate_condition_code(cc);
}
- if (pnc & ia32_pn_Cmp_float) {
+ if (cc & ia32_cc_float_parity_cases) {
/* Some floating point comparisons require a test of the parity flag,
* which indicates that the result is unordered */
- switch (pnc & 0x0f) {
- case pn_Cmp_Uo: {
+ if (cc & ia32_cc_negated) {
ia32_emitf(proj_true, "\tjp %L\n");
- break;
- }
-
- case pn_Cmp_Leg:
- ia32_emitf(proj_true, "\tjnp %L\n");
- break;
-
- case pn_Cmp_Eq:
- case pn_Cmp_Lt:
- case pn_Cmp_Le:
+ } else {
/* we need a local label if the false proj is a fallthrough
* as the falseblock might have no label emitted then */
if (can_be_fallthrough(proj_false)) {
} else {
ia32_emitf(proj_false, "\tjp %L\n");
}
- goto emit_jcc;
-
- case pn_Cmp_Ug:
- case pn_Cmp_Uge:
- case pn_Cmp_Ne:
- ia32_emitf(proj_true, "\tjp %L\n");
- goto emit_jcc;
-
- default:
- goto emit_jcc;
}
- } else {
-emit_jcc:
- ia32_emitf(proj_true, "\tj%P %L\n", pnc);
}
-
+ ia32_emitf(proj_true, "\tj%P %L\n", cc);
if (need_parity_label) {
ia32_emitf(NULL, "1:\n");
}
{
const arch_register_t *dreg = get_out_reg(node, pn_ia32_Setcc_res);
- int pnc = get_ia32_condcode(node);
- pnc = determine_final_pnc(node, n_ia32_Setcc_eflags, pnc);
- if (pnc & ia32_pn_Cmp_float) {
- switch (pnc & 0x0f) {
- case pn_Cmp_Uo:
- ia32_emitf(node, "\tsetp %#R\n", dreg);
- return;
-
- case pn_Cmp_Leg:
- ia32_emitf(node, "\tsetnp %#R\n", dreg);
- return;
-
- case pn_Cmp_Eq:
- case pn_Cmp_Lt:
- case pn_Cmp_Le:
- ia32_emitf(node, "\tset%P %<R\n", pnc, dreg);
- ia32_emitf(node, "\tsetnp %>R\n", dreg);
- ia32_emitf(node, "\tandb %>R, %<R\n", dreg, dreg);
- return;
-
- case pn_Cmp_Ug:
- case pn_Cmp_Uge:
- case pn_Cmp_Ne:
- ia32_emitf(node, "\tset%P %<R\n", pnc, dreg);
+ ia32_condition_code_t cc = get_ia32_condcode(node);
+ cc = determine_final_cc(node, n_ia32_Setcc_eflags, cc);
+ if (cc & ia32_cc_float_parity_cases) {
+ if (cc & ia32_cc_negated) {
+ ia32_emitf(node, "\tset%P %<R\n", cc, dreg);
ia32_emitf(node, "\tsetp %>R\n", dreg);
ia32_emitf(node, "\torb %>R, %<R\n", dreg, dreg);
- return;
-
- default:
- break;
+ } else {
+ ia32_emitf(node, "\tset%P %<R\n", cc, dreg);
+ ia32_emitf(node, "\tsetnp %>R\n", dreg);
+ ia32_emitf(node, "\tandb %>R, %<R\n", dreg, dreg);
}
+ } else {
+ ia32_emitf(node, "\tset%P %#R\n", cc, dreg);
}
- ia32_emitf(node, "\tset%P %#R\n", pnc, dreg);
}
static void emit_ia32_CMovcc(const ir_node *node)
{
const ia32_attr_t *attr = get_ia32_attr_const(node);
const arch_register_t *out = arch_irn_get_register(node, pn_ia32_res);
- int pnc = get_ia32_condcode(node);
+ ia32_condition_code_t cc = get_ia32_condcode(node);
const arch_register_t *in_true;
const arch_register_t *in_false;
- pnc = determine_final_pnc(node, n_ia32_CMovcc_eflags, pnc);
+ cc = determine_final_cc(node, n_ia32_CMovcc_eflags, cc);
/* although you can't set ins_permuted in the constructor it might still
* be set by memory operand folding
* Permuting inputs of a cmov means the condition is negated!
*/
if (attr->data.ins_permuted)
- pnc = ia32_get_negated_pnc(pnc);
+ cc = ia32_negate_condition_code(cc);
in_true = arch_get_irn_register(get_irn_n(node, n_ia32_CMovcc_val_true));
in_false = arch_get_irn_register(get_irn_n(node, n_ia32_CMovcc_val_false));
assert(get_ia32_op_type(node) == ia32_Normal);
- pnc = ia32_get_negated_pnc(pnc);
+ cc = ia32_negate_condition_code(cc);
tmp = in_true;
in_true = in_false;
ia32_emitf(node, "\tmovl %R, %R\n", in_false, out);
}
- /* TODO: handling of Nans isn't correct yet */
- if (pnc & ia32_pn_Cmp_float) {
- switch (pnc & 0x0f) {
- case pn_Cmp_Uo:
- case pn_Cmp_Leg:
- case pn_Cmp_Eq:
- case pn_Cmp_Lt:
- case pn_Cmp_Le:
- case pn_Cmp_Ug:
- case pn_Cmp_Uge:
- case pn_Cmp_Ne:
- panic("CMov with floatingpoint compare/parity not supported yet");
- }
+ if (cc & ia32_cc_float_parity_cases) {
+ panic("CMov with floatingpoint compare/parity not supported yet");
}
- ia32_emitf(node, "\tcmov%P %#AR, %#R\n", pnc, in_true, out);
+ ia32_emitf(node, "\tcmov%P %#AR, %#R\n", cc, in_true, out);
}
static void generate_jump_table(jmp_tbl_t *tbl, const ir_node *node)
{
int i;
- long pnc;
- long default_pn;
+ long default_pn = get_ia32_default_pn(node);
ir_node *proj;
const ir_edge_t *edge;
tbl->min_value = LONG_MAX;
tbl->max_value = LONG_MIN;
- default_pn = get_ia32_condcode(node);
i = 0;
/* go over all proj's and collect them */
foreach_out_edge(node, edge) {
+ long pn;
proj = get_edge_src_irn(edge);
assert(is_Proj(proj) && "Only proj allowed at SwitchJmp");
- pnc = get_Proj_proj(proj);
+ pn = get_Proj_proj(proj);
/* check for default proj */
- if (pnc == default_pn) {
+ if (pn == default_pn) {
assert(tbl->defProj == NULL && "found two default Projs at SwitchJmp");
tbl->defProj = proj;
} else {
- tbl->min_value = pnc < tbl->min_value ? pnc : tbl->min_value;
- tbl->max_value = pnc > tbl->max_value ? pnc : tbl->max_value;
+ tbl->min_value = pn < tbl->min_value ? pn : tbl->min_value;
+ tbl->max_value = pn > tbl->max_value ? pn : tbl->max_value;
/* create branch entry */
tbl->branches[i].target = proj;
- tbl->branches[i].value = pnc;
+ tbl->branches[i].value = pn;
++i;
}
static unsigned char reg_gp_map[N_ia32_gp_REGS];
//static unsigned char reg_mmx_map[N_ia32_mmx_REGS];
//static unsigned char reg_sse_map[N_ia32_xmm_REGS];
-static unsigned char pnc_map_signed[8];
-static unsigned char pnc_map_unsigned[8];
static void build_reg_map(void)
{
reg_gp_map[REG_GP_EBP] = 0x5;
reg_gp_map[REG_GP_ESI] = 0x6;
reg_gp_map[REG_GP_EDI] = 0x7;
-
- pnc_map_signed[pn_Cmp_Eq] = 0x04;
- pnc_map_signed[pn_Cmp_Lt] = 0x0C;
- pnc_map_signed[pn_Cmp_Le] = 0x0E;
- pnc_map_signed[pn_Cmp_Gt] = 0x0F;
- pnc_map_signed[pn_Cmp_Ge] = 0x0D;
- pnc_map_signed[pn_Cmp_Lg] = 0x05;
-
- pnc_map_unsigned[pn_Cmp_Eq] = 0x04;
- pnc_map_unsigned[pn_Cmp_Lt] = 0x02;
- pnc_map_unsigned[pn_Cmp_Le] = 0x06;
- pnc_map_unsigned[pn_Cmp_Gt] = 0x07;
- pnc_map_unsigned[pn_Cmp_Ge] = 0x03;
- pnc_map_unsigned[pn_Cmp_Lg] = 0x05;
}
/** Returns the encoding for a pnc field. */
-static unsigned char pnc2cc(int pnc)
+static unsigned char pnc2cc(ia32_condition_code_t cc)
{
- unsigned char cc;
- if (pnc == ia32_pn_Cmp_parity) {
- cc = 0x0A;
- } else if (pnc & ia32_pn_Cmp_float || pnc & ia32_pn_Cmp_unsigned) {
- cc = pnc_map_unsigned[pnc & 0x07];
- } else {
- cc = pnc_map_signed[pnc & 0x07];
- }
- assert(cc != 0);
- return cc;
+ return cc & 0xf;
}
/** Sign extension bit values for binops */
{
const arch_register_t *dreg = get_out_reg(node, pn_ia32_Setcc_res);
- int pnc = get_ia32_condcode(node);
- pnc = determine_final_pnc(node, n_ia32_Setcc_eflags, pnc);
- if (pnc & ia32_pn_Cmp_float) {
- switch (pnc & 0x0f) {
- case pn_Cmp_Uo:
- /* setp <dreg */
+ ia32_condition_code_t cc = get_ia32_condcode(node);
+ cc = determine_final_cc(node, n_ia32_Setcc_eflags, cc);
+ if (cc & ia32_cc_float_parity_cases) {
+ if (cc & ia32_cc_negated) {
+ /* set%PNC <dreg */
bemit8(0x0F);
- bemit8(0x9A);
+ bemit8(0x90 | pnc2cc(cc));
bemit_modrm8(REG_LOW, dreg);
- return;
- case pn_Cmp_Leg:
- /* setnp <dreg*/
+ /* setp >dreg */
bemit8(0x0F);
- bemit8(0x9B);
- bemit_modrm8(REG_LOW, dreg);
- return;
+ bemit8(0x9A);
+ bemit_modrm8(REG_HIGH, dreg);
- case pn_Cmp_Eq:
- case pn_Cmp_Lt:
- case pn_Cmp_Le:
+ /* orb %>dreg, %<dreg */
+ bemit8(0x08);
+ bemit_modrr8(REG_LOW, dreg, REG_HIGH, dreg);
+ } else {
/* set%PNC <dreg */
bemit8(0x0F);
- bemit8(0x90 | pnc2cc(pnc));
+ bemit8(0x90 | pnc2cc(cc));
bemit_modrm8(REG_LOW, dreg);
/* setnp >dreg */
/* andb %>dreg, %<dreg */
bemit8(0x20);
bemit_modrr8(REG_LOW, dreg, REG_HIGH, dreg);
- return;
-
- case pn_Cmp_Ug:
- case pn_Cmp_Uge:
- case pn_Cmp_Ne:
- /* set%PNC <dreg */
- bemit8(0x0F);
- bemit8(0x90 | pnc2cc(pnc));
- bemit_modrm8(REG_LOW, dreg);
-
- /* setp >dreg */
- bemit8(0x0F);
- bemit8(0x9A);
- bemit_modrm8(REG_HIGH, dreg);
-
- /* orb %>dreg, %<dreg */
- bemit8(0x08);
- bemit_modrr8(REG_LOW, dreg, REG_HIGH, dreg);
- return;
-
- default:
- break;
}
+ } else {
+ /* set%PNC <dreg */
+ bemit8(0x0F);
+ bemit8(0x90 | pnc2cc(cc));
+ bemit_modrm8(REG_LOW, dreg);
}
- /* set%PNC <dreg */
- bemit8(0x0F);
- bemit8(0x90 | pnc2cc(pnc));
- bemit_modrm8(REG_LOW, dreg);
}
static void bemit_cmovcc(const ir_node *node)
const ia32_attr_t *attr = get_ia32_attr_const(node);
int ins_permuted = attr->data.ins_permuted;
const arch_register_t *out = arch_irn_get_register(node, pn_ia32_res);
- int pnc = get_ia32_condcode(node);
+ ia32_condition_code_t cc = get_ia32_condcode(node);
const arch_register_t *in_true;
const arch_register_t *in_false;
- pnc = determine_final_pnc(node, n_ia32_CMovcc_eflags, pnc);
+ cc = determine_final_cc(node, n_ia32_CMovcc_eflags, cc);
in_true = arch_get_irn_register(get_irn_n(node, n_ia32_CMovcc_val_true));
in_false = arch_get_irn_register(get_irn_n(node, n_ia32_CMovcc_val_false));
}
if (ins_permuted)
- pnc = ia32_get_negated_pnc(pnc);
+ cc = ia32_negate_condition_code(cc);
- /* TODO: handling of Nans isn't correct yet */
+ if (cc & ia32_cc_float_parity_cases)
+ panic("cmov can't handle parity float cases");
bemit8(0x0F);
- bemit8(0x40 | pnc2cc(pnc));
+ bemit8(0x40 | pnc2cc(cc));
if (get_ia32_op_type(node) == ia32_Normal) {
bemit_modrr(in_true, out);
} else {
static void bemit_ia32_jcc(const ir_node *node)
{
- int pnc = get_ia32_condcode(node);
- const ir_node *proj_true;
- const ir_node *proj_false;
- const ir_node *dest_true;
- const ir_node *dest_false;
- const ir_node *block;
+ ia32_condition_code_t cc = get_ia32_condcode(node);
+ const ir_node *proj_true;
+ const ir_node *proj_false;
+ const ir_node *dest_true;
+ const ir_node *dest_false;
+ const ir_node *block;
- pnc = determine_final_pnc(node, 0, pnc);
+ cc = determine_final_cc(node, 0, cc);
/* get both Projs */
proj_true = get_proj(node, pn_ia32_Jcc_true);
proj_true = proj_false;
proj_false = t;
- pnc = ia32_get_negated_pnc(pnc);
+ cc = ia32_negate_condition_code(cc);
}
dest_true = get_cfop_target_block(proj_true);
dest_false = get_cfop_target_block(proj_false);
- if (pnc & ia32_pn_Cmp_float) {
+ if (cc & ia32_cc_float_parity_cases) {
/* Some floating point comparisons require a test of the parity flag,
* which indicates that the result is unordered */
- switch (pnc & 15) {
- case pn_Cmp_Uo: {
- bemit_jp(false, dest_true);
- break;
+ if (cc & ia32_cc_negated) {
+ bemit_jp(false, dest_true);
+ } else {
+ /* we need a local label if the false proj is a fallthrough
+ * as the falseblock might have no label emitted then */
+ if (can_be_fallthrough(proj_false)) {
+ bemit8(0x7A);
+ bemit8(0x06); // jp + 6
+ } else {
+ bemit_jp(false, dest_false);
}
-
- case pn_Cmp_Leg:
- bemit_jp(true, dest_true);
- break;
-
- case pn_Cmp_Eq:
- case pn_Cmp_Lt:
- case pn_Cmp_Le:
- /* we need a local label if the false proj is a fallthrough
- * as the falseblock might have no label emitted then */
- if (can_be_fallthrough(proj_false)) {
- bemit8(0x7A);
- bemit8(0x06); // jp + 6
- } else {
- bemit_jp(false, dest_false);
- }
- goto emit_jcc;
-
- case pn_Cmp_Ug:
- case pn_Cmp_Uge:
- case pn_Cmp_Ne:
- bemit_jp(false, dest_true);
- goto emit_jcc;
-
- default:
- goto emit_jcc;
}
- } else {
-emit_jcc:
- bemit_jcc(pnc, dest_true);
}
+ bemit_jcc(cc, dest_true);
/* the second Proj might be a fallthrough */
if (can_be_fallthrough(proj_false)) {
#include "config.h"
#include <stdlib.h>
+#include <stdbool.h>
#include "irargs_t.h"
#include "irprog_t.h"
/* dump pn code */
if (is_ia32_SwitchJmp(n)) {
- fprintf(F, "pn_code = %ld\n", get_ia32_condcode(n));
+ fprintf(F, "default_pn = %ld\n", get_ia32_default_pn(n));
} else if (is_ia32_CMovcc(n) || is_ia32_Setcc(n) || is_ia32_Jcc(n)) {
ia32_attr_t *attr = get_ia32_attr(n);
- long pnc = get_ia32_condcode(n);
- fprintf(F, "pn_code = 0x%X (%s)\n", (unsigned) pnc,
- get_pnc_string(pnc & pn_Cmp_True));
+ fprintf(F, "condition_code = 0x%X\n", get_ia32_condcode(n));
fprintf(F, "ins_permuted = %u \n", attr->data.ins_permuted);
- fprintf(F, "cmp_unsigned = %u \n", attr->data.cmp_unsigned);
}
else if (is_ia32_CopyB(n) || is_ia32_CopyB_i(n)) {
fprintf(F, "size = %u\n", get_ia32_copyb_size(n));
return cc_attr;
}
+ia32_switch_attr_t *get_ia32_switch_attr(ir_node *node)
+{
+ ia32_attr_t *attr = get_ia32_attr(node);
+ ia32_switch_attr_t *switch_attr = CAST_IA32_ATTR(ia32_switch_attr_t, attr);
+ return switch_attr;
+}
+
+const ia32_switch_attr_t *get_ia32_switch_attr_const(const ir_node *node)
+{
+ const ia32_attr_t *attr = get_ia32_attr_const(node);
+ const ia32_switch_attr_t *switch_attr = CONST_CAST_IA32_ATTR(ia32_switch_attr_t, attr);
+ return switch_attr;
+}
+
ia32_call_attr_t *get_ia32_call_attr(ir_node *node)
{
ia32_attr_t *attr = get_ia32_attr(node);
/**
* Returns the condition code of a node.
*/
-long get_ia32_condcode(const ir_node *node)
+ia32_condition_code_t get_ia32_condcode(const ir_node *node)
{
const ia32_condcode_attr_t *attr = get_ia32_condcode_attr_const(node);
- return attr->pn_code;
+ return attr->condition_code;
}
/**
* Sets the condition code of a node
*/
-void set_ia32_condcode(ir_node *node, long code)
+void set_ia32_condcode(ir_node *node, ia32_condition_code_t code)
{
ia32_condcode_attr_t *attr = get_ia32_condcode_attr(node);
- attr->pn_code = code;
+ attr->condition_code = code;
+}
+
+long get_ia32_default_pn(const ir_node *node)
+{
+ const ia32_switch_attr_t *attr = get_ia32_switch_attr_const(node);
+ return attr->default_pn;
}
/**
attr->size = size;
}
-void init_ia32_condcode_attributes(ir_node *res, long pnc)
+void init_ia32_condcode_attributes(ir_node *res, ia32_condition_code_t cc)
{
ia32_condcode_attr_t *attr = (ia32_condcode_attr_t*)get_irn_generic_attr(res);
#ifndef NDEBUG
attr->attr.attr_type |= IA32_ATTR_ia32_condcode_attr_t;
#endif
- attr->pn_code = pnc;
+ attr->condition_code = cc;
}
void init_ia32_climbframe_attributes(ir_node *res, unsigned count)
attr->count = count;
}
+void init_ia32_switch_attributes(ir_node *res, long default_pn)
+{
+ ia32_switch_attr_t *attr = (ia32_switch_attr_t*) get_irn_generic_attr(res);
+#ifndef NDEBUG
+ attr->attr.attr_type |= IA32_ATTR_ia32_switch_attr_t;
+#endif
+ attr->default_pn = default_pn;
+}
+
/* default compare operation to compare attributes */
static int ia32_compare_attr(const ia32_attr_t *a, const ia32_attr_t *b)
if (a->data.has_except_label != b->data.has_except_label)
return 1;
- if (a->data.ins_permuted != b->data.ins_permuted
- || a->data.cmp_unsigned != b->data.cmp_unsigned)
+ if (a->data.ins_permuted != b->data.ins_permuted)
return 1;
return 0;
attr_a = get_ia32_condcode_attr_const(a);
attr_b = get_ia32_condcode_attr_const(b);
- if (attr_a->pn_code != attr_b->pn_code)
+ if (attr_a->condition_code != attr_b->condition_code)
+ return 1;
+
+ return 0;
+}
+
+/** Compare node attributes for nodes with condition code. */
+static int ia32_compare_switch_attr(ir_node *a, ir_node *b)
+{
+ const ia32_switch_attr_t *attr_a;
+ const ia32_switch_attr_t *attr_b;
+
+ if (ia32_compare_nodes_attr(a, b))
+ return 1;
+
+ attr_a = get_ia32_switch_attr_const(a);
+ attr_b = get_ia32_switch_attr_const(b);
+
+ if (attr_a->default_pn != attr_b->default_pn)
return 1;
return 0;
/**
* Returns the condition code of a node.
*/
-long get_ia32_condcode(const ir_node *node);
+ia32_condition_code_t get_ia32_condcode(const ir_node *node);
/**
* Sets the condition code of a node
*/
-void set_ia32_condcode(ir_node *node, long code);
+void set_ia32_condcode(ir_node *node, ia32_condition_code_t code);
+
+long get_ia32_default_pn(const ir_node *node);
-/**
- * Returns the condition code of a node.
- */
unsigned get_ia32_copyb_size(const ir_node *node);
/**
int is_ia32_AddrModeD(const ir_node *node);
/**
- * Swaps left/right input of a node (and adjusts pnc if needed)
+ * Swaps left/right input of a node (and sets ins_permuted accordingly)
*/
void ia32_swap_left_right(ir_node *node);
long offset);
void init_ia32_call_attributes(ir_node *res, unsigned pop, ir_type *call_tp);
void init_ia32_copyb_attributes(ir_node *res, unsigned size);
-void init_ia32_condcode_attributes(ir_node *res, long pnc);
+void init_ia32_condcode_attributes(ir_node *res, ia32_condition_code_t cc);
void init_ia32_climbframe_attributes(ir_node *res, unsigned count);
/* Include the generated headers */
#include "../bemachine.h"
#include "irnode_t.h"
-enum {
- ia32_pn_Cmp_unsigned = 0x1000,
- ia32_pn_Cmp_float = 0x2000,
- ia32_pn_Cmp_parity = 0x4000,
- /* The unsigned Lt/Ge comparisons test the carry bit. */
- ia32_pn_Cmp_carry = pn_Cmp_Lt | ia32_pn_Cmp_unsigned,
- ia32_pn_Cmp_not_carry = pn_Cmp_Ge | ia32_pn_Cmp_unsigned
-};
+/** ia32 condition codes (the numbers correspond to the real encoding order) */
+typedef enum ia32_condition_code_t {
+ ia32_cc_negated = 0x01, /**< negates condition */
+
+ ia32_cc_overflow = 0x00, /**< OF=1 */
+ ia32_cc_below = 0x02, /**< CF=1 */
+ ia32_cc_equal = 0x04, /**< ZF=1 */
+ ia32_cc_below_equal = 0x06, /**< ZF=1 or CF=1 */
+ ia32_cc_sign = 0x08, /**< SF=1 */
+ ia32_cc_parity = 0x0A, /**< PF=1 */
+ ia32_cc_less = 0x0C, /**< SF!=OF */
+ ia32_cc_less_equal = 0x0E, /**< ZF=1 or SF!=OF */
+ ia32_cc_not_overflow = ia32_cc_negated|ia32_cc_overflow, /**< OF=0 */
+ ia32_cc_above_equal = ia32_cc_negated|ia32_cc_below, /**< CF=0 */
+ ia32_cc_not_equal = ia32_cc_negated|ia32_cc_equal, /**< ZF=0 */
+ ia32_cc_above = ia32_cc_negated|ia32_cc_below_equal, /**< ZF=0 and CF=0 */
+ ia32_cc_not_sign = ia32_cc_negated|ia32_cc_sign, /**< SF=0 */
+ ia32_cc_not_parity = ia32_cc_negated|ia32_cc_parity, /**< PF=0 */
+ ia32_cc_greater_equal = ia32_cc_negated|ia32_cc_less, /**< SF=OF */
+ ia32_cc_greater = ia32_cc_negated|ia32_cc_less_equal, /**< ZF=0 and SF=OF */
+
+ /* the following codes are (unfortunately) NOT real hardware codes but
+ * simplify our backend as you need these combinations for some
+ * floatingpoint compares (the emitter will split them into multiple
+ * instructions) */
+ ia32_cc_float_parity_cases = 0x20,
+ /* we need even more cases as inversing the cc is different for float
+ * comparisons (though for the following we need no special
+ * parity+x combinations) */
+ ia32_cc_additional_float_cases = 0x10,
+
+ /* make sure that the lower 4 bit correspond to the real encoding
+ * (of the comparison not involving the parity special) */
+ ia32_cc_float_equal = 0x34, /**< PF=0 and ZF=1 */
+ ia32_cc_float_below = 0x32, /**< PF=0 and CF=1 */
+ ia32_cc_float_below_equal = 0x36, /**< PF=0 and (ZF=1 or CF=1) */
+ ia32_cc_float_not_equal = ia32_cc_negated|ia32_cc_float_equal, /**< PF=1 or ZF=0 */
+ ia32_cc_float_unordered_above_equal
+ = ia32_cc_negated|ia32_cc_float_below, /**< PF=1 or CF=0 */
+ ia32_cc_float_unordered_above
+ = ia32_cc_negated|ia32_cc_float_below_equal, /**< PF=1 or (ZF=0 and CF=0) */
+
+ ia32_cc_float_unordered_below_equal = 0x16, /**< ZF=1 or CF=1 */
+ ia32_cc_float_unordered_below = 0x12, /**< CF=1 */
+ ia32_cc_float_above =
+ ia32_cc_negated|ia32_cc_float_unordered_below_equal, /**< ZF=0 and CF=0 */
+ ia32_cc_float_above_equal
+ = ia32_cc_negated|ia32_cc_float_unordered_below, /**< CF=0 */
+} ia32_condition_code_t;
+ENUM_BITSET(ia32_condition_code_t)
+
+static inline ia32_condition_code_t ia32_negate_condition_code(
+ ia32_condition_code_t code)
+{
+ return code ^ ia32_cc_negated;
+}
+
+static inline ia32_condition_code_t ia32_invert_condition_code(
+ ia32_condition_code_t code)
+{
+ /* doesn't appear to have any systematic, so use a table */
+ switch (code) {
+ case ia32_cc_below: return ia32_cc_above;
+ case ia32_cc_below_equal: return ia32_cc_above_equal;
+ case ia32_cc_above: return ia32_cc_below;
+ case ia32_cc_above_equal: return ia32_cc_below_equal;
+ case ia32_cc_less: return ia32_cc_greater;
+ case ia32_cc_less_equal: return ia32_cc_greater_equal;
+ case ia32_cc_greater: return ia32_cc_less;
+ case ia32_cc_greater_equal: return ia32_cc_less_equal;
+ case ia32_cc_float_below: return ia32_cc_float_above;
+ case ia32_cc_float_below_equal: return ia32_cc_float_above_equal;
+ case ia32_cc_float_above: return ia32_cc_float_below;
+ case ia32_cc_float_above_equal: return ia32_cc_float_below_equal;
+ case ia32_cc_float_unordered_below: return ia32_cc_float_unordered_above;
+ case ia32_cc_float_unordered_below_equal: return ia32_cc_float_unordered_above_equal;
+ case ia32_cc_float_unordered_above: return ia32_cc_float_unordered_below;
+ case ia32_cc_float_unordered_above_equal: return ia32_cc_float_unordered_below_equal;
+ default: return code;
+ }
+}
typedef enum {
ia32_Normal,
IA32_ATTR_ia32_copyb_attr_t = 1 << 5,
IA32_ATTR_ia32_call_attr_t = 1 << 6,
IA32_ATTR_ia32_climbframe_attr_t = 1 << 7,
+ IA32_ATTR_ia32_switch_attr_t = 1 << 8,
} ia32_attr_type_t;
#endif
unsigned need_32bit_stackent:1; /**< needs a 32bit stack entity */
unsigned ins_permuted : 1; /**< inputs of node have been permuted
(for commutative nodes) */
- unsigned cmp_unsigned : 1; /**< compare should be unsigned */
unsigned is_reload : 1; /**< node performs a reload */
unsigned is_spill : 1;
unsigned is_remat : 1;
*/
typedef struct ia32_condcode_attr_t ia32_condcode_attr_t;
struct ia32_condcode_attr_t {
- ia32_attr_t attr; /**< generic attribute */
- long pn_code; /**< projnum "types" (e.g. indicate compare operators */
+ ia32_attr_t attr; /**< generic attribute */
+ ia32_condition_code_t condition_code; /**< condition code*/
+};
+
+/**
+ * The attributes for Switches
+ */
+typedef struct ia32_switch_attr_t ia32_switch_attr_t;
+struct ia32_switch_attr_t {
+ ia32_attr_t attr; /**< generic attribute */
+ long default_pn;
};
/**
ia32_asm_attr_t asm_attr;
ia32_immediate_attr_t immediate_attr;
ia32_climbframe_attr_t climbframe_attr;
+ ia32_switch_attr_t switch_attr;
};
#ifndef NDEBUG
ir_node *op;
ia32_attr_t const *attr;
int ins_permuted;
- int cmp_unsigned;
ir_node *test;
arch_register_t const *reg;
ir_edge_t const *edge;
op = get_irn_n(node, n_ia32_Cmp_left);
attr = get_ia32_attr(node);
ins_permuted = attr->data.ins_permuted;
- cmp_unsigned = attr->data.cmp_unsigned;
if (is_ia32_Cmp(node)) {
test = new_bd_ia32_Test(dbgi, block, noreg, noreg, nomem,
- op, op, ins_permuted, cmp_unsigned);
+ op, op, ins_permuted);
} else {
test = new_bd_ia32_Test8Bit(dbgi, block, noreg, noreg, nomem,
- op, op, ins_permuted, cmp_unsigned);
+ op, op, ins_permuted);
}
set_ia32_ls_mode(test, get_ia32_ls_mode(node));
/* make sure only Lg/Eq tests are used */
foreach_out_edge(node, edge) {
- ir_node *user = get_edge_src_irn(edge);
- int pnc = get_ia32_condcode(user);
+ ir_node *user = get_edge_src_irn(edge);
+ ia32_condition_code_t cc = get_ia32_condcode(user);
- if (pnc != pn_Cmp_Eq && pnc != pn_Cmp_Lg) {
+ if (cc != ia32_cc_equal && cc != ia32_cc_not_equal) {
return;
}
}
case produces_flag_carry:
foreach_out_edge(node, edge) {
- ir_node *user = get_edge_src_irn(edge);
- int pnc = get_ia32_condcode(user);
+ ir_node *user = get_edge_src_irn(edge);
+ ia32_condition_code_t cc = get_ia32_condcode(user);
- switch (pnc) {
- case pn_Cmp_Eq: pnc = ia32_pn_Cmp_not_carry; break;
- case pn_Cmp_Lg: pnc = ia32_pn_Cmp_carry; break;
- default: panic("unexpected pn");
+ switch (cc) {
+ case ia32_cc_equal: cc = ia32_cc_above_equal; break; /* CF = 0 */
+ case ia32_cc_not_equal: cc = ia32_cc_below; break; /* CF = 1 */
+ default: panic("unexpected pn");
}
- set_ia32_condcode(user, pnc);
+ set_ia32_condcode(user, cc);
}
break;
"\tinit_ia32_call_attributes(res, pop, call_tp);",
ia32_condcode_attr_t =>
"\tinit_ia32_attributes(res, flags, in_reqs, exec_units, n_res);\n".
- "\tinit_ia32_condcode_attributes(res, pnc);",
+ "\tinit_ia32_condcode_attributes(res, condition_code);",
+ ia32_switch_attr_t =>
+ "\tinit_ia32_attributes(res, flags, in_reqs, exec_units, n_res);\n".
+ "\tinit_ia32_switch_attributes(res, default_pn);",
ia32_copyb_attr_t =>
"\tinit_ia32_attributes(res, flags, in_reqs, exec_units, n_res);\n".
"\tinit_ia32_copyb_attributes(res, size);",
);
%compare_attr = (
- ia32_asm_attr_t => "ia32_compare_asm_attr",
+ ia32_asm_attr_t => "ia32_compare_asm_attr",
ia32_attr_t => "ia32_compare_nodes_attr",
ia32_call_attr_t => "ia32_compare_call_attr",
ia32_condcode_attr_t => "ia32_compare_condcode_attr",
+ ia32_switch_attr_t => "ia32_compare_switch_attr",
ia32_copyb_attr_t => "ia32_compare_copyb_attr",
ia32_immediate_attr_t => "ia32_compare_immediate_attr",
ia32_x87_attr_t => "ia32_compare_x87_attr",
outs => [ "eflags", "unused", "M" ],
am => "source,binary",
emit => '. cmp%M %binop',
- attr => "int ins_permuted, int cmp_unsigned",
- init_attr => "attr->data.ins_permuted = ins_permuted;\n".
- "\tattr->data.cmp_unsigned = cmp_unsigned;\n",
+ attr => "bool ins_permuted",
+ init_attr => "attr->data.ins_permuted = ins_permuted;",
latency => 1,
units => [ "GP" ],
mode => $mode_flags,
outs => [ "eflags", "unused", "M" ],
am => "source,binary",
emit => '. cmpb %binop',
- attr => "int ins_permuted, int cmp_unsigned",
- init_attr => "attr->data.ins_permuted = ins_permuted;\n".
- "\tattr->data.cmp_unsigned = cmp_unsigned;\n",
+ attr => "bool ins_permuted",
+ init_attr => "attr->data.ins_permuted = ins_permuted;",
latency => 1,
units => [ "GP" ],
mode => $mode_flags,
outs => [ "eflags", "unused", "M" ],
am => "source,binary",
emit => '. test%M %binop',
- attr => "int ins_permuted, int cmp_unsigned",
- init_attr => "attr->data.ins_permuted = ins_permuted;\n".
- "\tattr->data.cmp_unsigned = cmp_unsigned;\n",
+ attr => "bool ins_permuted",
+ init_attr => "attr->data.ins_permuted = ins_permuted;",
latency => 1,
units => [ "GP" ],
mode => $mode_flags,
outs => [ "eflags", "unused", "M" ],
am => "source,binary",
emit => '. testb %binop',
- attr => "int ins_permuted, int cmp_unsigned",
- init_attr => "attr->data.ins_permuted = ins_permuted;\n".
- "\tattr->data.cmp_unsigned = cmp_unsigned;\n",
+ attr => "bool ins_permuted",
+ init_attr => "attr->data.ins_permuted = ins_permuted;",
latency => 1,
units => [ "GP" ],
mode => $mode_flags,
ins => [ "eflags" ],
outs => [ "res" ],
attr_type => "ia32_condcode_attr_t",
- attr => "int pnc",
+ attr => "ia32_condition_code_t condition_code",
# The way we handle Setcc with float nodes (potentially) destroys the flags
# (when we emit the setX; setp; orb and the setX;setnp;andb sequences)
init_attr => "set_ia32_ls_mode(res, mode_Bu);\n"
- . "\tif ((pnc & ia32_pn_Cmp_float) && ((pnc & 0xf) != pn_Cmp_Uo) && ((pnc & 0xf) != pn_Cmp_Leg)) {\n"
+ . "\tif (condition_code & ia32_cc_additional_float_cases) {\n"
. "\t\tarch_irn_add_flags(res, arch_irn_flags_modify_flags);\n"
. "\t\t/* attr->latency = 3; */\n"
. "\t}\n",
reg_req => { in => [ "gp", "gp", "none", "eflags" ], out => [ "none" ] },
ins => [ "base", "index", "mem","eflags" ],
attr_type => "ia32_condcode_attr_t",
- attr => "int pnc",
+ attr => "ia32_condition_code_t condition_code",
init_attr => "set_ia32_ls_mode(res, mode_Bu);\n",
emit => '. set%CMP3 %AM',
latency => 1,
outs => [ "res", "flags", "M" ],
am => "source,binary",
attr_type => "ia32_condcode_attr_t",
- attr => "int pnc",
+ attr => "ia32_condition_code_t condition_code",
latency => 1,
units => [ "GP" ],
mode => $mode_gp,
ins => [ "eflags" ],
outs => [ "false", "true" ],
attr_type => "ia32_condcode_attr_t",
- attr => "int pnc",
+ attr => "ia32_condition_code_t condition_code",
latency => 2,
units => [ "BRANCH" ],
},
op_flags => [ "labeled", "cfopcode", "forking" ],
reg_req => { in => [ "gp" ] },
mode => "mode_T",
- attr_type => "ia32_condcode_attr_t",
- attr => "long pnc",
+ attr_type => "ia32_switch_attr_t",
+ attr => "long default_pn",
latency => 3,
units => [ "BRANCH" ],
modified_flags => $status_flags,
ins => [ "base", "index", "mem", "left", "right" ],
outs => [ "flags" ],
am => "source,binary",
- attr => "int ins_permuted",
+ attr => "bool ins_permuted",
init_attr => "attr->data.ins_permuted = ins_permuted;",
emit => ' .ucomi%XXM %binop',
latency => 3,
reg_req => { in => [ "vfp", "vfp" ], out => [ "eax" ] },
ins => [ "left", "right" ],
outs => [ "flags" ],
- attr => "int ins_permuted",
+ attr => "bool ins_permuted",
init_attr => "attr->attr.data.ins_permuted = ins_permuted;",
latency => 3,
units => [ "VFP" ],
reg_req => { in => [ "vfp", "vfp" ], out => [ "eflags" ] },
ins => [ "left", "right" ],
outs => [ "flags" ],
- attr => "int ins_permuted",
+ attr => "bool ins_permuted",
init_attr => "attr->attr.data.ins_permuted = ins_permuted;",
latency => 3,
units => [ "VFP" ],
reg_req => { in => [ "vfp" ], out => [ "eax" ] },
ins => [ "left" ],
outs => [ "flags" ],
- attr => "int ins_permuted",
+ attr => "bool ins_permuted",
init_attr => "attr->attr.data.ins_permuted = ins_permuted;",
latency => 3,
units => [ "VFP" ],
} else {
new_op1 = be_transform_node(op2);
new_op2 = noreg;
- am->ins_permuted = 1;
+ am->ins_permuted = true;
}
am->op_type = ia32_AddrModeS;
} else {
return new_bd_ia32_Bt(dbgi, new_block, op1, op2);
}
-/**
- * Transform a node returning a "flag" result.
- *
- * @param node the node to transform
- * @param pnc_out the compare mode to use
- */
-static ir_node *get_flags_node(ir_node *node, int *pnc_out)
+static ia32_condition_code_t pnc_to_condition_code(pn_Cmp pnc, ir_mode *mode)
{
+ if (mode_is_float(mode)) {
+ switch (pnc) {
+ case pn_Cmp_Eq: return ia32_cc_float_equal;
+ case pn_Cmp_Lt: return ia32_cc_float_below;
+ case pn_Cmp_Le: return ia32_cc_float_below_equal;
+ case pn_Cmp_Gt: return ia32_cc_float_above;
+ case pn_Cmp_Ge: return ia32_cc_float_above_equal;
+ case pn_Cmp_Lg: return ia32_cc_not_equal;
+ case pn_Cmp_Leg: return ia32_cc_not_parity;
+ case pn_Cmp_Uo: return ia32_cc_parity;
+ case pn_Cmp_Ue: return ia32_cc_equal;
+ case pn_Cmp_Ul: return ia32_cc_float_unordered_below;
+ case pn_Cmp_Ule: return ia32_cc_float_unordered_below_equal;
+ case pn_Cmp_Ug: return ia32_cc_float_unordered_above;
+ case pn_Cmp_Uge: return ia32_cc_float_unordered_above_equal;
+ case pn_Cmp_Ne: return ia32_cc_float_not_equal;
+ case pn_Cmp_False:
+ case pn_Cmp_True:
+ case pn_Cmp_max:
+ /* should we introduce a jump always/jump never? */
+ break;
+ }
+ panic("Unexpected float pnc");
+ } else if (mode_is_signed(mode)) {
+ switch (pnc) {
+ case pn_Cmp_Ue:
+ case pn_Cmp_Eq: return ia32_cc_equal;
+ case pn_Cmp_Ul:
+ case pn_Cmp_Lt: return ia32_cc_less;
+ case pn_Cmp_Ule:
+ case pn_Cmp_Le: return ia32_cc_less_equal;
+ case pn_Cmp_Ug:
+ case pn_Cmp_Gt: return ia32_cc_greater;
+ case pn_Cmp_Uge:
+ case pn_Cmp_Ge: return ia32_cc_greater_equal;
+ case pn_Cmp_Lg:
+ case pn_Cmp_Ne: return ia32_cc_not_equal;
+ case pn_Cmp_Leg:
+ case pn_Cmp_Uo:
+ case pn_Cmp_False:
+ case pn_Cmp_True:
+ case pn_Cmp_max:
+ /* introduce jump always/jump never? */
+ break;
+ }
+ panic("Unexpected pnc");
+ } else {
+ switch (pnc) {
+ case pn_Cmp_Ue:
+ case pn_Cmp_Eq: return ia32_cc_equal;
+ case pn_Cmp_Ul:
+ case pn_Cmp_Lt: return ia32_cc_below;
+ case pn_Cmp_Ule:
+ case pn_Cmp_Le: return ia32_cc_below_equal;
+ case pn_Cmp_Ug:
+ case pn_Cmp_Gt: return ia32_cc_above;
+ case pn_Cmp_Uge:
+ case pn_Cmp_Ge: return ia32_cc_above_equal;
+ case pn_Cmp_Lg:
+ case pn_Cmp_Ne: return ia32_cc_not_equal;
+ case pn_Cmp_Leg:
+ case pn_Cmp_Uo:
+ case pn_Cmp_False:
+ case pn_Cmp_True:
+ case pn_Cmp_max:
+ /* introduce jump always/jump never? */
+ break;
+ }
+ panic("Unexpected pnc");
+ }
+}
+
+static ir_node *get_flags_mode_b(ir_node *node, ia32_condition_code_t *cc_out)
+{
+ /* a mode_b value, we have to compare it against 0 */
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_node *new_block = be_transform_node(get_nodes_block(node));
+ ir_node *new_op = be_transform_node(node);
+ ir_node *flags = new_bd_ia32_Test(dbgi, new_block, noreg_GP, noreg_GP, nomem, new_op, new_op, false);
+ *cc_out = ia32_cc_not_equal;
+ return flags;
+}
+
+static ir_node *get_flags_node_cmp(ir_node *node, ia32_condition_code_t *cc_out)
+{
+ /* must have a Proj(Cmp) as input */
+ ir_node *cmp = get_Proj_pred(node);
+ int pnc = get_Proj_pn_cmp(node);
+ ir_node *l = get_Cmp_left(cmp);
+ ir_mode *mode = get_irn_mode(l);
ir_node *flags;
- ir_node *new_op;
- ir_node *new_block;
- dbg_info *dbgi;
- /* we have a Cmp as input */
- if (is_Proj(node)) {
- ir_node *pred = get_Proj_pred(node);
- if (is_Cmp(pred)) {
- int pnc = get_Proj_pn_cmp(node);
- if (ia32_cg_config.use_bt && (pnc == pn_Cmp_Lg || pnc == pn_Cmp_Eq)) {
- ir_node *l = get_Cmp_left(pred);
- ir_node *r = get_Cmp_right(pred);
- if (is_And(l)) {
- ir_node *la = get_And_left(l);
- ir_node *ra = get_And_right(l);
- if (is_Shl(la)) {
- ir_node *c = get_Shl_left(la);
- if (is_Const_1(c) && is_Const_0(r)) {
- /* (1 << n) & ra) */
- ir_node *n = get_Shl_right(la);
- flags = gen_bt(pred, ra, n);
- /* we must generate a Jc/Jnc jump */
- pnc = pnc == pn_Cmp_Lg ? pn_Cmp_Lt : pn_Cmp_Ge;
- *pnc_out = ia32_pn_Cmp_unsigned | pnc;
- return flags;
- }
- }
- if (is_Shl(ra)) {
- ir_node *c = get_Shl_left(ra);
- if (is_Const_1(c) && is_Const_0(r)) {
- /* la & (1 << n)) */
- ir_node *n = get_Shl_right(ra);
- flags = gen_bt(pred, la, n);
- /* we must generate a Jc/Jnc jump */
- pnc = pnc == pn_Cmp_Lg ? pn_Cmp_Lt : pn_Cmp_Ge;
- *pnc_out = ia32_pn_Cmp_unsigned | pnc;
- return flags;
- }
- }
- }
+ /* check for bit-test */
+ if (ia32_cg_config.use_bt
+ && (pnc == pn_Cmp_Lg || pnc == pn_Cmp_Eq || pnc == pn_Cmp_Ne
+ || pnc == pn_Cmp_Ue)) {
+ ir_node *l = get_Cmp_left(cmp);
+ ir_node *r = get_Cmp_right(cmp);
+ if (is_And(l)) {
+ ir_node *la = get_And_left(l);
+ ir_node *ra = get_And_right(l);
+ if (is_Shl(ra)) {
+ ir_node *tmp = la;
+ la = ra;
+ ra = tmp;
}
- /* add ia32 compare flags */
- {
- ir_node *l = get_Cmp_left(pred);
- ir_mode *mode = get_irn_mode(l);
- if (mode_is_float(mode))
- pnc |= ia32_pn_Cmp_float;
- else if (! mode_is_signed(mode))
- pnc |= ia32_pn_Cmp_unsigned;
+ if (is_Shl(la)) {
+ ir_node *c = get_Shl_left(la);
+ if (is_Const_1(c) && is_Const_0(r)) {
+ /* (1 << n) & ra) */
+ ir_node *n = get_Shl_right(la);
+ flags = gen_bt(cmp, ra, n);
+ /* the bit is copied into the CF flag */
+ if (pnc & pn_Cmp_Eq)
+ *cc_out = ia32_cc_below; /* ==0, so we test for CF=1 */
+ else
+ *cc_out = ia32_cc_above_equal; /* test for CF=0 */
+ return flags;
+ }
}
- *pnc_out = pnc;
- flags = be_transform_node(pred);
- return flags;
}
}
- /* a mode_b value, we have to compare it against 0 */
- dbgi = get_irn_dbg_info(node);
- new_block = be_transform_node(get_nodes_block(node));
- new_op = be_transform_node(node);
- flags = new_bd_ia32_Test(dbgi, new_block, noreg_GP, noreg_GP, nomem, new_op,
- new_op, /*is_permuted=*/0, /*cmp_unsigned=*/0);
- *pnc_out = pn_Cmp_Lg;
+ /* just do a normal transformation of the Cmp */
+ *cc_out = pnc_to_condition_code(pnc, mode);
+ flags = be_transform_node(cmp);
return flags;
}
+/**
+ * Transform a node returning a "flag" result.
+ *
+ * @param node the node to transform
+ * @param cc_out the compare mode to use
+ */
+static ir_node *get_flags_node(ir_node *node, ia32_condition_code_t *cc_out)
+{
+ if (is_Proj(node) && is_Cmp(get_Proj_pred(node)))
+ return get_flags_node_cmp(node, cc_out);
+ assert(get_irn_mode(node) == mode_b);
+ return get_flags_mode_b(node, cc_out);
+}
+
/**
* Transforms a Load.
*
return new_node;
}
-static int ia32_get_negated_pnc(int pnc)
-{
- ir_mode *mode = pnc & ia32_pn_Cmp_float ? mode_F : mode_Iu;
- return get_negated_pnc(pnc, mode);
-}
-
static ir_node *try_create_SetMem(ir_node *node, ir_node *ptr, ir_node *mem)
{
- ir_mode *mode = get_irn_mode(node);
- ir_node *mux_true = get_Mux_true(node);
- ir_node *mux_false = get_Mux_false(node);
- ir_node *cond;
- dbg_info *dbgi;
- ir_node *block;
- ir_node *new_block;
- ir_node *flags;
- ir_node *new_node;
- bool negated;
- int pnc;
- ia32_address_t addr;
+ ir_mode *mode = get_irn_mode(node);
+ ir_node *mux_true = get_Mux_true(node);
+ ir_node *mux_false = get_Mux_false(node);
+ ir_node *cond;
+ dbg_info *dbgi;
+ ir_node *block;
+ ir_node *new_block;
+ ir_node *flags;
+ ir_node *new_node;
+ bool negated;
+ ia32_condition_code_t cc;
+ ia32_address_t addr;
if (get_mode_size_bits(mode) != 8)
return NULL;
}
cond = get_Mux_sel(node);
- flags = get_flags_node(cond, &pnc);
+ flags = get_flags_node(cond, &cc);
/* we can't handle the float special cases with SetM */
- if (pnc & ia32_pn_Cmp_float)
+ if (cc & ia32_cc_additional_float_cases)
return NULL;
if (negated)
- pnc = ia32_get_negated_pnc(pnc);
+ cc = ia32_negate_condition_code(cc);
build_address_ptr(&addr, ptr, mem);
block = get_nodes_block(node);
new_block = be_transform_node(block);
new_node = new_bd_ia32_SetccMem(dbgi, new_block, addr.base,
- addr.index, addr.mem, flags, pnc);
+ addr.index, addr.mem, flags, cc);
set_address(new_node, &addr);
set_ia32_op_type(new_node, ia32_AddrModeD);
set_ia32_ls_mode(new_node, mode);
*/
static ir_node *gen_Cond(ir_node *node)
{
- ir_node *block = get_nodes_block(node);
- ir_node *new_block = be_transform_node(block);
- dbg_info *dbgi = get_irn_dbg_info(node);
- ir_node *sel = get_Cond_selector(node);
- ir_mode *sel_mode = get_irn_mode(sel);
- ir_node *flags = NULL;
- ir_node *new_node;
- int pnc;
+ ir_node *block = get_nodes_block(node);
+ ir_node *new_block = be_transform_node(block);
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_node *sel = get_Cond_selector(node);
+ ir_mode *sel_mode = get_irn_mode(sel);
+ ir_node *flags = NULL;
+ ir_node *new_node;
+ ia32_condition_code_t cc;
if (sel_mode != mode_b) {
return create_Switch(node);
}
/* we get flags from a Cmp */
- flags = get_flags_node(sel, &pnc);
+ flags = get_flags_node(sel, &cc);
- new_node = new_bd_ia32_Jcc(dbgi, new_block, flags, pnc);
+ new_node = new_bd_ia32_Jcc(dbgi, new_block, flags, cc);
SET_IA32_ORIG_NODE(new_node, node);
return new_node;
ir_node *new_node;
ia32_address_mode_t am;
ia32_address_t *addr = &am.addr;
- int cmp_unsigned;
if (mode_is_float(cmp_mode)) {
if (ia32_cg_config.use_sse2) {
assert(ia32_mode_needs_gp_reg(cmp_mode));
/* Prefer the Test instruction, when encountering (x & y) ==/!= 0 */
- cmp_unsigned = !mode_is_signed(cmp_mode);
if (is_Const_0(right) &&
is_And(left) &&
get_irn_n_edges(left) == 1 &&
if (get_mode_size_bits(cmp_mode) == 8) {
new_node = new_bd_ia32_Test8Bit(dbgi, new_block, addr->base,
- addr->index, addr->mem, am.new_op1, am.new_op2, am.ins_permuted,
- cmp_unsigned);
+ addr->index, addr->mem, am.new_op1, am.new_op2, am.ins_permuted);
} else {
new_node = new_bd_ia32_Test(dbgi, new_block, addr->base, addr->index,
- addr->mem, am.new_op1, am.new_op2, am.ins_permuted, cmp_unsigned);
+ addr->mem, am.new_op1, am.new_op2, am.ins_permuted);
}
} else {
/* Cmp(left, right) */
if (get_mode_size_bits(cmp_mode) == 8) {
new_node = new_bd_ia32_Cmp8Bit(dbgi, new_block, addr->base,
addr->index, addr->mem, am.new_op1,
- am.new_op2, am.ins_permuted,
- cmp_unsigned);
+ am.new_op2, am.ins_permuted);
} else {
new_node = new_bd_ia32_Cmp(dbgi, new_block, addr->base, addr->index,
- addr->mem, am.new_op1, am.new_op2, am.ins_permuted, cmp_unsigned);
+ addr->mem, am.new_op1, am.new_op2, am.ins_permuted);
}
}
set_am_attributes(new_node, &am);
}
static ir_node *create_CMov(ir_node *node, ir_node *flags, ir_node *new_flags,
- int pnc)
+ ia32_condition_code_t cc)
{
dbg_info *dbgi = get_irn_dbg_info(node);
ir_node *block = get_nodes_block(node);
match_commutative | match_am | match_16bit_am | match_mode_neutral);
if (am.ins_permuted)
- pnc = ia32_get_negated_pnc(pnc);
+ cc = ia32_invert_condition_code(cc);
new_node = new_bd_ia32_CMovcc(dbgi, new_block, addr->base, addr->index,
addr->mem, am.new_op1, am.new_op2, new_flags,
- pnc);
+ cc);
set_am_attributes(new_node, &am);
SET_IA32_ORIG_NODE(new_node, node);
* Creates a ia32 Setcc instruction.
*/
static ir_node *create_set_32bit(dbg_info *dbgi, ir_node *new_block,
- ir_node *flags, int pnc,
+ ir_node *flags, ia32_condition_code_t cc,
ir_node *orig_node)
{
ir_mode *mode = get_irn_mode(orig_node);
ir_node *new_node;
- new_node = new_bd_ia32_Setcc(dbgi, new_block, flags, pnc);
+ new_node = new_bd_ia32_Setcc(dbgi, new_block, flags, cc);
SET_IA32_ORIG_NODE(new_node, orig_node);
/* we might need to conv the result up */
};
typedef struct setcc_transform {
- unsigned num_steps;
- int pnc;
+ unsigned num_steps;
+ ia32_condition_code_t cc;
struct {
enum setcc_transform_insn transform;
long val;
* Find a transformation that creates 0 and 1 from
* tv_t and tv_f.
*/
-static void find_const_transform(int pnc, ir_tarval *t, ir_tarval *f,
+static void find_const_transform(ia32_condition_code_t cc,
+ ir_tarval *t, ir_tarval *f,
setcc_transform_t *res)
{
unsigned step = 0;
ir_tarval *tmp = t;
t = f;
f = tmp;
- pnc = ia32_get_negated_pnc(pnc);
+ cc = ia32_negate_condition_code(cc);
} else if (tarval_cmp(t, f) == pn_Cmp_Lt) {
// now, t is the bigger one
ir_tarval *tmp = t;
t = f;
f = tmp;
- pnc = ia32_get_negated_pnc(pnc);
+ cc = ia32_negate_condition_code(cc);
}
- res->pnc = pnc;
+ res->cc = cc;
if (! tarval_is_null(f)) {
ir_tarval *t_sub = tarval_sub(t, f, NULL);
*/
static ir_node *gen_Mux(ir_node *node)
{
- dbg_info *dbgi = get_irn_dbg_info(node);
- ir_node *block = get_nodes_block(node);
- ir_node *new_block = be_transform_node(block);
- ir_node *mux_true = get_Mux_true(node);
- ir_node *mux_false = get_Mux_false(node);
- ir_node *cond = get_Mux_sel(node);
- ir_mode *mode = get_irn_mode(node);
- ir_node *flags;
- ir_node *new_node;
- int is_abs;
- int pnc;
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_node *block = get_nodes_block(node);
+ ir_node *new_block = be_transform_node(block);
+ ir_node *mux_true = get_Mux_true(node);
+ ir_node *mux_false = get_Mux_false(node);
+ ir_node *cond = get_Mux_sel(node);
+ ir_mode *mode = get_irn_mode(node);
+ ir_node *flags;
+ ir_node *new_node;
+ int is_abs;
+ ia32_condition_code_t cc;
assert(get_irn_mode(cond) == mode_b);
ir_mode *new_mode;
unsigned scale;
- flags = get_flags_node(cond, &pnc);
- new_node = create_set_32bit(dbgi, new_block, flags, pnc, node);
+ flags = get_flags_node(cond, &cc);
+ new_node = create_set_32bit(dbgi, new_block, flags, cc, node);
if (ia32_cg_config.use_sse2) {
/* cannot load from different mode on SSE */
am.new_op2 = NULL;
am.pinned = op_pin_state_floats;
am.commutative = 1;
- am.ins_permuted = 0;
+ am.ins_permuted = false;
if (ia32_cg_config.use_sse2)
load = new_bd_ia32_xLoad(dbgi, block, am.addr.base, am.addr.index, am.addr.mem, new_mode);
ir_node *tmp = val_false;
val_false = val_true;
val_true = tmp;
- pnc = ia32_get_negated_pnc(pnc);
+ pnc = get_negated_pnc(pnc, get_irn_mode(cmp_left));
}
if (is_Const_0(val_false) && is_Sub(val_true)) {
if ((pnc == pn_Cmp_Gt || pnc == pn_Cmp_Ge)
}
}
- flags = get_flags_node(cond, &pnc);
+ flags = get_flags_node(cond, &cc);
if (is_Const(mux_true) && is_Const(mux_false)) {
/* both are const, good */
setcc_transform_t res;
int step;
- find_const_transform(pnc, tv_true, tv_false, &res);
+ find_const_transform(cc, tv_true, tv_false, &res);
new_node = node;
for (step = (int)res.num_steps - 1; step >= 0; --step) {
ir_node *imm;
new_node = new_bd_ia32_And(dbgi, new_block, noreg_GP, noreg_GP, nomem, new_node, imm);
break;
case SETCC_TR_SET:
- new_node = create_set_32bit(dbgi, new_block, flags, res.pnc, node);
+ new_node = create_set_32bit(dbgi, new_block, flags, res.cc, node);
break;
case SETCC_TR_SBB:
new_node = new_bd_ia32_Sbb0(dbgi, new_block, flags);
}
}
} else {
- new_node = create_CMov(node, cond, flags, pnc);
+ new_node = create_CMov(node, cond, flags, cc);
}
return new_node;
}
return new_node;
}
-/**
- * Transform a Bound node.
- */
-static ir_node *gen_Bound(ir_node *node)
-{
- ir_node *new_node;
- ir_node *lower = get_Bound_lower(node);
- dbg_info *dbgi = get_irn_dbg_info(node);
-
- if (is_Const_0(lower)) {
- /* typical case for Java */
- ir_node *sub, *res, *flags, *block;
-
- res = gen_binop(node, get_Bound_index(node), get_Bound_upper(node),
- new_bd_ia32_Sub,
- match_mode_neutral | match_am | match_immediate);
-
- block = get_nodes_block(res);
- if (! is_Proj(res)) {
- sub = res;
- set_irn_mode(sub, mode_T);
- res = new_rd_Proj(NULL, sub, mode_Iu, pn_ia32_res);
- } else {
- sub = get_Proj_pred(res);
- }
- flags = new_rd_Proj(NULL, sub, mode_Iu, pn_ia32_Sub_flags);
- new_node = new_bd_ia32_Jcc(dbgi, block, flags, pn_Cmp_Lt | ia32_pn_Cmp_unsigned);
- SET_IA32_ORIG_NODE(new_node, node);
- } else {
- panic("generic Bound not supported in ia32 Backend");
- }
- return new_node;
-}
-
-
static ir_node *gen_ia32_l_ShlDep(ir_node *node)
{
ir_node *left = get_irn_n(node, n_ia32_l_ShlDep_val);
am.new_op2 = ia32_new_NoReg_vfp(current_ir_graph);
am.pinned = op_pin_state_floats;
am.commutative = 1;
- am.ins_permuted = 0;
+ am.ins_permuted = false;
fadd = new_bd_ia32_vfadd(dbgi, block, am.addr.base, am.addr.index, am.addr.mem,
am.new_op1, am.new_op2, get_fpcw());
match_arguments(&am, block, NULL, param, NULL, match_am);
imm = ia32_create_Immediate(NULL, 0, 0);
cmp = new_bd_ia32_Cmp(dbgi, new_block, addr->base, addr->index,
- addr->mem, imm, am.new_op2, am.ins_permuted, 0);
+ addr->mem, imm, am.new_op2, am.ins_permuted);
set_am_attributes(cmp, &am);
set_ia32_ls_mode(cmp, mode_Iu);
cmp = fix_mem_proj(cmp, &am);
/* setp */
- new_node = new_bd_ia32_Setcc(dbgi, new_block, cmp, ia32_pn_Cmp_parity);
+ new_node = new_bd_ia32_Setcc(dbgi, new_block, cmp, ia32_cc_parity);
SET_IA32_ORIG_NODE(new_node, node);
/* conv to 32bit */
node);
}
-/**
- * Transform the Projs from a Bound.
- */
-static ir_node *gen_Proj_Bound(ir_node *node)
-{
- ir_node *new_node;
- ir_node *pred = get_Proj_pred(node);
-
- switch (get_Proj_proj(node)) {
- case pn_Bound_M:
- return be_transform_node(get_Bound_mem(pred));
- case pn_Bound_X_regular:
- new_node = be_transform_node(pred);
- return new_r_Proj(new_node, mode_X, pn_ia32_Jcc_true);
- case pn_Bound_X_except:
- new_node = be_transform_node(pred);
- return new_r_Proj(new_node, mode_X, pn_ia32_Jcc_false);
- case pn_Bound_res:
- return be_transform_node(get_Bound_index(pred));
- default:
- panic("unsupported Proj from Bound");
- }
-}
-
static ir_node *gen_Proj_ASM(ir_node *node)
{
ir_mode *mode = get_irn_mode(node);
return gen_Proj_be_Call(node);
case iro_Cmp:
return gen_Proj_Cmp(node);
- case iro_Bound:
- return gen_Proj_Bound(node);
case iro_Start:
proj = get_Proj_proj(node);
switch (proj) {
be_set_transform_function(op_be_IncSP, gen_be_IncSP);
be_set_transform_function(op_be_Return, gen_be_Return);
be_set_transform_function(op_be_SubSP, gen_be_SubSP);
- be_set_transform_function(op_Bound, gen_Bound);
be_set_transform_function(op_Builtin, gen_Builtin);
be_set_transform_function(op_Cmp, gen_Cmp);
be_set_transform_function(op_Cond, gen_Cond);