#include "execfreq.h"
#include "error.h"
#include "raw_bitset.h"
+#include "dbginfo.h"
#include "../besched_t.h"
#include "../benode_t.h"
#include "ia32_nodes_attr.h"
#include "ia32_new_nodes.h"
#include "ia32_map_regs.h"
+#include "ia32_architecture.h"
#include "bearch_ia32_t.h"
DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
switch(get_mode_size_bits(mode)) {
case 32: be_emit_char('s'); return;
case 64: be_emit_char('l'); return;
- case 80: be_emit_char('t'); return;
+ case 80:
+ case 96: be_emit_char('t'); return;
}
} else {
assert(mode_is_int(mode) || mode_is_reference(mode));
}
}
+static void ia32_emit_entity(ir_entity *entity)
+{
+ ident *id;
+
+ set_entity_backend_marked(entity, 1);
+ id = get_entity_ld_ident(entity);
+ be_emit_ident(id);
+
+ if(get_entity_owner(entity) == get_tls_type()) {
+ if (get_entity_visibility(entity) == visibility_external_allocated) {
+ be_emit_cstring("@INDNTPOFF");
+ } else {
+ be_emit_cstring("@NTPOFF");
+ }
+ }
+}
+
/**
* Emits address mode.
*/
/* emit offset */
if (ent != NULL) {
- ident *id;
-
- set_entity_backend_marked(ent, 1);
- id = get_entity_ld_ident(ent);
if (is_ia32_am_sc_sign(node))
be_emit_char('-');
- be_emit_ident(id);
-
- if(get_entity_owner(ent) == get_tls_type()) {
- if (get_entity_visibility(ent) == visibility_external_allocated) {
- be_emit_cstring("@INDNTPOFF");
- } else {
- be_emit_cstring("@NTPOFF");
- }
- }
+ ia32_emit_entity(ent);
}
if(offs != 0) {
}
}
+static void emit_ia32_IMul(const ir_node *node)
+{
+ ir_node *left = get_irn_n(node, n_ia32_IMul_left);
+ const arch_register_t *out_reg = get_out_reg(node, pn_ia32_IMul_res);
+
+ be_emit_cstring("\timul");
+ ia32_emit_mode_suffix(node);
+ be_emit_char(' ');
+
+ ia32_emit_binop(node);
+
+ /* do we need the 3-address form? */
+ if(is_ia32_NoReg_GP(left) ||
+ get_in_reg(node, n_ia32_IMul_left) != out_reg) {
+ be_emit_cstring(", ");
+ emit_register(out_reg, get_ia32_ls_mode(node));
+ }
+ be_emit_finish_line_gas(node);
+}
+
/*************************************************
* _ _ _
* (_) | | |
pnc = get_mirrored_pnc(pnc);
pnc |= ia32_pn_Cmp_float;
} else {
+#if 0
assert(is_ia32_Cmp(flags) || is_ia32_Test(flags)
|| is_ia32_Cmp8Bit(flags) || is_ia32_Test8Bit(flags));
+#endif
flags_attr = get_ia32_attr_const(flags);
if(flags_attr->data.ins_permuted)
void ia32_emit_cmp_suffix_node(const ir_node *node,
int flags_pos)
{
- pn_Cmp pnc = get_ia32_pncode(node);
+ const ia32_attr_t *attr = get_ia32_attr_const(node);
+
+ 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);
+ }
+ }
+
ia32_emit_cmp_suffix(pnc);
}
const ir_node *proj_false;
const ir_node *block;
const ir_node *next_block;
- pn_Cmp pnc = get_ia32_pncode(node);
+ pn_Cmp pnc = get_ia32_condcode(node);
pnc = determine_final_pnc(node, 0, pnc);
const ia32_attr_t *attr = get_ia32_attr_const(node);
int ins_permuted = attr->data.ins_permuted;
const arch_register_t *out = arch_get_irn_register(arch_env, node);
- pn_Cmp pnc = get_ia32_pncode(node);
+ pn_Cmp pnc = get_ia32_condcode(node);
const arch_register_t *in_true;
const arch_register_t *in_false;
* possible otherwise a cmp-jmp cascade). Port from
* cggg ia32 backend
*/
-static
-void emit_ia32_SwitchJmp(const ir_node *node) {
+static void emit_ia32_SwitchJmp(const ir_node *node)
+{
unsigned long interval;
int last_value, i;
long pnc;
+ long default_pn;
jmp_tbl_t tbl;
ir_node *proj;
const ir_edge_t *edge;
tbl.label = xmalloc(SNPRINTF_BUF_LEN);
tbl.label = get_unique_label(tbl.label, SNPRINTF_BUF_LEN, ".TBL_");
tbl.defProj = NULL;
- tbl.num_branches = get_irn_n_edges(node);
+ tbl.num_branches = get_irn_n_edges(node) - 1;
tbl.branches = xcalloc(tbl.num_branches, sizeof(tbl.branches[0]));
tbl.min_value = INT_MAX;
tbl.max_value = INT_MIN;
+ default_pn = get_ia32_condcode(node);
i = 0;
/* go over all proj's and collect them */
foreach_out_edge(node, edge) {
pnc = get_Proj_proj(proj);
- /* create branch entry */
- tbl.branches[i].target = proj;
- tbl.branches[i].value = pnc;
-
- tbl.min_value = pnc < tbl.min_value ? pnc : tbl.min_value;
- tbl.max_value = pnc > tbl.max_value ? pnc : tbl.max_value;
-
/* check for default proj */
- if (pnc == get_ia32_pncode(node)) {
- assert(tbl.defProj == NULL && "found two defProjs at SwitchJmp");
+ if (pnc == 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;
+
+ /* create branch entry */
+ tbl.branches[i].target = proj;
+ tbl.branches[i].value = pnc;
+ ++i;
}
- i++;
}
+ assert(i == tbl.num_branches);
/* sort the branches by their number */
qsort(tbl.branches, tbl.num_branches, sizeof(tbl.branches[0]), ia32_cmp_branch_t);
be_emit_char('$');
if(attr->symconst != NULL) {
- ident *id = get_entity_ld_ident(attr->symconst);
-
- if(attr->attr.data.am_sc_sign)
+ if(attr->sc_sign)
be_emit_char('-');
- be_emit_ident(id);
+ ia32_emit_entity(attr->symconst);
}
if(attr->symconst == NULL || attr->offset != 0) {
if(attr->symconst != NULL) {
}
}
+/**
+ * Emit an inline assembler operand.
+ *
+ * @param node the ia32_ASM node
+ * @param s points to the operand (a %c)
+ *
+ * @return pointer to the first char in s NOT in the current operand
+ */
static const char* emit_asm_operand(const ir_node *node, const char *s)
{
+ const ia32_attr_t *ia32_attr = get_ia32_attr_const(node);
+ const ia32_asm_attr_t *attr = CONST_CAST_IA32_ATTR(ia32_asm_attr_t,
+ ia32_attr);
const arch_register_t *reg;
+ const ia32_asm_reg_t *asm_regs = attr->register_map;
+ const ia32_asm_reg_t *asm_reg;
const char *reg_name;
char c;
char modifier = 0;
int num = -1;
- const ia32_attr_t *attr;
- int n_outs;
int p;
assert(*s == '%');
s += p;
}
+ if(num < 0 || num >= ARR_LEN(asm_regs)) {
+ ir_fprintf(stderr, "Error: Custom assembler references invalid "
+ "input/output (%+F)\n", node);
+ return s;
+ }
+ asm_reg = & asm_regs[num];
+ assert(asm_reg->valid);
+
/* get register */
- attr = get_ia32_attr_const(node);
- n_outs = ARR_LEN(attr->slots);
- if(num < n_outs) {
- reg = get_out_reg(node, num);
+ if(asm_reg->use_input == 0) {
+ reg = get_out_reg(node, asm_reg->inout_pos);
} else {
- ir_node *pred;
- int in = num - n_outs;
- if(in >= get_irn_arity(node)) {
- ir_fprintf(stderr, "Warning: Invalid input %d specified in asm "
- "op (%+F)\n", num, node);
- return s;
- }
- pred = get_irn_n(node, in);
+ ir_node *pred = get_irn_n(node, asm_reg->inout_pos);
+
/* might be an immediate value */
if(is_ia32_Immediate(pred)) {
emit_ia32_Immediate(pred);
return s;
}
- reg = get_in_reg(node, in);
+ reg = get_in_reg(node, asm_reg->inout_pos);
}
if(reg == NULL) {
ir_fprintf(stderr, "Warning: no register assigned for %d asm op "
return s;
}
+ if(asm_reg->memory) {
+ be_emit_char('(');
+ }
+
/* emit it */
- be_emit_char('%');
- switch(modifier) {
- case 0:
- reg_name = arch_register_get_name(reg);
- break;
- case 'b':
- reg_name = ia32_get_mapped_reg_name(isa->regs_8bit, reg);
- break;
- case 'h':
- reg_name = ia32_get_mapped_reg_name(isa->regs_8bit_high, reg);
- break;
- case 'w':
- reg_name = ia32_get_mapped_reg_name(isa->regs_16bit, reg);
- break;
- default:
- panic("Invalid asm op modifier");
+ if(modifier != 0) {
+ be_emit_char('%');
+ switch(modifier) {
+ case 'b':
+ reg_name = ia32_get_mapped_reg_name(isa->regs_8bit, reg);
+ break;
+ case 'h':
+ reg_name = ia32_get_mapped_reg_name(isa->regs_8bit_high, reg);
+ break;
+ case 'w':
+ reg_name = ia32_get_mapped_reg_name(isa->regs_16bit, reg);
+ break;
+ default:
+ panic("Invalid asm op modifier");
+ }
+ be_emit_string(reg_name);
+ } else {
+ emit_register(reg, asm_reg->mode);
+ }
+
+ if(asm_reg->memory) {
+ be_emit_char(')');
}
- be_emit_string(reg_name);
return s;
}
/**
* Emit movsb/w instructions to make mov count divideable by 4
*/
-static void emit_CopyB_prolog(int rem) {
+static void emit_CopyB_prolog(unsigned size) {
be_emit_cstring("\tcld");
be_emit_finish_line_gas(NULL);
- switch(rem) {
+ switch (size) {
case 1:
be_emit_cstring("\tmovsb");
be_emit_finish_line_gas(NULL);
*/
static void emit_ia32_CopyB(const ir_node *node)
{
- int rem = get_ia32_pncode(node);
+ unsigned size = get_ia32_copyb_size(node);
- emit_CopyB_prolog(rem);
+ emit_CopyB_prolog(size);
be_emit_cstring("\trep movsd");
be_emit_finish_line_gas(node);
*/
static void emit_ia32_CopyB_i(const ir_node *node)
{
- int size = get_ia32_pncode(node);
+ unsigned size = get_ia32_copyb_size(node);
emit_CopyB_prolog(size & 0x3);
be_emit_cstring("\tcall ");
if (ent) {
- set_entity_backend_marked(ent, 1);
- be_emit_string(get_entity_ld_name(ent));
+ ia32_emit_entity(ent);
} else {
const arch_register_t *reg = get_in_reg(node, be_pos_Call_ptr);
be_emit_char('*');
/* other ia32 emitter functions */
IA32_EMIT(Asm);
IA32_EMIT(CMov);
+ IA32_EMIT(IMul);
IA32_EMIT(SwitchJmp);
IA32_EMIT(CopyB);
IA32_EMIT(CopyB_i);
{
dbg_info *db = get_irn_dbg_info(node);
unsigned lineno;
- const char *fname = be_retrieve_dbg_info(db, &lineno);
+ const char *fname = ir_retrieve_dbg_info(db, &lineno);
if (! cg->birg->main_env->options->stabs_debug_support)
return;
/**
* Emits gas alignment directives for Functions depended on cpu architecture.
*/
-static void ia32_emit_align_func(cpu_support cpu)
+static void ia32_emit_align_func(void)
{
- unsigned align;
- unsigned maximum_skip;
+ unsigned align = ia32_cg_config.function_alignment;
+ unsigned maximum_skip = (1 << align) - 1;
- switch (cpu) {
- case arch_i386:
- align = 2;
- break;
- case arch_i486:
- align = 4;
- break;
- case arch_k6:
- align = 5;
- break;
- default:
- align = 4;
- }
- maximum_skip = (1 << align) - 1;
ia32_emit_alignment(align, maximum_skip);
}
/**
* Emits gas alignment directives for Labels depended on cpu architecture.
*/
-static void ia32_emit_align_label(cpu_support cpu)
+static void ia32_emit_align_label(void)
{
- unsigned align; unsigned maximum_skip;
-
- switch (cpu) {
- case arch_i386:
- align = 2;
- break;
- case arch_i486:
- align = 4;
- break;
- case arch_k6:
- align = 5;
- break;
- default:
- align = 4;
- }
- maximum_skip = (1 << align) - 1;
+ unsigned align = ia32_cg_config.label_alignment;
+ unsigned maximum_skip = (1 << align) - 1;
ia32_emit_alignment(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
+ * For cpus in the P4/Athlon class it is useful 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.
*/
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 = isa->opt_arch;
int i, n_cfgpreds;
if(exec_freq == NULL)
return 0;
- if(cpu == arch_i386 || cpu == arch_i486)
+ if(ia32_cg_config.label_alignment_factor <= 0)
return 0;
block_freq = get_block_execfreq(exec_freq, block);
jmp_freq /= prev_freq;
- switch (cpu) {
- case arch_athlon:
- case arch_athlon_64:
- case arch_k6:
- return jmp_freq > 3;
- default:
- return jmp_freq > 2;
- }
+ return jmp_freq > ia32_cg_config.label_alignment_factor;
}
static void ia32_emit_block_header(ir_node *block, ir_node *prev)
if (should_align_block(block, prev)) {
assert(need_label);
- ia32_emit_align_label(isa->opt_arch);
+ ia32_emit_align_label();
}
if(need_label) {
{
ir_entity *irg_ent = get_irg_entity(irg);
const char *irg_name = get_entity_ld_name(irg_ent);
- cpu_support cpu = isa->opt_arch;
const be_irg_t *birg = cg->birg;
+ /* write the begin line (used by scripts processing the assembler... */
+ be_emit_write_line();
+ be_emit_cstring("# -- Begin ");
+ be_emit_string(irg_name);
+ be_emit_char('\n');
be_emit_write_line();
+
be_gas_emit_switch_section(GAS_SECTION_TEXT);
be_dbg_method_begin(birg->main_env->db_handle, irg_ent, be_abi_get_stack_layout(birg->abi));
- ia32_emit_align_func(cpu);
+ ia32_emit_align_func();
if (get_entity_visibility(irg_ent) == visibility_external_visible) {
be_emit_cstring(".global ");
be_emit_string(irg_name);
ia32_emit_function_size(irg_name);
be_dbg_method_end(birg->main_env->db_handle);
+
+ be_emit_cstring("# -- End ");
+ be_emit_string(irg_name);
+ be_emit_char('\n');
+ be_emit_write_line();
+
be_emit_char('\n');
be_emit_write_line();
}