static char pic_base_label[128];
static ir_label_t exc_label_id;
+/** Return the next block in Block schedule */
+static ir_node *get_prev_block_sched(const ir_node *block)
+{
+ return get_irn_link(block);
+}
+
+static int is_fallthrough(const ir_node *cfgpred)
+{
+ ir_node *pred;
+
+ if(!is_Proj(cfgpred))
+ return 1;
+ pred = get_Proj_pred(cfgpred);
+ if(is_ia32_SwitchJmp(pred))
+ return 0;
+
+ return 1;
+}
+
+static int block_needs_label(const ir_node *block)
+{
+ int need_label = 1;
+ int n_cfgpreds = get_Block_n_cfgpreds(block);
+
+ if (n_cfgpreds == 0) {
+ need_label = 0;
+ } else if (n_cfgpreds == 1) {
+ ir_node *cfgpred = get_Block_cfgpred(block, 0);
+ ir_node *cfgpred_block = get_nodes_block(cfgpred);
+
+ if (get_prev_block_sched(block) == cfgpred_block
+ && is_fallthrough(cfgpred)) {
+ need_label = 0;
+ }
+ }
+
+ return need_label;
+}
+
/**
* Returns the register at in position pos.
*/
void ia32_emit_x87_mode_suffix(const ir_node *node)
{
- ir_mode *mode = get_ia32_ls_mode(node);
- assert(mode != NULL);
/* we only need to emit the mode on address mode */
- if(get_ia32_op_type(node) != ia32_Normal)
+ if(get_ia32_op_type(node) != ia32_Normal) {
+ ir_mode *mode = get_ia32_ls_mode(node);
+ assert(mode != NULL);
ia32_emit_mode_suffix_mode(mode);
+ }
}
static char get_xmm_mode_suffix(ir_mode *mode)
* Returns the target block for a control flow node.
*/
static ir_node *get_cfop_target_block(const ir_node *irn) {
+ assert(get_irn_mode(irn) == mode_X);
return get_irn_link(irn);
}
{
if (has_Block_label(block)) {
be_emit_string(be_gas_block_label_prefix());
- be_emit_irprintf("%u", get_Block_label(block));
+ be_emit_irprintf("%lu", get_Block_label(block));
} else {
be_emit_cstring(BLOCK_PREFIX);
- be_emit_irprintf("%d", get_irn_node_nr(block));
+ be_emit_irprintf("%ld", get_irn_node_nr(block));
}
}
static void ia32_emit_exc_label(const ir_node *node)
{
be_emit_string(be_gas_insn_label_prefix());
- be_emit_irprintf("%u", get_ia32_exc_label_id(node));
+ be_emit_irprintf("%lu", get_ia32_exc_label_id(node));
}
/**
ia32_emit_block_name(block);
}
-/** Return the next block in Block schedule */
-static ir_node *next_blk_sched(const ir_node *block)
-{
- return get_irn_link(block);
-}
-
/**
* Returns the Proj with projection number proj and NOT mode_M
*/
return NULL;
}
+static int can_be_fallthrough(const ir_node *node)
+{
+ ir_node *target_block = get_cfop_target_block(node);
+ ir_node *block = get_nodes_block(node);
+ return get_prev_block_sched(target_block) == block;
+}
+
/**
* Emits the jump sequence for a conditional jump (cmp + jmp_true + jmp_false)
*/
const ir_node *proj_true;
const ir_node *proj_false;
const ir_node *block;
- const ir_node *next_block;
pn_Cmp pnc = get_ia32_condcode(node);
pnc = determine_final_pnc(node, 0, pnc);
assert(proj_false && "Jcc without false Proj");
block = get_nodes_block(node);
- next_block = next_blk_sched(block);
- if (get_cfop_target_block(proj_true) == next_block) {
+ if (can_be_fallthrough(proj_true)) {
/* exchange both proj's so the second one can be omitted */
const ir_node *t = proj_true;
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 (get_cfop_target_block(proj_false) == next_block) {
+ if (can_be_fallthrough(proj_false)) {
need_parity_label = 1;
be_emit_cstring("\tjp 1f");
} else {
}
/* the second Proj might be a fallthrough */
- if (get_cfop_target_block(proj_false) != next_block) {
- be_emit_cstring("\tjmp ");
+ if (can_be_fallthrough(proj_false)) {
+ be_emit_cstring("\t/* fallthrough to ");
ia32_emit_cfop_target(proj_false);
+ be_emit_cstring(" */");
be_emit_finish_line_gas(proj_false);
} else {
- be_emit_cstring("\t/* fallthrough to ");
+ be_emit_cstring("\tjmp ");
ia32_emit_cfop_target(proj_false);
- be_emit_cstring(" */");
be_emit_finish_line_gas(proj_false);
}
}
*/
static void emit_Jmp(const ir_node *node)
{
- ir_node *block, *next_block;
+ ir_node *block;
/* for now, the code works for scheduled and non-schedules blocks */
block = get_nodes_block(node);
/* we have a block schedule */
- next_block = next_blk_sched(block);
- if (get_cfop_target_block(node) != next_block) {
- be_emit_cstring("\tjmp ");
- ia32_emit_cfop_target(node);
- } else {
+ if (can_be_fallthrough(node)) {
be_emit_cstring("\t/* fallthrough to ");
ia32_emit_cfop_target(node);
be_emit_cstring(" */");
+ } else {
+ be_emit_cstring("\tjmp ");
+ ia32_emit_cfop_target(node);
}
be_emit_finish_line_gas(node);
}
const arch_register_t *in_reg, *out_reg;
assert(!mode_is_float(smaller_mode));
- assert(smaller_bits == 8 || smaller_bits == 16 || smaller_bits == 32);
+ assert(smaller_bits == 8 || smaller_bits == 16);
signed_mode = mode_is_signed(smaller_mode);
- if(smaller_bits == 32) {
- // this should not happen as it's no convert
- assert(0);
- sign_suffix = "";
- } else {
- sign_suffix = signed_mode ? "s" : "z";
- }
+ sign_suffix = signed_mode ? "s" : "z";
out_reg = get_out_reg(node, 0);
break;
}
default:
- assert(0 && "unsupported op type for Conv");
+ panic("unsupported op type for Conv");
}
be_emit_finish_line_gas(node);
}
be_emit_cstring("\tret");
pop = be_Return_get_pop(node);
- if (pop > 0 || be_Return_get_emit_pop(node)) {
+ if (pop > 0) {
be_emit_irprintf(" $%d", pop);
+ } else if (be_Return_get_emit_pop(node)) {
+ ir_node *block = get_nodes_block(node);
+ if (block_needs_label(block)) {
+ be_emit_cstring(" $0");
+ }
}
be_emit_finish_line_gas(node);
}
/**
* Emits code for a node.
*/
-static void ia32_emit_node(const ir_node *node)
+static void ia32_emit_node(ir_node *node)
{
ir_op *op = get_irn_op(node);
* 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 should_align_block(ir_node *block, ir_node *prev)
+static int should_align_block(const ir_node *block)
{
static const double DELTA = .0001;
ir_exec_freq *exec_freq = cg->birg->exec_freq;
+ ir_node *prev = get_prev_block_sched(block);
double block_freq;
double prev_freq = 0; /**< execfreq of the fallthrough block */
double jmp_freq = 0; /**< execfreq of all non-fallthrough blocks */
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);
+ const ir_node *pred = get_Block_cfgpred_block(block, i);
+ double pred_freq = get_block_execfreq(exec_freq, pred);
if(pred == prev) {
prev_freq += pred_freq;
return jmp_freq > ia32_cg_config.label_alignment_factor;
}
-/**
- * Return non-zero, if a instruction in a fall-through.
- */
-static int is_fallthrough(ir_node *cfgpred)
-{
- ir_node *pred;
-
- if(!is_Proj(cfgpred))
- return 1;
- pred = get_Proj_pred(cfgpred);
- if(is_ia32_SwitchJmp(pred))
- return 0;
-
- return 1;
-}
-
/**
* Emit the block header for a block.
*
* @param block the block
* @param prev_block the previous block
*/
-static void ia32_emit_block_header(ir_node *block, ir_node *prev_block)
+static void ia32_emit_block_header(ir_node *block)
{
ir_graph *irg = current_ir_graph;
- int n_cfgpreds;
- int need_label = 1;
+ int need_label = block_needs_label(block);
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))
return;
- n_cfgpreds = get_Block_n_cfgpreds(block);
-
- if (n_cfgpreds == 0) {
- need_label = 0;
- } else if (n_cfgpreds == 1) {
- ir_node *cfgpred = get_Block_cfgpred(block, 0);
- if (get_nodes_block(cfgpred) == prev_block && is_fallthrough(cfgpred)) {
- need_label = 0;
- }
- }
-
if (ia32_cg_config.label_alignment > 0) {
/* align the current block if:
* a) if should be aligned due to its execution frequency
* b) there is no fall-through here
*/
- if (should_align_block(block, prev_block)) {
+ if (should_align_block(block)) {
ia32_emit_align_label();
} else {
/* if the predecessor block has no fall-through,
we can always align the label. */
int i;
- ir_node *check_node = NULL;
+ int has_fallthrough = 0;
- for (i = n_cfgpreds - 1; i >= 0; --i) {
+ for (i = get_Block_n_cfgpreds(block) - 1; i >= 0; --i) {
ir_node *cfg_pred = get_Block_cfgpred(block, i);
-
- if (get_nodes_block(skip_Proj(cfg_pred)) == prev_block) {
- check_node = cfg_pred;
+ if (can_be_fallthrough(cfg_pred)) {
+ has_fallthrough = 1;
break;
}
}
- if (check_node == NULL || !is_fallthrough(check_node))
+
+ if (!has_fallthrough)
ia32_emit_align_label();
}
}
* Walks over the nodes in a block connected by scheduling edges
* and emits code for each node.
*/
-static void ia32_gen_block(ir_node *block, ir_node *last_block)
+static void ia32_gen_block(ir_node *block)
{
- const ir_node *node;
+ ir_node *node;
- ia32_emit_block_header(block, last_block);
+ ia32_emit_block_header(block);
/* emit the contents of the block */
be_dbg_set_dbg_info(get_irn_dbg_info(block));
}
/**
- * Emit an exception label if the current instruction can fail.
+ * Assign and emit an exception label if the current instruction can fail.
*/
-void ia32_assign_exc_label(const ir_node *node)
+void ia32_assign_exc_label(ir_node *node)
{
if (get_ia32_exc_label(node)) {
/* assign a new ID to the instruction */
*/
void ia32_gen_routine(ia32_code_gen_t *ia32_cg, ir_graph *irg)
{
- ir_node *block;
- ir_node *last_block = NULL;
ir_entity *entity = get_irg_entity(irg);
exc_entry *exc_list = NEW_ARR_F(exc_entry, 0);
int i, n;
set_using_irn_link(irg);
irg_block_walk_graph(irg, ia32_gen_labels, NULL, &exc_list);
+ /* initialize next block links */
n = ARR_LEN(cg->blk_sched);
- for (i = 0; i < n;) {
- ir_node *next_bl;
+ for (i = 0; i < n; ++i) {
+ ir_node *block = cg->blk_sched[i];
+ ir_node *prev = i > 0 ? cg->blk_sched[i-1] : NULL;
+
+ set_irn_link(block, prev);
+ }
- block = cg->blk_sched[i];
- ++i;
- next_bl = i < n ? cg->blk_sched[i] : NULL;
+ for (i = 0; i < n; ++i) {
+ ir_node *block = cg->blk_sched[i];
- /* set here the link. the emitter expects to find the next block here */
- set_irn_link(block, next_bl);
- ia32_gen_block(block, last_block);
- last_block = block;
+ ia32_gen_block(block);
}
be_gas_emit_function_epilog(entity);