return get_irn_link(block);
}
+/** Checks if the current block is a fall-through target. */
static int is_fallthrough(const ir_node *cfgpred)
{
ir_node *pred;
return 1;
}
+/**
+ * returns non-zero if the given block needs a label
+ * because of being a jump-target (and not a fall-through)
+ */
static int block_needs_label(const ir_node *block)
{
int need_label = 1;
* |_| |_|
*************************************************************/
+/**
+ * Emit the name of the 8bit low register
+ */
static void emit_8bit_register(const arch_register_t *reg)
{
const char *reg_name = arch_register_get_name(reg);
be_emit_char('l');
}
+/**
+ * Emit the name of the 8bit high register
+ */
+static void emit_8bit_register_high(const arch_register_t *reg)
+{
+ const char *reg_name = arch_register_get_name(reg);
+
+ be_emit_char('%');
+ be_emit_char(reg_name[1]);
+ be_emit_char('h');
+}
+
static void emit_16bit_register(const arch_register_t *reg)
{
const char *reg_name = ia32_get_mapped_reg_name(isa->regs_16bit, reg);
be_emit_string(reg_name);
}
+/**
+ * emit a register, possible shortened by a mode
+ *
+ * @param reg the register
+ * @param mode the mode of the register or NULL for full register
+ */
static void emit_register(const arch_register_t *reg, const ir_mode *mode)
{
const char *reg_name;
void ia32_emit_8bit_source_register_or_immediate(const ir_node *node, int pos)
{
const arch_register_t *reg;
- ir_node *in = get_irn_n(node, pos);
+ const ir_node *in = get_irn_n(node, pos);
if (is_ia32_Immediate(in)) {
emit_ia32_Immediate(in);
return;
emit_8bit_register(reg);
}
+void ia32_emit_8bit_high_source_register(const ir_node *node, int pos)
+{
+ const arch_register_t *reg = get_in_reg(node, pos);
+ emit_8bit_register_high(reg);
+}
+
+void ia32_emit_16bit_source_register_or_immediate(const ir_node *node, int pos)
+{
+ const arch_register_t *reg;
+ const ir_node *in = get_irn_n(node, pos);
+ if (is_ia32_Immediate(in)) {
+ emit_ia32_Immediate(in);
+ return;
+ }
+
+ reg = get_in_reg(node, pos);
+ emit_16bit_register(reg);
+}
+
void ia32_emit_dest_register(const ir_node *node, int pos)
{
const arch_register_t *reg = get_out_reg(node, pos);
emit_register(reg, NULL);
}
+void ia32_emit_dest_register_size(const ir_node *node, int pos)
+{
+ const arch_register_t *reg = get_out_reg(node, pos);
+
+ emit_register(reg, get_ia32_ls_mode(node));
+}
+
void ia32_emit_8bit_dest_register(const ir_node *node, int pos)
{
const arch_register_t *reg = get_out_reg(node, pos);
be_emit_char(get_xmm_mode_suffix(mode));
}
-void ia32_emit_extend_suffix(const ir_mode *mode)
+void ia32_emit_extend_suffix(const ir_node *node)
{
+ ir_mode *mode = get_ia32_ls_mode(node);
if (get_mode_size_bits(mode) == 32)
return;
be_emit_char(mode_is_signed(mode) ? 's' : 'z');
+ ia32_emit_mode_suffix_mode(mode);
}
void ia32_emit_source_register_or_immediate(const ir_node *node, int pos)
ia32_emit_block_name(block);
}
-/*
- * coding of conditions
- */
-struct cmp2conditon_t {
- const char *name;
- int num;
-};
-
/*
* positive conditions for signed compares
*/
-static const struct cmp2conditon_t cmp2condition_s[] = {
- { NULL, pn_Cmp_False }, /* always false */
- { "e", pn_Cmp_Eq }, /* == */
- { "l", pn_Cmp_Lt }, /* < */
- { "le", pn_Cmp_Le }, /* <= */
- { "g", pn_Cmp_Gt }, /* > */
- { "ge", pn_Cmp_Ge }, /* >= */
- { "ne", pn_Cmp_Lg }, /* != */
- { NULL, pn_Cmp_Leg}, /* always true */
+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 struct cmp2conditon_t cmp2condition_u[] = {
- { NULL, pn_Cmp_False }, /* always false */
- { "e", pn_Cmp_Eq }, /* == */
- { "b", pn_Cmp_Lt }, /* < */
- { "be", pn_Cmp_Le }, /* <= */
- { "a", pn_Cmp_Gt }, /* > */
- { "ae", pn_Cmp_Ge }, /* >= */
- { "ne", pn_Cmp_Lg }, /* != */
- { NULL, pn_Cmp_Leg }, /* always true */
+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_float) || (pnc & ia32_pn_Cmp_unsigned)) {
- pnc = pnc & 7;
- assert(cmp2condition_u[pnc].num == pnc);
- str = cmp2condition_u[pnc].name;
+ 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 {
- pnc = pnc & 7;
- assert(cmp2condition_s[pnc].num == pnc);
- str = cmp2condition_s[pnc].name;
+ str = cmp2condition_s[pnc & 7];
}
be_emit_string(str);
typedef enum ia32_emit_mod_t {
EMIT_RESPECT_LS = 1U << 0,
- EMIT_ALTERNATE_AM = 1U << 1
+ EMIT_ALTERNATE_AM = 1U << 1,
+ EMIT_LONG = 1U << 2
} ia32_emit_mod_t;
/**
* %Sx <node> source register x
* %s const char* string
* %u unsigned int unsigned int
+ * %d signed int signed int
*
* x starts at 0
* # modifier for %ASx, %D and %S uses ls mode of node to alter register width
* * modifier does not prefix immediates with $, but AM with *
+ * l modifier for %lu and %ld
*/
static void ia32_emitf(const ir_node *node, const char *fmt, ...)
{
++fmt;
}
+ if (*fmt == 'l') {
+ mod |= EMIT_LONG;
+ ++fmt;
+ }
+
switch (*fmt++) {
case '%':
be_emit_char('%');
break;
}
- case 'u': {
- unsigned num = va_arg(ap, unsigned);
- be_emit_irprintf("%u", num);
+ case 'u':
+ if (mod & EMIT_LONG) {
+ unsigned long num = va_arg(ap, unsigned long);
+ be_emit_irprintf("%lu", num);
+ } else {
+ unsigned num = va_arg(ap, unsigned);
+ be_emit_irprintf("%u", num);
+ }
+ break;
+
+ case 'd':
+ if (mod & EMIT_LONG) {
+ long num = va_arg(ap, long);
+ be_emit_irprintf("%ld", num);
+ } else {
+ int num = va_arg(ap, int);
+ be_emit_irprintf("%d", num);
+ }
break;
- }
default:
unknown:
- panic("unknown conversion");
+ panic("unknown format conversion in ia32_emitf()");
}
}
return pnc;
}
+static pn_Cmp ia32_get_negated_pnc(pn_Cmp pnc)
+{
+ ir_mode *mode = pnc & ia32_pn_Cmp_float ? mode_F : mode_Iu;
+ return get_negated_pnc(pnc, mode);
+}
+
void ia32_emit_cmp_suffix_node(const ir_node *node,
int flags_pos)
{
pn_Cmp pnc = get_ia32_condcode(node);
pnc = determine_final_pnc(node, flags_pos, pnc);
- if (attr->data.ins_permuted) {
- if (pnc & ia32_pn_Cmp_float) {
- pnc = get_negated_pnc(pnc, mode_F);
- } else {
- pnc = get_negated_pnc(pnc, mode_Iu);
- }
- }
+ if (attr->data.ins_permuted)
+ pnc = ia32_get_negated_pnc(pnc);
ia32_emit_cmp_suffix(pnc);
}
proj_true = proj_false;
proj_false = t;
- if (pnc & ia32_pn_Cmp_float) {
- pnc = get_negated_pnc(pnc, mode_F);
- } else {
- pnc = get_negated_pnc(pnc, mode_Iu);
- }
+ pnc = ia32_get_negated_pnc(pnc);
}
if (pnc & ia32_pn_Cmp_float) {
ia32_emitf(node, "\tmovl %R, %R\n", in_false, out);
}
- if (ins_permuted) {
- if (pnc & ia32_pn_Cmp_float) {
- pnc = get_negated_pnc(pnc, mode_F);
- } else {
- pnc = get_negated_pnc(pnc, mode_Iu);
- }
- }
+ if (ins_permuted)
+ pnc = ia32_get_negated_pnc(pnc);
/* TODO: handling of Nans isn't correct yet */
- ia32_emitf(node, "\tcmov%P %AR, %#R\n", pnc, in_true, out);
+ ia32_emitf(node, "\tcmov%P %#AR, %#R\n", pnc, in_true, out);
}
/*********************************************************
/* parse modifiers */
switch(c) {
case 0:
- ir_fprintf(stderr, "Warning: asm text (%+F) ends with %\n", node);
+ ir_fprintf(stderr, "Warning: asm text (%+F) ends with %%\n", node);
be_emit_char('%');
return s + 1;
case '%':
case '9':
break;
default:
- ir_fprintf(stderr, "Warning: asm text (%+F) contains unknown modifier "
- "'%c' for asm op\n", node, c);
+ ir_fprintf(stderr,
+ "Warning: asm text (%+F) contains unknown modifier '%c' for asm op\n",
+ node, c);
++s;
break;
}
s += p;
}
- if (num < 0 || num >= ARR_LEN(asm_regs)) {
- ir_fprintf(stderr, "Error: Custom assembler references invalid "
- "input/output (%+F)\n", node);
+ if (num < 0 || ARR_LEN(asm_regs) <= num) {
+ ir_fprintf(stderr,
+ "Error: Custom assembler references invalid input/output (%+F)\n",
+ node);
return s;
}
asm_reg = & asm_regs[num];
reg = get_in_reg(node, asm_reg->inout_pos);
}
if (reg == NULL) {
- ir_fprintf(stderr, "Warning: no register assigned for %d asm op "
- "(%+F)\n", num, node);
+ ir_fprintf(stderr,
+ "Warning: no register assigned for %d asm op (%+F)\n",
+ num, node);
return s;
}
/**
* Emit code for conversions (I, FP), (FP, I) and (FP, FP).
*/
-static void emit_ia32_Conv_with_FP(const ir_node *node)
+static void emit_ia32_Conv_with_FP(const ir_node *node, const char* conv_f,
+ const char* conv_d)
{
ir_mode *ls_mode = get_ia32_ls_mode(node);
int ls_bits = get_mode_size_bits(ls_mode);
- const char *conv;
-
- if (is_ia32_Conv_I2FP(node)) {
- if (ls_bits == 32) {
- conv = "si2ss";
- } else {
- conv = "si2sd";
- }
- } else if (is_ia32_Conv_FP2I(node)) {
- if (ls_bits == 32) {
- conv = "ss2si";
- } else {
- conv = "sd2si";
- }
- } else {
- assert(is_ia32_Conv_FP2FP(node));
- if (ls_bits == 32) {
- conv = "sd2ss";
- } else {
- conv = "ss2sd";
- }
- }
+ const char *conv = ls_bits == 32 ? conv_f : conv_d;
ia32_emitf(node, "\tcvt%s %AS3, %D0\n", conv);
}
static void emit_ia32_Conv_I2FP(const ir_node *node)
{
- emit_ia32_Conv_with_FP(node);
+ emit_ia32_Conv_with_FP(node, "si2ss", "si2sd");
}
static void emit_ia32_Conv_FP2I(const ir_node *node)
{
- emit_ia32_Conv_with_FP(node);
+ emit_ia32_Conv_with_FP(node, "ss2si", "sd2si");
}
static void emit_ia32_Conv_FP2FP(const ir_node *node)
{
- emit_ia32_Conv_with_FP(node);
+ emit_ia32_Conv_with_FP(node, "sd2ss", "ss2sd");
}
/**
static void emit_ia32_Conv_I2I(const ir_node *node)
{
ir_mode *smaller_mode = get_ia32_ls_mode(node);
- int smaller_bits = get_mode_size_bits(smaller_mode);
int signed_mode = mode_is_signed(smaller_mode);
+ const char *sign_suffix;
assert(!mode_is_float(smaller_mode));
- assert(smaller_bits == 8 || smaller_bits == 16);
-
- const arch_register_t *eax = &ia32_gp_regs[REG_EAX];
- if (signed_mode &&
- smaller_bits == 16 &&
- eax == get_out_reg(node, 0) &&
- eax == arch_get_irn_register(get_irn_n(node, n_ia32_unary_op))) {
- /* argument and result are both in EAX and signedness is ok: use the
- * smaller cwtl opcode */
- ia32_emitf(node, "\tcwtl\n");
- } else {
- const char *sign_suffix = signed_mode ? "s" : "z";
- ia32_emitf(node, "\tmov%s%Ml %#AS3, %D0\n", sign_suffix);
- }
+
+ sign_suffix = signed_mode ? "s" : "z";
+ ia32_emitf(node, "\tmov%s%Ml %#AS3, %D0\n", sign_suffix);
}
/**
ia32_emitf(node, "\tpopl %D0\n");
}
+static void emit_ia32_ClimbFrame(const ir_node *node)
+{
+ const ia32_climbframe_attr_t *attr = get_ia32_climbframe_attr_const(node);
+
+ ia32_emitf(node, "\tmovl %S0, %D0\n");
+ ia32_emitf(node, "\tmovl $%u, %S1\n", attr->count);
+ ia32_emitf(NULL, BLOCK_PREFIX "%ld:\n", get_irn_node_nr(node));
+ ia32_emitf(node, "\tmovl (%D0), %D0\n");
+ ia32_emitf(node, "\tdec %S1\n");
+ ia32_emitf(node, "\tjnz " BLOCK_PREFIX "%ld\n", get_irn_node_nr(node));
+}
+
static void emit_be_Return(const ir_node *node)
{
unsigned pop = be_Return_get_pop(node);
IA32_EMIT(LdTls);
IA32_EMIT(Minus64Bit);
IA32_EMIT(SwitchJmp);
+ IA32_EMIT(ClimbFrame);
/* benode emitter */
BE_EMIT(Copy);
int i, arity;
ir_exec_freq *exec_freq = cg->birg->exec_freq;
- if (block == get_irg_end_block(irg) || block == get_irg_start_block(irg))
+ if (block == get_irg_end_block(irg))
return;
if (ia32_cg_config.label_alignment > 0) {
/* emit list of pred blocks in comment */
arity = get_irn_arity(block);
- for (i = 0; i < arity; ++i) {
- ir_node *predblock = get_Block_cfgpred_block(block, i);
- be_emit_irprintf(" %d", get_irn_node_nr(predblock));
+ if (arity <= 0) {
+ be_emit_cstring(" none");
+ } else {
+ for (i = 0; i < arity; ++i) {
+ ir_node *predblock = get_Block_cfgpred_block(block, i);
+ be_emit_irprintf(" %d", get_irn_node_nr(predblock));
+ }
}
if (exec_freq != NULL) {
- be_emit_irprintf(" freq: %f",
+ be_emit_irprintf(", freq: %f",
get_block_execfreq(exec_freq, block));
}
be_emit_cstring(" */\n");