+/**
+ * This file implements the node emitter.
+ *
+ * $Id$
+ */
+
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "irop_t.h"
#include "irargs_t.h"
#include "irprog_t.h"
+#include "iredges_t.h"
#include "../besched.h"
#include "../benode_t.h"
static const arch_env_t *arch_env = NULL;
-/**
- * Emits registers and/or address mode of a binary operation.
- */
-char *ia32_emit_binop(const ir_node *n) {
- static char *buf = NULL;
-
- /* verify that this function is never called on non-AM supporting operations */
- assert(get_ia32_am_support(n) != ia32_am_None && "emit binop expects addressmode support");
-
- if (! buf) {
- buf = xcalloc(1, SNPRINTF_BUF_LEN);
- }
- else {
- memset(buf, 0, SNPRINTF_BUF_LEN);
- }
-
- switch(get_ia32_op_type(n)) {
- case ia32_Normal:
- if (get_ia32_cnst(n)) {
- lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%3S, %s", n, get_ia32_cnst(n));
- }
- else {
- lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%3S, %4S", n, n);
- }
- break;
- case ia32_AddrModeS:
- lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%4S, %s", n, ia32_emit_am(n));
- break;
- case ia32_AddrModeD:
- if (get_ia32_cnst(n)) {
- lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%s, %s", ia32_emit_am(n), get_ia32_cnst(n));
- }
- else {
- lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%s, %3S", ia32_emit_am(n), n);
- }
- break;
- default:
- assert(0 && "unsupported op type");
- }
-
- return buf;
-}
-
-/**
- * Emits registers and/or address mode of a unary operation.
- */
-char *ia32_emit_unop(const ir_node *n) {
- static char *buf = NULL;
-
- if (! buf) {
- buf = xcalloc(1, SNPRINTF_BUF_LEN);
- }
- else {
- memset(buf, 0, SNPRINTF_BUF_LEN);
- }
-
- switch(get_ia32_op_type(n)) {
- case ia32_Normal:
- lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%1D", n);
- break;
- case ia32_am_Dest:
- snprintf(buf, SNPRINTF_BUF_LEN, ia32_emit_am(n));
- break;
- default:
- assert(0 && "unsupported op type");
- }
-
- return buf;
-}
-
-/**
- * Emits adressmode.
- */
-char *ia32_emit_am(const ir_node *n) {
- ia32_am_flavour_t am_flav = get_ia32_am_flavour(n);
- int had_output = 0;
- char *s;
- int size;
- static struct obstack *obst = NULL;
-
- if (! obst) {
- obst = xcalloc(1, sizeof(*obst));
- }
- else {
- obstack_free(obst, NULL);
- }
-
- /* obstack_free with NULL results in an uninitialized obstack */
- obstack_init(obst);
-
- obstack_printf(obst, "[");
-
- if (am_flav & ia32_B) {
- lc_eoprintf(ia32_get_arg_env(), obst, "%1S", n);
- had_output = 1;
- }
-
- if (am_flav & ia32_I) {
- if (had_output) {
- obstack_printf(obst, "+");
- }
-
- lc_eoprintf(ia32_get_arg_env(), obst, "%2S", n);
-
- if (am_flav & ia32_S) {
- obstack_printf(obst, "*%d", 1 << get_ia32_am_scale(n));
- }
-
- had_output = 1;
- }
-
- if (am_flav & ia32_O) {
- obstack_printf(obst, get_ia32_am_offs(n));
- }
-
- obstack_printf(obst, "] ");
-
- size = obstack_object_size(obst);
- s = obstack_finish(obst);
- s[size - 1] = '\0';
-
- return s;
-}
-
/*************************************************************
* _ _ __ _ _
* (_) | | / _| | | | |
ir_node *proj;
const arch_register_t *reg = NULL;
- assert(get_irn_n_edges(irn) > pos && "Invalid OUT position");
-
/* 1st case: irn is not of mode_T, so it has only */
/* one OUT register -> good */
/* 2nd case: irn is of mode_T -> collect all Projs and ask the */
return reg;
}
-/**
- * Returns the number of the in register at position pos.
- */
-int get_ia32_reg_nr(ir_node *irn, int pos, int in_out) {
- const arch_register_t *reg;
-
- if (in_out == 1) {
- reg = get_in_reg(irn, pos);
- }
- else {
- reg = get_out_reg(irn, pos);
- }
-
- return arch_register_get_index(reg);
-}
-
enum io_direction {
IN_REG,
OUT_REG
}
else {
/* destination address mode nodes don't have outputs */
- if (get_ia32_op_type(irn) == ia32_AddrModeD) {
+ if (is_ia32_irn(irn) && get_ia32_op_type(irn) == ia32_AddrModeD) {
return "MEM";
}
static int ia32_get_mode_suffix(lc_appendable_t *app,
const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
{
- ir_node *X = arg->v_ptr;
+ ir_node *X = arg->v_ptr;
+ ir_mode *mode = get_irn_mode(X);
+
+ if (mode == mode_T) {
+ mode = is_ia32_AddrModeS(X) || is_ia32_AddrModeD(X) ? get_ia32_ls_mode(X) : get_ia32_res_mode(X);
+ }
if (!X)
return lc_arg_append(app, occ, "(null)", 6);
- return lc_appendable_chadd(app, get_mode_size_bits(get_irn_mode(X)) == 32 ? 's' : 'd');
+ if (mode_is_float(mode)) {
+ return lc_appendable_chadd(app, get_mode_size_bits(mode) == 32 ? 's' : 'd');
+ }
+ else {
+
+ return lc_appendable_chadd(app, mode_is_signed(mode) ? 's' : 'z');
+ }
}
/**
return env;
}
+/**
+ * Emits registers and/or address mode of a binary operation.
+ */
+char *ia32_emit_binop(const ir_node *n) {
+ static char *buf = NULL;
+
+ /* verify that this function is never called on non-AM supporting operations */
+ assert(get_ia32_am_support(n) != ia32_am_None && "emit binop expects addressmode support");
-/*
+ if (! buf) {
+ buf = xcalloc(1, SNPRINTF_BUF_LEN);
+ }
+ else {
+ memset(buf, 0, SNPRINTF_BUF_LEN);
+ }
+
+ switch(get_ia32_op_type(n)) {
+ case ia32_Normal:
+ if (get_ia32_cnst(n)) {
+ lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%3S, %s", n, get_ia32_cnst(n));
+ }
+ else {
+ const arch_register_t *in1 = get_in_reg(n, 2);
+ const arch_register_t *in2 = get_in_reg(n, 3);
+ const arch_register_t *out = get_ia32_n_res(n) > 0 ? get_out_reg(n, 0) : NULL;
+ const arch_register_t *in;
+
+ in = out ? (REGS_ARE_EQUAL(out, in2) ? in1 : in2) : in2;
+ out = out ? out : in1;
+
+ snprintf(buf, SNPRINTF_BUF_LEN, "%s, %s", \
+ arch_register_get_name(out), arch_register_get_name(in));
+ }
+ break;
+ case ia32_AddrModeS:
+ lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%4S, %s", n, ia32_emit_am(n));
+ break;
+ case ia32_AddrModeD:
+ if (get_ia32_cnst(n)) {
+ lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%s, %s", ia32_emit_am(n), get_ia32_cnst(n));
+ }
+ else {
+ lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%s, %3S", ia32_emit_am(n), n);
+ }
+ break;
+ default:
+ assert(0 && "unsupported op type");
+ }
+
+ return buf;
+}
+
+/**
+ * Emits registers and/or address mode of a unary operation.
+ */
+char *ia32_emit_unop(const ir_node *n) {
+ static char *buf = NULL;
+
+ if (! buf) {
+ buf = xcalloc(1, SNPRINTF_BUF_LEN);
+ }
+ else {
+ memset(buf, 0, SNPRINTF_BUF_LEN);
+ }
+
+ switch(get_ia32_op_type(n)) {
+ case ia32_Normal:
+ lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%1D", n);
+ break;
+ case ia32_am_Dest:
+ snprintf(buf, SNPRINTF_BUF_LEN, ia32_emit_am(n));
+ break;
+ default:
+ assert(0 && "unsupported op type");
+ }
+
+ return buf;
+}
+
+/**
+ * Emits adress mode.
+ */
+char *ia32_emit_am(const ir_node *n) {
+ ia32_am_flavour_t am_flav = get_ia32_am_flavour(n);
+ int had_output = 0;
+ char *s;
+ int size;
+ static struct obstack *obst = NULL;
+ ir_mode *mode = get_ia32_ls_mode(n);
+
+ if (! is_ia32_Lea(n))
+ assert(mode && "AM node must have ls_mode attribute set.");
+
+ if (! obst) {
+ obst = xcalloc(1, sizeof(*obst));
+ }
+ else {
+ obstack_free(obst, NULL);
+ }
+
+ /* obstack_free with NULL results in an uninitialized obstack */
+ obstack_init(obst);
+
+ if (mode) {
+ switch (get_mode_size_bits(mode)) {
+ case 8:
+ obstack_printf(obst, "BYTE PTR ");
+ break;
+ case 16:
+ obstack_printf(obst, "WORD PTR ");
+ break;
+ default:
+ break;
+ }
+ }
+
+ obstack_printf(obst, "[");
+
+ if (am_flav & ia32_B) {
+ lc_eoprintf(ia32_get_arg_env(), obst, "%1S", n);
+ had_output = 1;
+ }
+
+ if (am_flav & ia32_I) {
+ if (had_output) {
+ obstack_printf(obst, "+");
+ }
+
+ lc_eoprintf(ia32_get_arg_env(), obst, "%2S", n);
+
+ if (am_flav & ia32_S) {
+ obstack_printf(obst, "*%d", 1 << get_ia32_am_scale(n));
+ }
+
+ had_output = 1;
+ }
+
+ if (am_flav & ia32_O) {
+ obstack_printf(obst, get_ia32_am_offs(n));
+ }
+
+ obstack_printf(obst, "] ");
+
+ size = obstack_object_size(obst);
+ s = obstack_finish(obst);
+ s[size - 1] = '\0';
+
+ return s;
+}
+
+
+
+/**
* Add a number to a prefix. This number will not be used a second time.
*/
static char *get_unique_label(char *buf, size_t buflen, const char *prefix) {
}
+
/*************************************************
* _ _ _
* (_) | | |
* |_| |___/
**********************************/
+/**
+ * Emit movsb/w instructions to make mov count divideable by 4
+ */
static void emit_CopyB_prolog(FILE *F, int rem, int size) {
fprintf(F, "\t/* memcopy %d bytes*/\n", size);
fprintf(F, "\tcld\t\t\t\t/* copy direction forward*/\n");
}
}
+/**
+ * Emit rep movsd instruction for memcopy.
+ */
void emit_ia32_CopyB(const ir_node *irn, emit_env_t *emit_env) {
FILE *F = emit_env->out;
tarval *tv = get_ia32_Immop_tarval(irn);
fprintf(F, "\trep movsd\t\t\t\t/* memcopy */\n");
}
+/**
+ * Emits unrolled memcopy.
+ */
void emit_ia32_CopyB_i(const ir_node *irn, emit_env_t *emit_env) {
tarval *tv = get_ia32_Immop_tarval(irn);
int size = get_tarval_long(tv);
+/***************************
+ * _____
+ * / ____|
+ * | | ___ _ ____ __
+ * | | / _ \| '_ \ \ / /
+ * | |___| (_) | | | \ V /
+ * \_____\___/|_| |_|\_/
+ *
+ ***************************/
+
+/**
+ * Emit code for conversions (I, FP), (FP, I) and (FP, FP).
+ */
+static void emit_ia32_Conv(const ir_node *irn, emit_env_t *emit_env) {
+ FILE *F = emit_env->out;
+ const lc_arg_env_t *env = ia32_get_arg_env();
+ char *from, *to, buf[64];
+ ir_mode *src_mode, *tgt_mode;
+
+ src_mode = is_ia32_AddrModeS(irn) ? get_ia32_ls_mode(irn) : get_irn_mode(get_irn_n(irn, 2));
+ tgt_mode = get_ia32_res_mode(irn);
+
+ from = mode_is_float(src_mode) ? (get_mode_size_bits(src_mode) == 32 ? "ss" : "sd") : "si";
+ to = mode_is_float(tgt_mode) ? (get_mode_size_bits(tgt_mode) == 32 ? "ss" : "sd") : "si";
+
+ switch(get_ia32_op_type(irn)) {
+ case ia32_Normal:
+ lc_esnprintf(env, buf, sizeof(buf), "%1D, %3S", irn, irn);
+ break;
+ case ia32_AddrModeS:
+ lc_esnprintf(env, buf, sizeof(buf), "%1D, %s", irn, ia32_emit_am(irn));
+ break;
+ default:
+ assert(0 && "unsupported op type for Conv");
+ }
+
+ lc_efprintf(env, F, "\tcvt%s2%s %s\t\t\t/* %+F(%+F, %+F) */\n", from, to, buf, irn, src_mode, tgt_mode);
+}
+
+void emit_ia32_Conv_I2FP(const ir_node *irn, emit_env_t *emit_env) {
+ emit_ia32_Conv(irn, emit_env);
+}
+
+void emit_ia32_Conv_FP2I(const ir_node *irn, emit_env_t *emit_env) {
+ emit_ia32_Conv(irn, emit_env);
+}
+
+void emit_ia32_Conv_FP2FP(const ir_node *irn, emit_env_t *emit_env) {
+ emit_ia32_Conv(irn, emit_env);
+}
+
+
+
/*******************************************
* _ _
* | | | |
*
*******************************************/
+/**
+ * Emits a backend call
+ */
void emit_be_Call(const ir_node *irn, emit_env_t *emit_env) {
FILE *F = emit_env->out;
+ entity *ent = be_Call_get_entity(irn);
+
+ fprintf(F, "\tcall ");
- lc_efprintf(ia32_get_arg_env(), F, "\tcall %3S\t\t\t/* %+F(%+F) (be_Call) */\n", irn, irn, get_irn_n(irn, 2));
+ if (ent) {
+ fprintf(F, "%s", get_entity_name(ent));
+ }
+ else {
+ lc_efprintf(ia32_get_arg_env(), F, "%1D", get_irn_n(irn, be_pos_Call_ptr));
+ }
+
+ ir_fprintf(F, "\t\t\t/* %+F (be_Call) */\n", irn);
}
+/**
+ * Emits code to increase stack pointer.
+ */
void emit_be_IncSP(const ir_node *irn, emit_env_t *emit_env) {
FILE *F = emit_env->out;
unsigned offs = be_get_IncSP_offset(irn);
}
}
+/**
+ * Emits code to set stack pointer.
+ */
+void emit_be_SetSP(const ir_node *irn, emit_env_t *emit_env) {
+ FILE *F = emit_env->out;
+
+ lc_efprintf(ia32_get_arg_env(), F, "\tmov %1D, %3S\t\t\t/* restore SP */\n", irn, irn);
+}
+
+/**
+ * Emits code for Copy.
+ */
+void emit_be_Copy(const ir_node *irn, emit_env_t *emit_env) {
+ FILE *F = emit_env->out;
+
+ lc_efprintf(ia32_get_arg_env(), F, "\tmov %1D, %1S\t\t\t/* %+F */\n", irn, irn, irn);
+}
+
+/**
+ * Emits code for exchange.
+ */
+void emit_be_Perm(const ir_node *irn, emit_env_t *emit_env) {
+ FILE *F = emit_env->out;
+
+ lc_efprintf(ia32_get_arg_env(), F, "\txchg %1S, %2S\t\t\t/* %+F(%1A, %2A) */\n", irn, irn, irn);
+}
/***********************************************************************************
* _ __ _
IA32_EMIT(SwitchJmp);
IA32_EMIT(CopyB);
IA32_EMIT(CopyB_i);
+ IA32_EMIT(Conv_I2FP);
+ IA32_EMIT(Conv_FP2I);
+ IA32_EMIT(Conv_FP2FP);
/* benode emitter */
BE_EMIT(Call);
BE_EMIT(IncSP);
+ BE_EMIT(SetSP);
+ BE_EMIT(Copy);
+ BE_EMIT(Perm);
/* firm emitter */
EMIT(Jmp);
void (*emit)(const ir_node *, void *) = (void (*)(const ir_node *, void *))op->ops.generic;
(*emit)(irn, env);
}
- else {
- ir_fprintf(F, "\t\t\t\t\t/* %+F */\n", irn);
- }
+
+ ir_fprintf(F, "\t\t\t\t\t/* %+F */\n", irn);
}
/**