irn = my_skip_proj(irn);
if (is_cfop(irn))
return arch_irn_class_branch;
- else if (is_ia32_Call(irn))
- return arch_irn_class_call;
else if (is_ia32_irn(irn))
return arch_irn_class_normal;
else
#include "irprog_t.h"
#include "../besched.h"
+#include "../benode_t.h"
#include "ia32_emitter.h"
#include "gen_ia32_emitter.h"
lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%1D, %4S", n, n);
}
break;
- case ia32_am_Source:
+ case ia32_AddrModeS:
lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%1D, %s", n, ia32_emit_am(n));
break;
- case ia32_am_Dest:
- lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%s, %4S", ia32_emit_am(n), n);
+ 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 {
+ if (is_ia32_St(n)) {
+ lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%s, %3S", ia32_emit_am(n), n);
+ }
+ else {
+ lc_esnprintf(ia32_get_arg_env(), buf, SNPRINTF_BUF_LEN, "%s, %4S", ia32_emit_am(n), n);
+ }
+ }
break;
default:
assert(0 && "unsupported op type");
/**
* Returns the register at in position pos.
*/
-static const arch_register_t *get_in_reg(ir_node *irn, int pos) {
+static const arch_register_t *get_in_reg(const ir_node *irn, int pos) {
ir_node *op;
const arch_register_t *reg = NULL;
/**
* Returns the register at out position pos.
*/
-static const arch_register_t *get_out_reg(ir_node *irn, int pos) {
+static const arch_register_t *get_out_reg(const ir_node *irn, int pos) {
ir_node *proj;
const arch_register_t *reg = NULL;
if (!X)
return lc_arg_append(app, occ, "(null)", 6);
- buf = get_ia32_reg_name(X, nr, occ->conversion == 'S' ? IN_REG : OUT_REG);
+ buf = get_ia32_reg_name(X, nr, occ->conversion == 'S' ? IN_REG : OUT_REG);
- lc_appendable_chadd(app, '%');
return lc_arg_append(app, occ, buf, strlen(buf));
}
if (!X)
return lc_arg_append(app, occ, "(null)", 6);
- if (get_mode_size_bits(get_irn_mode(X)) == 32)
- return lc_appendable_chadd(app, 's');
- else
- return lc_appendable_chadd(app, 'd');
+ return lc_appendable_chadd(app, get_mode_size_bits(get_irn_mode(X)) == 32 ? 's' : 'd');
}
/**
if(env == NULL) {
/* extend the firm printer */
env = firm_get_arg_env();
- //lc_arg_new_env();
lc_arg_register(env, "ia32:sreg", 'S', &ia32_reg_handler);
lc_arg_register(env, "ia32:dreg", 'D', &ia32_reg_handler);
/**
* Emits the jump sequence for a conditional jump (cmp + jmp_true + jmp_false)
*/
-static void finish_CondJmp(FILE *F, ir_node *irn) {
+static void finish_CondJmp(FILE *F, const ir_node *irn) {
const ir_node *proj;
const ir_edge_t *edge;
char buf[SNPRINTF_BUF_LEN];
/**
* Emits code for conditional jump with two variables.
*/
-static void emit_ia32_CondJmp(ir_node *irn, emit_env_t *env) {
+static void emit_ia32_CondJmp(const ir_node *irn, emit_env_t *env) {
FILE *F = env->out;
lc_efprintf(ia32_get_arg_env(), F, "\tcmp %2S, %1S\t\t\t/* CondJmp(%+F, %+F) */\n", irn, irn,
/**
* Emits code for conditional jump with immediate.
*/
-void emit_ia32_CondJmp_i(ir_node *irn, emit_env_t *env) {
+void emit_ia32_CondJmp_i(const ir_node *irn, emit_env_t *env) {
FILE *F = env->out;
lc_efprintf(ia32_get_arg_env(), F, "\tcmp %C, %1S\t\t\t/* CondJmp_i(%+F) */\n", irn, irn, get_irn_n(irn, 0));
if (do_jmp_tbl) {
/* emit the table */
if (tbl.min_value != 0) {
- fprintf(F, "\tcmpl %lu, -%d", interval, tbl.min_value);
- lc_efprintf(env, F, "(%1S)\t\t/* first switch value is not 0 */\n", irn);
+ lc_efprintf(env, F, "\tcmpl %lu, -%d(%1S)\t\t/* first switch value is not 0 */\n",
+ interval, tbl.min_value, irn);
}
else {
- fprintf(F, "\tcmpl %lu, ", interval);
- lc_efprintf(env, F, "%1S\t\t\t/* compare for switch */\n", irn);
+ lc_efprintf(env, F, "\tcmpl %lu, %1S\t\t\t/* compare for switch */\n", interval, irn);
}
fprintf(F, "\tja %s\t\t\t/* default jump if out of range */\n", get_cfop_target(tbl.defProj, buf));
if (tbl.num_branches > 1) {
/* create table */
- //fprintf(F, "\tjmp *%s", tbl.label);
lc_efprintf(env, F, "\tjmp *%s(,%1S,4)\t\t/* get jump table entry as target */\n", tbl.label, irn);
fprintf(F, "\t.section\t.rodata\t\t/* start jump table */\n");
}
else { // no jump table
for (i = 0; i < tbl.num_branches; ++i) {
- fprintf(F, "\tcmpl %d, ", tbl.branches[i].value);
- lc_efprintf(env, F, "%1S", irn);
- fprintf(F, "\t\t\t/* case %d */\n", tbl.branches[i].value);
+ lc_efprintf(env, F, "\tcmpl %d, %1S\t\t\t/* case %d */\n", tbl.branches[i].value, irn, i);
fprintf(F, "\tje %s\n", get_cfop_target(tbl.branches[i].target, buf));
}
/**
* Emits code for a unconditional jump.
*/
-void emit_Jmp(ir_node *irn, emit_env_t *env) {
+void emit_Jmp(const ir_node *irn, emit_env_t *env) {
FILE *F = env->out;
char buf[SNPRINTF_BUF_LEN];
/**
* Emits code for a proj -> node
*/
-void emit_Proj(ir_node *irn, emit_env_t *env) {
+void emit_Proj(const ir_node *irn, emit_env_t *env) {
ir_node *pred = get_Proj_pred(irn);
if (get_irn_op(pred) == op_Start) {
}
}
-void emit_ia32_CopyB(ir_node *irn, emit_env_t *emit_env) {
+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);
int rem = get_tarval_long(tv);
fprintf(F, "\trep movsd\t\t\t\t/* memcopy */\n");
}
-void emit_ia32_CopyB_i(ir_node *irn, emit_env_t *emit_env) {
+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);
FILE *F = emit_env->out;
}
}
-/********************
- * _____ _ _
- * / ____| | | |
- * | | __ _| | |
- * | | / _` | | |
- * | |___| (_| | | |
- * \_____\__,_|_|_|
+
+
+/*******************************************
+ * _ _
+ * | | | |
+ * | |__ ___ _ __ ___ __| | ___ ___
+ * | '_ \ / _ \ '_ \ / _ \ / _` |/ _ \/ __|
+ * | |_) | __/ | | | (_) | (_| | __/\__ \
+ * |_.__/ \___|_| |_|\___/ \__,_|\___||___/
*
- ********************/
+ *******************************************/
+
+void emit_be_Call(const ir_node *irn, emit_env_t *emit_env) {
+ FILE *F = emit_env->out;
-void emit_ia32_Call(ir_node *irn, emit_env_t *emit_env) {
+ lc_efprintf(ia32_get_arg_env(), F, "\tcall %3S\t\t\t/* %+F(%+F) (be_Call) */\n", irn, irn, get_irn_n(irn, 2));
+}
+
+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);
+ be_stack_dir_t dir = be_get_IncSP_direction(irn);
+
+ if (offs) {
+ lc_efprintf(ia32_get_arg_env(), F, "\tadd %1S,%s%u\t\t\t/* %+F (IncSP) */\n", irn,
+ (dir == be_stack_dir_along) ? " -" : " ", offs, irn);
+ }
+ else {
+ fprintf(F, "\t\t\t\t\t/* omitted IncSP with 0 */\n");
+ }
+}
+
+void emit_be_AddSP(const ir_node *irn, emit_env_t *emit_env) {
+ FILE *F = emit_env->out;
+ lc_efprintf(ia32_get_arg_env(), F, "\tadd %1D, %1S\t\t\t/* %+F (AddSP) */\n", irn, irn, irn);
}
* pointer of an opcode.
*/
void ia32_register_emitters(void) {
- int i;
#define IA32_EMIT(a) op_ia32_##a->ops.generic = (op_func)emit_ia32_##a
#define EMIT(a) op_##a->ops.generic = (op_func)emit_##a
+#define BE_EMIT(a) op_be_##a->ops.generic = (op_func)emit_be_##a
- /* first clear all generic operations */
- for (i = get_irp_n_opcodes() - 1; i >= 0; --i) {
- ir_op *op = get_irp_opcode(i);
- op->ops.generic = (op_func)NULL;
- }
-
- /* generated int emitter functions */
- IA32_EMIT(Const);
-
- IA32_EMIT(Add);
- IA32_EMIT(Sub);
- IA32_EMIT(Minus);
- IA32_EMIT(Inc);
- IA32_EMIT(Dec);
-
- IA32_EMIT(Max);
- IA32_EMIT(Min);
- IA32_EMIT(CMov);
-
- IA32_EMIT(And);
- IA32_EMIT(Or);
- IA32_EMIT(Eor);
- IA32_EMIT(Not);
-
- IA32_EMIT(Shl);
- IA32_EMIT(Shr);
- IA32_EMIT(Shrs);
- IA32_EMIT(RotL);
- IA32_EMIT(RotR);
-
- IA32_EMIT(Lea);
-
- IA32_EMIT(Mul);
-
- IA32_EMIT(Cdq);
- IA32_EMIT(DivMod);
-
- IA32_EMIT(Store);
- IA32_EMIT(Load);
-
- IA32_EMIT(CopyB);
- IA32_EMIT(CopyB_i);
-
- /* generated floating point emitter */
- IA32_EMIT(fConst);
-
- IA32_EMIT(fAdd);
- IA32_EMIT(fSub);
-
- IA32_EMIT(fMul);
- IA32_EMIT(fDiv);
-
- IA32_EMIT(fMin);
- IA32_EMIT(fMax);
-
- IA32_EMIT(fLoad);
- IA32_EMIT(fStore);
+ /* register all emitter functions defined in spec */
+ ia32_register_spec_emitters();
/* other emitter functions */
IA32_EMIT(CondJmp);
IA32_EMIT(SwitchJmp);
- IA32_EMIT(Call);
+ IA32_EMIT(CopyB);
+ IA32_EMIT(CopyB_i);
+
+ /* benode emitter */
+ BE_EMIT(Call);
+ BE_EMIT(IncSP);
+ BE_EMIT(AddSP);
+ /* firm emitter */
EMIT(Jmp);
EMIT(Proj);
#undef IA32_EMIT
+#undef BE_EMIT
#undef EMIT
}
/**
* Emits code for a node.
*/
-static void ia32_emit_node(ir_node *irn, void *env) {
- emit_env_t *emit_env = env;
- firm_dbg_module_t *mod = emit_env->mod;
- FILE *F = emit_env->out;
- ir_op *op = get_irn_op(irn);
+static void ia32_emit_node(const ir_node *irn, void *env) {
+ emit_env_t *emit_env = env;
+ firm_dbg_module_t *mod = emit_env->mod;
+ FILE *F = emit_env->out;
+ ir_op *op = get_irn_op(irn);
DBG((mod, LEVEL_1, "emitting code for %+F\n", irn));
if (op->ops.generic) {
- void (*emit)(ir_node *, void *) = (void (*)(ir_node *, void *))op->ops.generic;
+ void (*emit)(const ir_node *, void *) = (void (*)(const ir_node *, void *))op->ops.generic;
(*emit)(irn, env);
}
-
- ir_fprintf(F, "\t\t\t\t\t/* %+F */\n", irn);
+ else {
+ ir_fprintf(F, "\t\t\t\t\t/* %+F */\n", irn);
+ }
}
/**
* and emits code for each node.
*/
static void ia32_gen_block(ir_node *block, void *env) {
- ir_node *irn;
+ const ir_node *irn;
if (! is_Block(block))
return;
/**
* Emits code for function start.
*/
-void ia32_emit_start(FILE *F, ir_graph *irg) {
+static void ia32_emit_func_prolog(FILE *F, ir_graph *irg) {
const char *irg_name = get_entity_name(get_irg_entity(irg));
fprintf(F, "\t.text\n");
/**
* Emits code for function end
*/
-void ia32_emit_end(FILE *F, ir_graph *irg) {
+static void ia32_emit_func_epilog(FILE *F, ir_graph *irg) {
const char *irg_name = get_entity_name(get_irg_entity(irg));
fprintf(F, "\tret\n");
* Sets labels for control flow nodes (jump target)
* TODO: Jump optimization
*/
-void ia32_gen_labels(ir_node *block, void *env) {
+static void ia32_gen_labels(ir_node *block, void *env) {
ir_node *pred;
int n = get_Block_n_cfgpreds(block);
/* set the global arch_env (needed by print hooks) */
arch_env = cg->arch_env;
- ia32_emit_start(F, irg);
+ ia32_emit_func_prolog(F, irg);
irg_block_walk_graph(irg, ia32_gen_labels, NULL, &emit_env);
irg_walk_blkwise_graph(irg, NULL, ia32_gen_block, &emit_env);
- ia32_emit_end(F, irg);
+ ia32_emit_func_epilog(F, irg);
}
else
assert(0 && "there should be no more Projs for a fDiv");
}
- else if (is_ia32_Call(pred)) {
- return 0;
- }
else if (get_irn_mode(proj) == mode_X && nr == pn_Start_X_initial_exec) {
return 0;
}
ir_mode *mode = NULL;
int bad = 0;
int i, n_res, am_flav, flags;
- ia32_attr_t *attr;
const ia32_register_req_t **reqs;
const arch_register_t **slots;
case dump_node_mode_txt:
mode = get_irn_mode(n);
- if (is_ia32_Load(n) || is_ia32_Store(n)) {
+ if (is_ia32_Ld(n) || is_ia32_St(n)) {
mode = get_ia32_ls_mode(n);
}
- if (mode) {
- fprintf(F, "[%s]", get_mode_name(mode));
- }
- else {
- fprintf(F, "[?NOMODE?]");
- }
+ fprintf(F, "[%s]", mode ? get_mode_name(mode) : "?NOMODE?");
break;
case dump_node_nodeattr_txt:
- if (is_ia32_Call(n)) {
- fprintf(F, "&%s ", get_ia32_sc(n));
- }
- else if (get_ia32_cnst(n)) {
+ if (get_ia32_cnst(n)) {
char *pref = "";
if (get_ia32_sc(n)) {
break;
case dump_node_info_txt:
- attr = get_ia32_attr(n);
n_res = get_ia32_n_res(n);
fprintf(F, "=== IA32 attr begin ===\n");
slots = get_ia32_slots(n);
if (slots && n_res > 0) {
for (i = 0; i < n_res; i++) {
- if (slots[i]) {
- fprintf(F, "reg #%d = %s\n", i, slots[i]->name);
- }
- else {
- fprintf(F, "reg #%d = n/a\n", i);
- }
+ fprintf(F, "reg #%d = %s\n", i, slots[i] ? slots[i]->name : "n/a");
}
+ fprintf(F, "\n");
}
- fprintf(F, "\n");
/* dump op type */
fprintf(F, "op = ");
/* offset could already have an explicit sign */
/* -> supersede op if necessary */
- if (offset[0] == '-' && op == '-') {
- op = '+';
- }
- else if (offset[0] == '-' && op == '+') {
- op = '-';
- }
-
- /* skip explicit sign */
if (offset[0] == '-' || offset[0] == '+') {
+ if (offset[0] == '-') {
+ op = (op == '-') ? '+' : '-';
+ }
+
+ /* skip explicit sign */
offset++;
}
* Sets the index register scale for addrmode.
*/
void set_ia32_am_scale(ir_node *node, int scale) {
- ia32_attr_t *attr = get_ia32_attr(node);
- attr->data.am_scale = scale;
+ ia32_attr_t *attr = get_ia32_attr(node);
+ attr->data.am_scale = scale;
}
/**
* Sets the uses_frame flag.
*/
void set_ia32_use_frame(ir_node *node) {
- ia32_attr_t *attr = get_ia32_attr(node);
+ ia32_attr_t *attr = get_ia32_attr(node);
attr->data.use_frame = 1;
}
* Clears the uses_frame flag.
*/
void clear_ia32_use_frame(ir_node *node) {
- ia32_attr_t *attr = get_ia32_attr(node);
+ ia32_attr_t *attr = get_ia32_attr(node);
attr->data.use_frame = 0;
}
*/
int is_ia32_commutative(const ir_node *node) {
ia32_attr_t *attr = get_ia32_attr(node);
-
return attr->data.is_commutative;
}
unsigned get_ia32_Const_type(const ir_node *node) {
ia32_attr_t *attr = get_ia32_attr(node);
- assert((is_ia32_Const(node) || is_ia32_fConst(node)) && "Need ia32_Const to get type");
+ assert(is_ia32_Cnst(node) && "Need ia32_Const to get type");
return attr->data.tp;
}
void set_ia32_Const_type(ir_node *node, int type) {
ia32_attr_t *attr = get_ia32_attr(node);
- assert((is_ia32_Const(node) || is_ia32_fConst(node)) && "Need ia32_Const to set type");
+ assert(is_ia32_Cnst(node) && "Need ia32_Const to set type");
assert((type == ia32_Const || type == ia32_SymConst) && "Unsupported ia32_Const type");
attr->data.tp = type;
ia32_attr_t *na = get_ia32_attr(node);
ia32_attr_t *ca = get_ia32_attr(cnst);
- assert((is_ia32_Const(cnst) || is_ia32_fConst(cnst)) && "Need ia32_Const to set Immop attr");
+ assert(is_ia32_Cnst(cnst) && "Need ia32_Const to set Immop attr");
na->tv = ca->tv;
void set_ia32_Const_attr(ir_node *ia32_cnst, ir_node *cnst) {
ia32_attr_t *attr = get_ia32_attr(ia32_cnst);
- assert((is_ia32_Const(ia32_cnst) || is_ia32_fConst(ia32_cnst)) && "Need ia32_Const to set Const attr");
+ assert(is_ia32_Cnst(ia32_cnst) && "Need ia32_Const to set Const attr");
switch (get_irn_opcode(cnst)) {
case iro_Const:
- attr->data.tp = ia32_Const;
- attr->tv = get_Const_tarval(cnst);
- attr->cnst = set_cnst_from_tv(attr->cnst, attr->tv);
+ attr->data.tp = ia32_Const;
+ attr->tv = get_Const_tarval(cnst);
+ attr->cnst = set_cnst_from_tv(attr->cnst, attr->tv);
break;
case iro_SymConst:
- attr->data.tp = ia32_SymConst;
- attr->tv = NULL;
- attr->sc = copy_str(attr->sc, get_sc_name(cnst));
- attr->cnst = attr->sc;
+ attr->data.tp = ia32_SymConst;
+ attr->tv = NULL;
+ attr->sc = copy_str(attr->sc, get_sc_name(cnst));
+ attr->cnst = attr->sc;
break;
case iro_Unknown:
assert(0 && "Unknown Const NYI");
return is_ia32_Store(node) || is_ia32_fStore(node);
}
+/**
+ * Checks if node is a Const or fConst.
+ */
+int is_ia32_Cnst(const ir_node *node) {
+ return is_ia32_Const(node) || is_ia32_fConst(node);
+}
+
/**
* Returns the name of the OUT register at position pos.
*/
attr->slots = NULL;
}
- attr->data.n_res;
+ attr->data.n_res = num;
}
/**
*
***************************************************************************************/
+/* default compare operation to compare immediate ops */
+int ia32_compare_immop_attr(ia32_attr_t *a, ia32_attr_t *b) {
+ if (a->data.tp == b->data.tp) {
+ if (! a->cnst || ! b->cnst)
+ return 1;
+
+ return strcmp(a->cnst, b->cnst);
+ }
+
+ return 1;
+}
+
/* Include the generated constructor functions */
#include "gen_ia32_new_nodes.c.inl"
*/
int is_ia32_St(const ir_node *node);
+/**
+ * Checks if node is a Const or fConst.
+ */
+int is_ia32_Cnst(const ir_node *node);
+
/**
* Allocates num register slots for node.
*/
******************************************************************/
static int node_is_comm(const ir_node *irn) {
- if (is_ia32_Add(irn) ||
- is_ia32_fAdd(irn) ||
- is_ia32_Mul(irn) ||
- is_ia32_Mulh(irn) ||
- is_ia32_fMul(irn) ||
- is_ia32_And(irn) ||
- is_ia32_fAnd(irn) ||
- is_ia32_Or(irn) ||
- is_ia32_fOr(irn) ||
- is_ia32_Eor(irn) ||
- is_ia32_fEor(irn) ||
- is_ia32_Min(irn) ||
- is_ia32_fMin(irn) ||
- is_ia32_Max(irn) ||
- is_ia32_fMax(irn))
- {
- return 1;
- }
-
- return 0;
+ return is_ia32_irn(irn) ? is_ia32_commutative(irn) : 0;
}
static int ia32_get_irn_n_edges(const ir_node *irn) {
add_ia32_am_offs(irn, get_ia32_am_offs(left));
set_ia32_am_scale(irn, get_ia32_am_scale(left));
set_ia32_am_flavour(irn, get_ia32_am_flavour(left));
- set_ia32_op_type(irn, get_ia32_op_type(left));
+
+ set_ia32_op_type(irn, is_ia32_St(irn) ? ia32_AddrModeD : ia32_AddrModeS);
/* set base and index */
set_irn_n(irn, 0, get_irn_n(left, 0));
{ "name" => "esi", "type" => 2 },
{ "name" => "edi", "type" => 2 },
{ "name" => "ebp", "type" => 2 },
- { "name" => "esp", "type" => 6 },
+ { "name" => "esp", "type" => 4 },
{ "name" => "xxx", "type" => 6 }, # we need a dummy register for NoReg and Unknown nodes
{ "mode" => "mode_P" }
],
"Add" => {
"irn_flags" => "R",
"comment" => "construct Add: Add(a, b) = Add(b, a) = a + b",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r1" ] },
"emit" => '. add %ia32_emit_binop\t\t\t/* Add(%A1, %A2) -> %D1 */'
},
"Mul" => {
"irn_flags" => "A",
"comment" => "construct Mul: Mul(a, b) = Mul(b, a) = a * b",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r1" ] },
"emit" => '. imul %ia32_emit_binop\t\t\t/* Mul(%A1, %A2) -> %D1 */'
},
# Mulh is an exception from the 4 INs with AM because the target is always EAX:EDX
"Mulh" => {
"comment" => "construct Mul: Mul(a, b) = Mul(b, a) = a * b",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "eax in_r1", "edx in_r2" ] },
"emit" => '. imul %ia32_emit_unop\t\t\t/* Mulh(%A1, %A2) -> %D1 */ '
},
"And" => {
"irn_flags" => "R",
"comment" => "construct And: And(a, b) = And(b, a) = a AND b",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r1" ] },
"emit" => '. and %ia32_emit_binop\t\t\t/* And(%A1, %A2) -> %D1 */'
},
"Or" => {
"irn_flags" => "R",
"comment" => "construct Or: Or(a, b) = Or(b, a) = a OR b",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r1" ] },
"emit" => '. or %ia32_emit_binop\t\t\t/* Or(%A1, %A2) -> %D1 */'
},
"Eor" => {
"irn_flags" => "R",
"comment" => "construct Eor: Eor(a, b) = Eor(b, a) = a EOR b",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r1" ] },
"emit" => '. xor %ia32_emit_binop\t\t\t/* Xor(%A1, %A2) -> %D1 */'
},
"Sub" => {
"irn_flags" => "R",
"comment" => "construct Sub: Sub(a, b) = a - b",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "in_r1" ] },
"emit" => '. sub %ia32_emit_binop\t\t\t/* Sub(%A1, %A2) -> %D1 */'
},
"Shl" => {
"irn_flags" => "R",
"comment" => "construct Shl: Shl(a, b) = a << b",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "gp", "ecx", "none" ], "out" => [ "in_r1" ] },
"emit" => '. shl %ia32_emit_binop\t\t\t/* Shl(%A1, %A2) -> %D1 */'
},
"Shr" => {
"irn_flags" => "R",
"comment" => "construct Shr: Shr(a, b) = a >> b",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "gp", "ecx", "none" ], "out" => [ "in_r1" ] },
"emit" => '. shr %ia32_emit_binop\t\t\t/* Shr(%A1, %A2) -> %D1 */'
},
"Shrs" => {
"irn_flags" => "R",
"comment" => "construct Shrs: Shrs(a, b) = a >> b",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "gp", "ecx", "none" ], "out" => [ "in_r1" ] },
"emit" => '. sar %ia32_emit_binop\t\t\t/* Shrs(%A1, %A2) -> %D1 */'
},
"RotR" => {
"irn_flags" => "R",
"comment" => "construct RotR: RotR(a, b) = a ROTR b",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "gp", "ecx", "none" ], "out" => [ "in_r1" ] },
"emit" => '. ror %ia32_emit_binop\t\t\t/* RotR(%A1, %A2) -> %D1 */'
},
"RotL" => {
"irn_flags" => "R",
"comment" => "construct RotL: RotL(a, b) = a ROTL b",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "gp", "ecx", "none" ], "out" => [ "in_r1" ] },
"emit" => '. rol %ia32_emit_binop\t\t\t/* RotL(%A1, %A2) -> %D1 */'
},
"Minus" => {
"irn_flags" => "R",
"comment" => "construct Minus: Minus(a) = -a",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "gp", "none" ], "out" => [ "in_r1" ] },
"emit" => '. neg %ia32_emit_unop\t\t\t/* Neg(%A1) -> %D1, (%A1) */'
},
"Inc" => {
"irn_flags" => "R",
"comment" => "construct Increment: Inc(a) = a++",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "gp", "none" ], "out" => [ "in_r1" ] },
"emit" => '. inc %ia32_emit_unop\t\t\t/* Inc(%S1) -> %D1, (%A1) */'
},
"Dec" => {
"irn_flags" => "R",
"comment" => "construct Decrement: Dec(a) = a--",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "gp", "none" ], "out" => [ "in_r1" ] },
"emit" => '. dec %ia32_emit_unop\t\t\t/* Dec(%S1) -> %D1, (%A1) */'
},
"Not" => {
"irn_flags" => "R",
"comment" => "construct Not: Not(a) = !a",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "gp", "none" ], "out" => [ "in_r1" ] },
"emit" => '. not %ia32_emit_unop\t\t\t/* Not(%S1) -> %D1, (%A1) */'
},
"CondJmp" => {
"op_flags" => "L|X|Y",
"comment" => "construct conditional jump: CMP A, B && JMPxx LABEL",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "gp", "gp", "none" ], "out" => [ "none", "none" ] },
},
"SwitchJmp" => {
"op_flags" => "L|X|Y",
"comment" => "construct switch",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "gp", "none" ], "out" => [ "none" ] },
},
"op_flags" => "c",
"irn_flags" => "R",
"comment" => "represents an integer constant",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "out" => [ "gp" ] },
"emit" => '. mov %D1, %C\t\t\t/* Mov Const into register */',
- "cmp_attr" =>
-'
- if (attr_a->data.tp == attr_b->data.tp) {
- if (attr_a->data.tp == ia32_SymConst) {
- if (attr_a->sc == NULL || attr_b->sc == NULL)
- return 1;
- else
- return strcmp(attr_a->sc, attr_b->sc);
- }
- else {
- if (attr_a->tv == NULL || attr_b->tv == NULL)
- return 1;
-
- if (tarval_cmp(attr_a->tv, attr_b->tv) == pn_Cmp_Eq)
- return 0;
- else
- return 1;
- }
- }
- else
- return 1;
-'
},
"Cdq" => {
"irn_flags" => "R",
"state" => "exc_pinned",
"comment" => "construct Load: Load(ptr, mem) = LD ptr -> reg",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "none" ], "out" => [ "gp" ] },
"emit" => '. mov %D1, %ia32_emit_am\t\t\t/* Load((%A1)) -> %D1 */'
},
"op_flags" => "L|F",
"state" => "exc_pinned",
"comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "gp", "none" ] },
- "emit" => '. mov %ia32_emit_am, %S3\t\t\t/* Store(%A2) -> (%A1) */'
+ "emit" => '. mov %ia32_emit_binop\t\t\t/* Store(%A3) -> (%A1) */'
},
"Lea" => {
"irn_flags" => "R",
"comment" => "construct Lea: Lea(a,b) = lea [a+b*const+offs] | res = a + b * const + offs with const = 0,1,2,4,8",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp" ], "out" => [ "gp" ] },
- "emit" => '. lea %D1, %ia32_emit_am\t\t/* %D1 = %S1 + %S2 << %C + %O, (%A1, %A2) */'
+ "emit" => '. lea %D1, %ia32_emit_am\t\t/* %D1 = %S1 + %S2 << scale + %O, (%A1, %A2) */'
},
#--------------------------------------------------------#
"fAdd" => {
"irn_flags" => "R",
"comment" => "construct SSE Add: Add(a, b) = Add(b, a) = a + b",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "fp", "fp", "none" ], "out" => [ "in_r1" ] },
"emit" => '. adds%M %ia32_emit_binop\t\t\t/* SSE Add(%A1, %A2) -> %D1 */'
},
"fMul" => {
"irn_flags" => "R",
"comment" => "construct SSE Mul: Mul(a, b) = Mul(b, a) = a * b",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "fp", "fp", "none" ], "out" => [ "in_r3" ] },
"emit" => '. muls%M %ia32_emit_binop\t\t\t/* SSE Mul(%A1, %A2) -> %D1 */'
},
"fMax" => {
"irn_flags" => "R",
"comment" => "construct SSE Max: Max(a, b) = Max(b, a) = a > b ? a : b",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "fp", "fp", "none" ], "out" => [ "in_r3" ] },
"emit" => '. maxs%M %ia32_emit_binop\t\t\t/* SSE Max(%A1, %A2) -> %D1 */'
},
"fMin" => {
"irn_flags" => "R",
"comment" => "construct SSE Min: Min(a, b) = Min(b, a) = a < b ? a : b",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "fp", "fp", "none" ], "out" => [ "in_r3" ] },
"emit" => '. mins%M %ia32_emit_binop\t\t\t/* SSE Min(%A1, %A2) -> %D1 */'
},
"fAnd" => {
"irn_flags" => "R",
"comment" => "construct SSE And: And(a, b) = a AND b",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "fp", "fp", "none" ], "out" => [ "in_r3" ] },
"emit" => '. andp%M %ia32_emit_binop\t\t\t/* SSE And(%A3, %A4) -> %D1 */'
},
"fOr" => {
"irn_flags" => "R",
"comment" => "construct SSE Or: Or(a, b) = a OR b",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "fp", "fp", "none" ], "out" => [ "in_r3" ] },
"emit" => '. orp%M %ia32_emit_binop\t\t\t/* SSE Or(%A3, %A4) -> %D1 */'
},
"fEor" => {
"irn_flags" => "R",
"comment" => "construct SSE Eor: Eor(a, b) = a XOR b",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "fp", "fp", "none" ], "out" => [ "in_r3" ] },
"emit" => '. xorp%M %ia32_emit_binop\t\t\t/* SSE Xor(%A3, %A4) -> %D1 */'
},
"fSub" => {
"irn_flags" => "R",
"comment" => "construct SSE Sub: Sub(a, b) = a - b",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "fp", "fp", "none" ], "out" => [ "in_r1" ] },
"emit" => '. subs%M %ia32_emit_binop\t\t\t/* SSE Sub(%A1, %A2) -> %D1 */'
},
"fDiv" => {
"irn_flags" => "R",
"comment" => "construct SSE Div: Div(a, b) = a / b",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "fp", "fp", "none" ], "out" => [ "in_r1" ] },
"emit" => '. divs%M %ia32_emit_binop\t\t\t/* SSE Div(%A1, %A2) -> %D1 */'
},
"fCondJmp" => {
"op_flags" => "L|X|Y",
"comment" => "construct conditional jump: UCOMIS A, B && JMPxx LABEL",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "fp", "fp", "none" ], "out" => [ "none", "none" ] },
},
"op_flags" => "c",
"irn_flags" => "R",
"comment" => "represents a SSE constant",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "out" => [ "fp" ] },
"emit" => '. mov%M %D1, %C\t\t\t/* Load fConst into register */',
- "cmp_attr" =>
-'
- if (attr_a->data.tp == attr_b->data.tp) {
- if (attr_a->data.tp == ia32_SymConst) {
- if (attr_a->sc == NULL || attr_b->sc == NULL)
- return 1;
- else
- return strcmp(attr_a->sc, attr_b->sc);
- }
- else {
- if (attr_a->tv == NULL || attr_b->tv == NULL)
- return 1;
-
- if (tarval_cmp(attr_a->tv, attr_b->tv) == pn_Cmp_Eq)
- return 0;
- else
- return 1;
- }
- }
- else
- return 1;
-'
},
# Load / Store
"irn_flags" => "R",
"state" => "exc_pinned",
"comment" => "construct SSE Load: Load(ptr, mem) = LD ptr",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "none" ], "out" => [ "fp" ] },
"emit" => '. movs%M %D1, %ia32_emit_am\t\t\t/* Load((%A1)) -> %D1 */'
},
"op_flags" => "L|F",
"state" => "exc_pinned",
"comment" => "construct Store: Store(ptr, val, mem) = ST ptr,val",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
"reg_req" => { "in" => [ "gp", "gp", "fp", "none" ] },
"emit" => '. movs%M %ia32_emit_am, %S3\t\t\t/* Store(%S3) -> (%A1) */'
},
# CopyB
"CopyB" => {
- "op_flags" => "F|H",
- "state" => "pinned",
- "comment" => "implements a memcopy: CopyB(dst, src, size, mem) == memcpy(dst, src, size)",
- "reg_req" => { "in" => [ "edi", "esi", "ecx", "none" ], "out" => [ "none" ] },
+ "op_flags" => "F|H",
+ "state" => "pinned",
+ "comment" => "implements a memcopy: CopyB(dst, src, size, mem) == memcpy(dst, src, size)",
+ "reg_req" => { "in" => [ "edi", "esi", "ecx", "none" ], "out" => [ "none" ] },
},
"CopyB_i" => {
- "op_flags" => "F|H",
- "state" => "pinned",
- "comment" => "implements a memcopy: CopyB(dst, src, mem) == memcpy(dst, src, attr(size))",
- "reg_req" => { "in" => [ "edi", "esi", "none" ], "out" => [ "none" ] },
-},
-
-# Call
-
-"Call" => {
- "op_flags" => "L|F",
- "state" => "mem_pinned",
- "arity" => "variable",
- "comment" => "construct Call: Call(...)",
- "args" => [
- { "type" => "int", "name" => "n" },
- { "type" => "ir_node **", "name" => "in" }
- ],
- "rd_constructor" =>
-" if (!op_ia32_Call) assert(0);
- return new_ir_node(db, irg, block, op_ia32_Call, mode_T, n, in);
-"
+ "op_flags" => "F|H",
+ "state" => "pinned",
+ "comment" => "implements a memcopy: CopyB(dst, src, mem) == memcpy(dst, src, attr(size))",
+ "cmp_attr" => " return ia32_compare_immop_attr(attr_a, attr_b);\n",
+ "reg_req" => { "in" => [ "edi", "esi", "none" ], "out" => [ "none" ] },
},
); # end of %nodes
}
-#undef is_cnst
-#define is_cnst(op) (is_ia32_Const(op) || is_ia32_fConst(op))
/* determine if one operator is an Imm */
static ir_node *get_immediate_op(ir_node *op1, ir_node *op2) {
if (op1)
- return is_cnst(op1) ? op1 : (is_cnst(op2) ? op2 : NULL);
- else return is_cnst(op2) ? op2 : NULL;
+ return is_ia32_Cnst(op1) ? op1 : (is_ia32_Cnst(op2) ? op2 : NULL);
+ else return is_ia32_Cnst(op2) ? op2 : NULL;
}
/* determine if one operator is not an Imm */
static ir_node *get_expr_op(ir_node *op1, ir_node *op2) {
- return !is_cnst(op1) ? op1 : (!is_cnst(op2) ? op2 : NULL);
+ return !is_ia32_Cnst(op1) ? op1 : (!is_ia32_Cnst(op2) ? op2 : NULL);
}
}
}
+ if (is_op_commutative(get_irn_op(env->irn))) {
+ set_ia32_commutative(new_op);
+ }
+
return new_rd_Proj(dbg, irg, block, new_op, mode, 0);
}
}
set_ia32_am_support(new_op, ia32_am_Source);
+ set_ia32_op_type(new_op, ia32_AddrModeS);
+ set_ia32_am_flavour(new_op, ia32_B);
set_ia32_ls_mode(new_op, get_Load_mode(node));
return new_op;
static ir_node *gen_Store(ia32_transform_env_t *env) {
ir_node *node = env->irn;
ir_node *noreg = ia32_new_NoReg_gp(env->cg);
+ ir_node *val = get_Store_value(node);
+ ir_node *ptr = get_Store_ptr(node);
+ ir_node *mem = get_Store_mem(node);
+ ir_node *sval = val;
ir_node *new_op;
+ /* in case of storing a const -> make it an attribute */
+ if (is_ia32_Cnst(val)) {
+ sval = noreg;
+ }
+
if (mode_is_float(env->mode)) {
- new_op = new_rd_ia32_fStore(env->dbg, env->irg, env->block, get_Store_ptr(node), noreg, get_Store_value(node), get_Store_mem(node), env->mode);
+ new_op = new_rd_ia32_fStore(env->dbg, env->irg, env->block, ptr, noreg, sval, mem, env->mode);
}
else {
- new_op = new_rd_ia32_Store(env->dbg, env->irg, env->block, get_Store_ptr(node), noreg, get_Store_value(node), get_Store_mem(node), env->mode);
+ new_op = new_rd_ia32_Store(env->dbg, env->irg, env->block, ptr, noreg, sval, mem, env->mode);
+ }
+
+ /* stored const is an attribute (saves a register) */
+ if (is_ia32_Cnst(val)) {
+ set_ia32_Immop_attr(new_op, val);
}
set_ia32_am_support(new_op, ia32_am_Dest);
- set_ia32_ls_mode(new_op, get_irn_mode(get_Store_value(node)));
+ set_ia32_op_type(new_op, ia32_AddrModeD);
+ set_ia32_am_flavour(new_op, ia32_B);
+ set_ia32_ls_mode(new_op, get_irn_mode(val));
return new_op;
}