#include "../be_dbgout.h"
#include "../beemitter.h"
#include "../begnuas.h"
+#include "../beirg_t.h"
#include "ia32_emitter.h"
#include "gen_ia32_emitter.h"
return 't';
}
} else {
- assert(mode_is_int(mode) || mode_is_reference(mode));
+ assert(mode_is_int(mode) || mode_is_reference(mode) || mode_is_character(mode));
switch(get_mode_size_bits(mode)) {
case 64:
return 'q';
ir_entity *ent;
ident *id;
+ be_emit_char(env, '$');
+
switch(get_ia32_immop_type(node)) {
case ia32_ImmConst:
tv = get_ia32_Immop_tarval(node);
switch(get_ia32_op_type(node)) {
case ia32_Normal:
if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) {
- be_emit_char(env, '$');
ia32_emit_immediate(env, node);
be_emit_cstring(env, ", ");
ia32_emit_source_register(env, node, 2);
}
break;
case ia32_AddrModeS:
+ ia32_emit_am(env, node);
+ be_emit_cstring(env, ", ");
if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) {
assert(!produces_result(node) && "Source AM with Const must not produce result");
- ia32_emit_am(env, node);
- be_emit_cstring(env, ", $");
ia32_emit_immediate(env, node);
} else if (produces_result(node)) {
- ia32_emit_am(env, node);
- be_emit_cstring(env, ", ");
ia32_emit_dest_register(env, node, 0);
} else {
- ia32_emit_am(env, node);
- be_emit_cstring(env, ", ");
ia32_emit_source_register(env, node, 2);
}
break;
case ia32_AddrModeD:
if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) {
- be_emit_char(env, '$');
ia32_emit_immediate(env, node);
be_emit_cstring(env, ", ");
ia32_emit_am(env, node);
switch(get_ia32_op_type(node)) {
case ia32_Normal:
if (is_ia32_ImmConst(node) || is_ia32_ImmSymConst(node)) {
- be_emit_char(env, '$');
ia32_emit_immediate(env, node);
} else {
if (is_ia32_Mul(node) || is_ia32_IMul1OP(node)) {
return get_irn_link(irn);
}
+static
+void ia32_emit_block_name(ia32_emit_env_t *env, const ir_node *block)
+{
+ be_emit_cstring(env, BLOCK_PREFIX);
+ be_emit_irprintf(env->emit, "%d", get_irn_node_nr(block));
+}
+
/**
* Returns the target label for a control flow node.
*/
+static
void ia32_emit_cfop_target(ia32_emit_env_t * env, const ir_node *node) {
ir_node *block = get_cfop_target_block(node);
- be_emit_cstring(env, BLOCK_PREFIX);
- be_emit_irprintf(env->emit, "%d", get_irn_node_nr(block));
+ ia32_emit_block_name(env, block);
}
/** Return the next block in Block schedule */
ia32_emit_cfop_target(env, proj_false);
be_emit_finish_line_gas(env, proj_false);
} else {
- be_emit_cstring(env, "\t/* fallthrough to");
+ be_emit_cstring(env, "\t/* fallthrough to ");
ia32_emit_cfop_target(env, proj_false);
be_emit_cstring(env, " */");
be_emit_finish_line_gas(env, proj_false);
static
void TestJmp_emitter(ia32_emit_env_t *env, const ir_node *node) {
if(is_ia32_ImmSymConst(node) || is_ia32_ImmConst(node)) {
- be_emit_cstring(env, "\ttest $");
+ be_emit_cstring(env, "\ttest ");
ia32_emit_immediate(env, node);
be_emit_cstring(env, ", ");
ia32_emit_source_register(env, node, 0);
void Copy_emitter(ia32_emit_env_t *env, const ir_node *node, const ir_node *op)
{
const arch_env_t *aenv = env->arch_env;
+ ir_mode *mode;
if (REGS_ARE_EQUAL(arch_get_irn_register(aenv, node), arch_get_irn_register(aenv, op)) ||
arch_register_type_is(arch_get_irn_register(aenv, op), virtual))
return;
- if (mode_is_float(get_irn_mode(node))) {
+ mode = get_irn_mode(node);
+ if (mode == mode_E) {
be_emit_cstring(env, "\tmovsd ");
ia32_emit_source_register(env, node, 0);
be_emit_cstring(env, ", ");
ia32_immop_type_t imm_tp = get_ia32_immop_type(node);
if (imm_tp == ia32_ImmSymConst) {
- be_emit_cstring(env, "\tmovl $");
+ be_emit_cstring(env, "\tmovl ");
ia32_emit_immediate(env, node);
be_emit_cstring(env, ", ");
ia32_emit_dest_register(env, node, 0);
be_emit_cstring(env, ", ");
ia32_emit_dest_register(env, node, 0);
} else {
- be_emit_cstring(env, "\tmovl $");
+ be_emit_cstring(env, "\tmovl ");
ia32_emit_immediate(env, node);
be_emit_cstring(env, ", ");
ia32_emit_dest_register(env, node, 0);
ia32_emit_alignment(env, align, maximum_skip);
}
+/**
+ * Test wether a block should be aligned.
+ * For cpus in the P4/Athlon class it is usefull to align jump labels to
+ * 16 bytes. However we should only do that if the alignment nops before the
+ * label aren't executed more often than we have jumps to the label.
+ */
static
-int is_first_loop_block(ia32_emit_env_t *env, ir_node *block, ir_node *prev_block) {
- ir_exec_freq *exec_freq = env->cg->birg->exec_freq;
- double block_freq, prev_freq;
+int should_align_block(ia32_emit_env_t *env, ir_node *block, ir_node *prev) {
static const double DELTA = .0001;
- cpu_support cpu = env->isa->opt_arch;
+ ir_exec_freq *exec_freq = env->cg->birg->exec_freq;
+ double block_freq;
+ double prev_freq = 0; /**< execfreq of the fallthrough block */
+ double jmp_freq = 0; /**< execfreq of all non-fallthrough blocks */
+ cpu_support cpu = env->isa->opt_arch;
+ int i, n_cfgpreds;
if(exec_freq == NULL)
return 0;
return 0;
block_freq = get_block_execfreq(exec_freq, block);
- prev_freq = get_block_execfreq(exec_freq, prev_block);
-
- if(block_freq < DELTA || prev_freq < DELTA)
+ if(block_freq < DELTA)
return 0;
- block_freq /= prev_freq;
+ n_cfgpreds = get_Block_n_cfgpreds(block);
+ for(i = 0; i < n_cfgpreds; ++i) {
+ ir_node *pred = get_Block_cfgpred_block(block, i);
+ double pred_freq = get_block_execfreq(exec_freq, pred);
+
+ if(pred == prev) {
+ assert(prev_freq == 0);
+ prev_freq += pred_freq;
+ } else {
+ jmp_freq += pred_freq;
+ }
+ }
+
+ if(prev_freq < DELTA && !(jmp_freq < DELTA))
+ return 1;
+
+ jmp_freq /= prev_freq;
switch (cpu) {
case arch_athlon:
case arch_athlon_64:
case arch_k6:
- return block_freq > 3;
+ return jmp_freq > 3;
default:
- break;
+ return jmp_freq > 2;
}
-
- return block_freq > 2;
}
-/**
- * Walks over the nodes in a block connected by scheduling edges
- * and emits code for each node.
- */
static
-void ia32_gen_block(ia32_emit_env_t *env, ir_node *block, ir_node *last_block) {
- ir_graph *irg = get_irn_irg(block);
- ir_node *start_block = get_irg_start_block(irg);
- int need_label = 1;
- const ir_node *node;
- int i;
-
- assert(is_Block(block));
-
- if (block == start_block)
+void ia32_emit_block_header(ia32_emit_env_t *env, ir_node *block, ir_node *prev)
+{
+ int n_cfgpreds;
+ int need_label;
+ int i, arity;
+ ir_exec_freq *exec_freq = env->cg->birg->exec_freq;
+
+ need_label = 1;
+ n_cfgpreds = get_Block_n_cfgpreds(block);
+ if (n_cfgpreds == 0) {
need_label = 0;
-
- if (need_label && get_irn_arity(block) == 1) {
- ir_node *pred_block = get_Block_cfgpred_block(block, 0);
-
- if (pred_block == last_block && get_irn_n_edges_kind(pred_block, EDGE_KIND_BLOCK) <= 2)
+ } else if (n_cfgpreds == 1) {
+ ir_node *pred = get_Block_cfgpred(block, 0);
+ ir_node *pred_block = get_nodes_block(pred);
+
+ /* we don't need labels for fallthrough blocks, however switch-jmps
+ * are no fallthoughs */
+ if(pred_block == prev &&
+ !(is_Proj(pred) && is_ia32_SwitchJmp(get_Proj_pred(pred)))) {
need_label = 0;
- }
-
- /* special case: if one of our cfg preds is a switch-jmp we need a label, */
- /* otherwise there might be jump table entries jumping to */
- /* non-existent (omitted) labels */
- for (i = get_Block_n_cfgpreds(block) - 1; i >= 0; --i) {
- ir_node *pred = get_Block_cfgpred(block, i);
-
- if (is_Proj(pred)) {
- assert(get_irn_mode(pred) == mode_X);
- if (is_ia32_SwitchJmp(get_Proj_pred(pred))) {
- need_label = 1;
- break;
- }
+ } else {
+ need_label = 1;
}
+ } else {
+ need_label = 1;
}
- if (need_label) {
- int i, arity;
- int align = 1;
- ir_exec_freq *exec_freq = env->cg->birg->exec_freq;
-
- /* align the loop headers */
- if (! is_first_loop_block(env, block, last_block)) {
- /* align blocks where the previous block has no fallthrough */
- arity = get_irn_arity(block);
-
- for (i = 0; i < arity; ++i) {
- ir_node *predblock = get_Block_cfgpred_block(block, i);
-
- if (predblock == last_block) {
- align = 0;
- break;
- }
- }
- }
+ if (should_align_block(env, block, prev)) {
+ assert(need_label);
+ ia32_emit_align_label(env, env->isa->opt_arch);
+ }
- if (align)
- ia32_emit_align_label(env, env->isa->opt_arch);
+ if(need_label) {
+ ia32_emit_block_name(env, block);
+ be_emit_char(env, ':');
- be_emit_cstring(env, BLOCK_PREFIX);
- be_emit_irprintf(env->emit, "%d:", get_irn_node_nr(block));
be_emit_pad_comment(env);
be_emit_cstring(env, " /* preds:");
}
if (exec_freq != NULL) {
- be_emit_irprintf(env->emit, " freq: %f", get_block_execfreq(exec_freq, block));
+ be_emit_irprintf(env->emit, " freq: %f",
+ get_block_execfreq(exec_freq, block));
}
be_emit_cstring(env, " */\n");
- be_emit_write_line(env);
+ } else {
+ be_emit_cstring(env, "\t/* ");
+ ia32_emit_block_name(env, block);
+ be_emit_cstring(env, ": */\n");
}
+ be_emit_write_line(env);
+}
+
+/**
+ * Walks over the nodes in a block connected by scheduling edges
+ * and emits code for each node.
+ */
+static
+void ia32_gen_block(ia32_emit_env_t *env, ir_node *block, ir_node *last_block)
+{
+ const ir_node *node;
+
+ ia32_emit_block_header(env, block, last_block);
/* emit the contents of the block */
ia32_emit_dbg(env, block);
env.arch_env = cg->arch_env;
env.cg = cg;
- /* we mark referenced global entities */
- inc_master_type_visited();
-
ia32_register_emitters();
ia32_emit_func_prolog(&env, irg);