#include "ia32_new_nodes.h"
#include "ia32_map_regs.h"
-#ifdef obstack_chunk_alloc
-# undef obstack_chunk_alloc
-# define obstack_chunk_alloc xmalloc
-#else
-# define obstack_chunk_alloc xmalloc
-# define obstack_chunk_free free
-#endif
-
#define BLOCK_PREFIX(x) ".L" x
-extern int obstack_printf(struct obstack *obst, char *fmt, ...);
-
#define SNPRINTF_BUF_LEN 128
/* global arch_env for lc_printf functions */
static const arch_env_t *arch_env = NULL;
+/** by default, we generate assembler code for the Linux gas */
+asm_flavour_t asm_flavour = ASM_LINUX_GAS;
+
+/**
+ * Switch to a new section
+ */
+void ia32_switch_section(FILE *F, section_t sec) {
+ static section_t curr_sec = NO_SECTION;
+ static const char *text[ASM_MAX][SECTION_MAX] = {
+ {
+ ".section\t.text", ".section\t.data", ".section\t.rodata", ".section\t.text"
+ },
+ {
+ ".section\t.text", ".section\t.data", ".section .rdata,\"dr\"", ".section\t.text"
+ }
+ };
+
+ if (curr_sec == sec)
+ return;
+
+ curr_sec = sec;
+ switch (sec) {
+
+ case NO_SECTION:
+ break;
+
+ case SECTION_TEXT:
+ case SECTION_DATA:
+ case SECTION_RODATA:
+ case SECTION_COMMON:
+ fprintf(F, "\t%s\n", text[asm_flavour][sec]);
+ }
+}
+
+static void ia32_dump_function_object(FILE *F, const char *name)
+{
+ switch (asm_flavour) {
+ case ASM_LINUX_GAS:
+ fprintf(F, "\t.type\t%s, @function\n", name);
+ break;
+ case ASM_MINGW_GAS:
+ fprintf(F, "\t.def\t%s;\t.scl\t2;\t.type\t32;\t.endef\n", name);
+ break;
+ }
+}
+
+static void ia32_dump_function_size(FILE *F, const char *name)
+{
+ switch (asm_flavour) {
+ case ASM_LINUX_GAS:
+ fprintf(F, "\t.size\t%s, .-%s\n", name, name);
+ break;
+ }
+}
+
/*************************************************************
* _ _ __ _ _
* (_) | | / _| | | | |
/**
* returns true if a node has x87 registers
*/
-static int has_x87_register(const ir_node *n)
-{
- return get_irn_op(n)->flags & (irop_flag_machine << 1);
+static int has_x87_register(const ir_node *n) {
+ return is_irn_machine_user(n, 0);
}
/* We always pass the ir_node which is a pointer. */
reg = arch_get_irn_register(arch_env, op);
assert(reg && "no in register found");
+
+ /* in case of unknown: just return a register */
+ if (REGS_ARE_EQUAL(reg, &ia32_gp_regs[REG_GP_UKNWN]))
+ reg = &ia32_gp_regs[REG_EAX];
+ else if (REGS_ARE_EQUAL(reg, &ia32_xmm_regs[REG_XMM_UKNWN]))
+ reg = &ia32_xmm_regs[REG_XMM0];
+ else if (REGS_ARE_EQUAL(reg, &ia32_vfp_regs[REG_VFP_UKNWN]))
+ reg = &ia32_vfp_regs[REG_VF0];
+ else if (REGS_ARE_EQUAL(reg, &ia32_st_regs[REG_ST_UKNWN]))
+ reg = &ia32_st_regs[REG_ST0];
+
return reg;
}
snprintf(buf, SNPRINTF_BUF_LEN, "%s, %s", get_ia32_cnst(n), ia32_emit_am(n, env));
}
else {
- lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%4S, %s", n, ia32_emit_am(n, env));
+ if (PRODUCES_RESULT(n)) {
+ lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%1D, %s", n, ia32_emit_am(n, env));
+ }
+ else {
+ lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%4S, %s", n, ia32_emit_am(n, env));
+ }
}
break;
case ia32_AddrModeD:
snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* get jump table entry as target */");
IA32_DO_EMIT(irn);
- fprintf(F, "\t.section\t.rodata\n");
+ ia32_switch_section(F, SECTION_RODATA);
fprintf(F, "\t.align 4\n");
fprintf(F, "%s:\n", tbl.label);
snprintf(cmnt_buf, SNPRINTF_BUF_LEN, "/* case %d */", last_value);
IA32_DO_EMIT(irn);
}
-
- fprintf(F, "\n\t.text\n\n");
+ ia32_switch_section(F, SECTION_TEXT);
}
else {
/* one jump is enough */
* Emit rep movsd instruction for memcopy.
*/
static void emit_ia32_CopyB(const ir_node *irn, ia32_emit_env_t *emit_env) {
- FILE *F = emit_env->out;
- tarval *tv = get_ia32_Immop_tarval(irn);
- int rem = get_tarval_long(tv);
- int size = get_tarval_long(get_ia32_Immop_tarval(get_irn_n(irn, 2)));
+ FILE *F = emit_env->out;
+ tarval *tv = get_ia32_Immop_tarval(irn);
+ int rem = get_tarval_long(tv);
+ ir_node *size_node = get_irn_n(irn, 2);
+ int size;
char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
+ /* beware: size_node could be a be_Copy to fulfill constraints for ecx */
+ size_node = be_is_Copy(size_node) ? be_get_Copy_op(size_node) : size_node;
+ size = get_tarval_long(get_ia32_Immop_tarval(size_node));
+
emit_CopyB_prolog(F, rem, size);
snprintf(cmd_buf, SNPRINTF_BUF_LEN, "rep movsd");
char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
if (ent) {
- snprintf(cmd_buf, SNPRINTF_BUF_LEN, "call %s", get_entity_name(ent));
+ snprintf(cmd_buf, SNPRINTF_BUF_LEN, "call %s", get_entity_ld_name(ent));
}
else {
lc_esnprintf(ia32_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "%1D", get_irn_n(irn, be_pos_Call_ptr));
char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
if (offs) {
- lc_esnprintf(ia32_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "add %1S,%s%u", irn,
- (dir == be_stack_dir_expand) ? " -" : " ", offs);
+ if (dir == be_stack_dir_expand)
+ lc_esnprintf(ia32_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "sub %1S, %u", irn, offs);
+ else
+ lc_esnprintf(ia32_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "add %1S, %u", irn, offs);
lc_esnprintf(ia32_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* %+F (IncSP) */", irn);
}
else {
*/
static void ia32_emit_func_prolog(FILE *F, ir_graph *irg) {
entity *irg_ent = get_irg_entity(irg);
- const char *irg_name = get_entity_name(irg_ent);
+ const char *irg_name = get_entity_ld_name(irg_ent);
- fprintf(F, "\t.section\t.text\n");
+ fprintf(F, "\n");
+ ia32_switch_section(F, SECTION_TEXT);
if (get_entity_visibility(irg_ent) == visibility_external_visible) {
fprintf(F, ".globl %s\n", irg_name);
}
- fprintf(F, "\t.type\t%s, @function\n", irg_name);
+ ia32_dump_function_object(F, irg_name);
fprintf(F, "%s:\n", irg_name);
}
* Emits code for function end
*/
static void ia32_emit_func_epilog(FILE *F, ir_graph *irg) {
- const char *irg_name = get_entity_name(get_irg_entity(irg));
+ const char *irg_name = get_entity_ld_name(get_irg_entity(irg));
fprintf(F, "\tret\n");
- fprintf(F, "\t.size\t%s, .-%s\n\n", irg_name, irg_name);
+ ia32_dump_function_size(F, irg_name);
+ fprintf(F, "\n");
}
/**
ia32_emit_func_prolog(F, irg);
irg_block_walk_graph(irg, ia32_gen_labels, NULL, &emit_env);
- if (cg->opt.extbb && cg->blk_sched) {
+ if ((cg->opt & IA32_OPT_EXTBB) && cg->blk_sched) {
int i, n = ARR_LEN(cg->blk_sched);
for (i = 0; i < n;) {