/*
- * Copyright (C) 1995-2007 University of Karlsruhe. All right reserved.
+ * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
*
* This file is part of libFirm.
*
#include "config.h"
#endif
-#include <libcore/lc_opts.h>
-#include <libcore/lc_opts_enum.h>
+#include "lc_opts.h"
+#include "lc_opts_enum.h"
#include <math.h>
#include "irgopt.h"
#include "irbitset.h"
#include "irgopt.h"
+#include "irdump_grgen.h"
#include "pdeq.h"
#include "pset.h"
#include "debug.h"
#include "xmalloc.h"
#include "irtools.h"
#include "iroptimize.h"
+#include "instrument.h"
#include "../beabi.h"
#include "../beirg_t.h"
#include "ia32_fpu.h"
#include "ia32_architecture.h"
+#ifdef FIRM_GRGEN_BE
+#include "ia32_pbqp_transform.h"
+#endif
+
DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
/* TODO: ugly */
/**
- * Returns gp_noreg or fp_noreg, depending in input requirements.
+ * Returns the admissible noreg register node for input register pos of node irn.
*/
ir_node *ia32_get_admissible_noreg(ia32_code_gen_t *cg, ir_node *irn, int pos) {
const arch_register_req_t *req;
const ir_node *node,
int pos)
{
- long node_pos = pos == -1 ? 0 : pos;
- ir_mode *mode = is_Block(node) ? NULL : get_irn_mode(node);
- (void) self;
+ ir_mode *mode = get_irn_mode(node);
+ long node_pos;
- if (is_Block(node) || mode == mode_X) {
+ (void)self;
+ if (mode == mode_X || is_Block(node)) {
return arch_no_register_req;
}
return arch_no_register_req;
}
+ node_pos = pos == -1 ? 0 : pos;
if (is_Proj(node)) {
- if(mode == mode_M)
- return arch_no_register_req;
-
- if(pos >= 0) {
+ if (mode == mode_M || pos >= 0) {
return arch_no_register_req;
}
if (is_ia32_irn(node)) {
const arch_register_req_t *req;
- if(pos >= 0)
+ if (pos >= 0)
req = get_ia32_in_req(node, pos);
else
req = get_ia32_out_req(node, node_pos);
/* unknowns should be transformed already */
assert(!is_Unknown(node));
-
return arch_no_register_req;
}
static void ia32_set_irn_reg(const void *self, ir_node *irn,
const arch_register_t *reg)
{
- int pos = 0;
+ int pos = 0;
(void) self;
if (get_irn_mode(irn) == mode_X) {
set_ia32_frame_ent(irn, ent);
}
-static void ia32_set_frame_offset(const void *self, ir_node *irn, int bias) {
+static void ia32_set_frame_offset(const void *self, ir_node *irn, int bias)
+{
const ia32_irn_ops_t *ops = self;
- if (get_ia32_frame_ent(irn)) {
- if (is_ia32_Pop(irn)) {
- int omit_fp = be_abi_omit_fp(ops->cg->birg->abi);
- if (omit_fp) {
- /* Pop nodes modify the stack pointer before calculating the destination
- * address, so fix this here
- */
- bias -= 4;
- }
- }
+ if (get_ia32_frame_ent(irn) == NULL)
+ return;
- add_ia32_am_offs_int(irn, bias);
+ if (is_ia32_Pop(irn) || is_ia32_PopMem(irn)) {
+ int omit_fp = be_abi_omit_fp(ops->cg->birg->abi);
+ if (omit_fp) {
+ /* Pop nodes modify the stack pointer before calculating the
+ * destination address, so fix this here
+ */
+ bias -= 4;
+ }
}
+ add_ia32_am_offs_int(irn, bias);
}
static int ia32_get_sp_bias(const void *self, const ir_node *node)
if (is_ia32_Push(node))
return 4;
- if (is_ia32_Pop(node))
+ if (is_ia32_Pop(node) || is_ia32_PopMem(node))
return -4;
return 0;
be_node_set_flags(get_Proj_pred(curr_bp), BE_OUT_POS(get_Proj_proj(curr_bp)), arch_irn_flags_ignore);
/* push ebp */
- push = new_rd_ia32_Push(NULL, env->irg, bl, noreg, noreg, *mem, curr_sp, curr_bp);
+ push = new_rd_ia32_Push(NULL, env->irg, bl, noreg, noreg, *mem, curr_bp, curr_sp);
curr_sp = new_r_Proj(env->irg, bl, push, get_irn_mode(curr_sp), pn_ia32_Push_stack);
*mem = new_r_Proj(env->irg, bl, push, mode_M, pn_ia32_Push_M);
if (env->flags.try_omit_fp) {
/* simply remove the stack frame here */
- curr_sp = be_new_IncSP(env->isa->sp, env->irg, bl, curr_sp, BE_STACK_FRAME_SIZE_SHRINK);
+ curr_sp = be_new_IncSP(env->isa->sp, env->irg, bl, curr_sp, BE_STACK_FRAME_SIZE_SHRINK, 0);
add_irn_dep(curr_sp, *mem);
} else {
- const ia32_isa_t *isa = (ia32_isa_t *)env->isa;
- ia32_code_gen_t *cg = isa->cg;
ir_mode *mode_bp = env->isa->bp->reg_class->mode;
ir_graph *irg = current_ir_graph;
curr_bp = new_r_Proj(irg, bl, leave, mode_bp, pn_ia32_Leave_frame);
curr_sp = new_r_Proj(irg, bl, leave, get_irn_mode(curr_sp), pn_ia32_Leave_stack);
} else {
- ir_node *noreg = ia32_new_NoReg_gp(cg);
ir_node *pop;
/* the old SP is not needed anymore (kill the proj) */
be_node_set_flags(curr_sp, BE_OUT_POS(0), arch_irn_flags_ignore);
/* pop ebp */
- pop = new_rd_ia32_Pop(NULL, env->irg, bl, noreg, noreg, *mem, curr_sp);
+ pop = new_rd_ia32_Pop(NULL, env->irg, bl, *mem, curr_sp);
set_ia32_flags(pop, arch_irn_flags_ignore);
curr_bp = new_r_Proj(irg, bl, pop, mode_bp, pn_ia32_Pop_res);
curr_sp = new_r_Proj(irg, bl, pop, get_irn_mode(curr_sp), pn_ia32_Pop_stack);
}
/**
- * Check if irn can load it's operand at position i from memory (source addressmode).
+ * Check if irn can load its operand at position i from memory (source addressmode).
* @param self Pointer to irn ops itself
* @param irn The irn to be checked
* @param i The operands position
const ir_mode *spillmode = get_spill_mode(op);
(void) self;
- if (! is_ia32_irn(irn) || /* must be an ia32 irn */
+ if (
+ (i != n_ia32_binary_left && i != n_ia32_binary_right) || /* a "real" operand position must be requested */
+ ! is_ia32_irn(irn) || /* must be an ia32 irn */
get_ia32_am_arity(irn) != ia32_am_binary || /* must be a binary operation TODO is this necessary? */
get_ia32_op_type(irn) != ia32_Normal || /* must not already be a addressmode irn */
! (get_ia32_am_support(irn) & ia32_am_Source) || /* must be capable of source addressmode */
! ia32_is_spillmode_compatible(mode, spillmode) ||
- (i != n_ia32_binary_left && i != n_ia32_binary_right) || /* a "real" operand position must be requested */
is_ia32_use_frame(irn)) /* must not already use frame */
return 0;
* (As this (currently) breaks constraint handling copies)
*/
req = get_ia32_in_req(irn, n_ia32_binary_left);
- if(req->type & arch_register_req_type_limited) {
+ if (req->type & arch_register_req_type_limited) {
return 0;
}
}
ir_node *spill, unsigned int i)
{
const ia32_irn_ops_t *ops = self;
- ia32_code_gen_t *cg = ops->cg;
assert(ia32_possible_memory_operand(self, irn, i) && "Cannot perform memory operand change");
set_ia32_need_stackent(irn);
set_irn_n(irn, n_ia32_base, get_irg_frame(get_irn_irg(irn)));
- set_irn_n(irn, n_ia32_binary_right, ia32_get_admissible_noreg(cg, irn, n_ia32_binary_right));
+ set_irn_n(irn, n_ia32_binary_right, ia32_get_admissible_noreg(ops->cg, irn, n_ia32_binary_right));
set_irn_n(irn, n_ia32_mem, spill);
/* immediates are only allowed on the right side */
* |___/
**************************************************/
+static ir_entity *mcount = NULL;
+
+#define ID(s) new_id_from_chars(s, sizeof(s) - 1)
+
static void ia32_before_abi(void *self) {
lower_mode_b_config_t lower_mode_b_config = {
mode_Iu, /* lowered mode */
ia32_code_gen_t *cg = self;
ir_lower_mode_b(cg->irg, &lower_mode_b_config);
- if(cg->dump)
+ if (cg->dump)
be_dump(cg->irg, "-lower_modeb", dump_ir_block_graph_sched);
+ if (cg->gprof) {
+ if (mcount == NULL) {
+ ir_type *tp = new_type_method(ID("FKT.mcount"), 0, 0);
+ mcount = new_entity(get_glob_type(), ID("mcount"), tp);
+ /* FIXME: enter the right ld_ident here */
+ set_entity_ld_ident(mcount, get_entity_ident(mcount));
+ set_entity_visibility(mcount, visibility_external_allocated);
+ }
+ instrument_initcall(cg->irg, mcount);
+ }
}
/**
edges_activate(cg->irg);
#endif
- if(cg->dump)
+ if (cg->dump)
be_dump(cg->irg, "-pre_transform", dump_ir_block_graph_sched);
- /* transform nodes into assembler instructions */
+#ifdef FIRM_GRGEN_BE
+ /* transform nodes into assembler instructions by PBQP magic */
+ ia32_transform_graph_by_pbqp(cg);
+#endif
+
+ if (cg->dump)
+ be_dump(cg->irg, "-after_pbqp_transform", dump_ir_block_graph_sched);
+
+ /* transform remaining nodes into assembler instructions */
ia32_transform_graph(cg);
/* do local optimisations (mainly CSE) */
clear_ia32_am_sc_sign(node);
/* rewire mem-proj */
- if(get_irn_mode(node) == mode_T) {
+ if (get_irn_mode(node) == mode_T) {
mem_proj = NULL;
foreach_out_edge(node, edge) {
ir_node *out = get_edge_src_irn(edge);
}
set_ia32_op_type(node, ia32_Normal);
- if(sched_is_scheduled(node))
+ if (sched_is_scheduled(node))
sched_add_before(node, load);
}
static ir_node *flags_remat(ir_node *node, ir_node *after)
{
/* we should turn back source address mode when rematerializing nodes */
- ia32_op_type_t type = get_ia32_op_type(node);
+ ia32_op_type_t type;
ir_node *block;
ir_node *copy;
- if(is_Block(after)) {
+ if (is_Block(after)) {
block = after;
} else {
block = get_nodes_block(after);
}
+ type = get_ia32_op_type(node);
switch (type) {
case ia32_AddrModeS: turn_back_am(node); break;
new_op = new_rd_ia32_vfld(dbg, irg, block, ptr, noreg, mem, spillmode);
}
else if (get_mode_size_bits(spillmode) == 128) {
- // Reload 128 bit sse registers
+ /* Reload 128 bit SSE registers */
new_op = new_rd_ia32_xxLoad(dbg, irg, block, ptr, noreg, mem);
}
else
else
store = new_rd_ia32_vfst(dbg, irg, block, ptr, noreg, nomem, val, mode);
} else if (get_mode_size_bits(mode) == 128) {
- // Spill 128 bit SSE registers
+ /* Spill 128 bit SSE registers */
store = new_rd_ia32_xxStore(dbg, irg, block, ptr, noreg, nomem, val);
} else if (get_mode_size_bits(mode) == 8) {
store = new_rd_ia32_Store8Bit(dbg, irg, block, ptr, noreg, nomem, val);
ir_node *noreg = ia32_new_NoReg_gp(cg);
ir_node *frame = get_irg_frame(irg);
- ir_node *push = new_rd_ia32_Push(dbg, irg, block, frame, noreg, mem, sp, noreg);
+ ir_node *push = new_rd_ia32_Push(dbg, irg, block, frame, noreg, mem, noreg, sp);
set_ia32_frame_ent(push, ent);
set_ia32_use_frame(push);
ir_node *noreg = ia32_new_NoReg_gp(cg);
ir_node *frame = get_irg_frame(irg);
- ir_node *pop = new_rd_ia32_Pop(dbg, irg, block, frame, noreg, new_NoMem(), sp);
+ ir_node *pop = new_rd_ia32_PopMem(dbg, irg, block, frame, noreg, new_NoMem(), sp);
set_ia32_frame_ent(pop, ent);
set_ia32_use_frame(pop);
}
/**
- * Transform memperm, currently we do this the ugly way and produce
+ * Transform MemPerm, currently we do this the ugly way and produce
* push/pop into/from memory cascades. This is possible without using
* any registers.
*/
arity = be_get_MemPerm_entity_arity(node);
pops = alloca(arity * sizeof(pops[0]));
- // create pushs
+ /* create Pushs */
for(i = 0; i < arity; ++i) {
ir_entity *inent = be_get_MemPerm_in_entity(node, i);
ir_entity *outent = be_get_MemPerm_out_entity(node, i);
ir_type *enttype = get_entity_type(inent);
- int entbits = get_type_size_bits(enttype);
- int entbits2 = get_type_size_bits(get_entity_type(outent));
+ unsigned entsize = get_type_size_bytes(enttype);
+ unsigned entsize2 = get_type_size_bytes(get_entity_type(outent));
ir_node *mem = get_irn_n(node, i + 1);
ir_node *push;
/* work around cases where entities have different sizes */
- if(entbits2 < entbits)
- entbits = entbits2;
- assert( (entbits == 32 || entbits == 64) && "spillslot on x86 should be 32 or 64 bit");
+ if(entsize2 < entsize)
+ entsize = entsize2;
+ assert( (entsize == 4 || entsize == 8) && "spillslot on x86 should be 32 or 64 bit");
push = create_push(cg, node, node, sp, mem, inent);
sp = create_spproj(cg, node, push, pn_ia32_Push_stack);
- if(entbits == 64) {
- // add another push after the first one
+ if(entsize == 8) {
+ /* add another push after the first one */
push = create_push(cg, node, node, sp, mem, inent);
add_ia32_am_offs_int(push, 4);
sp = create_spproj(cg, node, push, pn_ia32_Push_stack);
set_irn_n(node, i, new_Bad());
}
- // create pops
+ /* create pops */
for(i = arity - 1; i >= 0; --i) {
ir_entity *inent = be_get_MemPerm_in_entity(node, i);
ir_entity *outent = be_get_MemPerm_out_entity(node, i);
ir_type *enttype = get_entity_type(outent);
- int entbits = get_type_size_bits(enttype);
- int entbits2 = get_type_size_bits(get_entity_type(inent));
+ unsigned entsize = get_type_size_bytes(enttype);
+ unsigned entsize2 = get_type_size_bytes(get_entity_type(inent));
ir_node *pop;
/* work around cases where entities have different sizes */
- if(entbits2 < entbits)
- entbits = entbits2;
- assert( (entbits == 32 || entbits == 64) && "spillslot on x86 should be 32 or 64 bit");
+ if(entsize2 < entsize)
+ entsize = entsize2;
+ assert( (entsize == 4 || entsize == 8) && "spillslot on x86 should be 32 or 64 bit");
pop = create_pop(cg, node, node, sp, outent);
sp = create_spproj(cg, node, pop, pn_ia32_Pop_stack);
- if(entbits == 64) {
+ if(entsize == 8) {
add_ia32_am_offs_int(pop, 4);
- // add another pop after the first one
+ /* add another pop after the first one */
pop = create_pop(cg, node, node, sp, outent);
sp = create_spproj(cg, node, pop, pn_ia32_Pop_stack);
}
keep = be_new_Keep(&ia32_reg_classes[CLASS_ia32_gp], irg, block, 1, in);
sched_add_before(node, keep);
- // exchange memprojs
+ /* exchange memprojs */
foreach_out_edge_safe(node, edge, next) {
ir_node *proj = get_edge_src_irn(edge);
int p = get_Proj_proj(proj);
set_Proj_proj(proj, pn_ia32_Pop_M);
}
- // remove memperm
+ /* remove memperm */
arity = get_irn_arity(node);
for(i = 0; i < arity; ++i) {
set_irn_n(node, i, new_Bad());
transform_to_Load(cg, node);
} else if (be_is_Spill(node)) {
transform_to_Store(cg, node);
- } else if(be_is_MemPerm(node)) {
+ } else if (be_is_MemPerm(node)) {
transform_MemPerm(cg, node);
}
}
is_ia32_xStoreSimple(node) ||
is_ia32_vfst(node) ||
is_ia32_vfist(node) ||
+ is_ia32_vfisttp(node) ||
is_ia32_FnstCW(node));
#endif
}
free(cg);
}
+/**
+ * Returns the node representing the PIC base.
+ */
+static ir_node *ia32_get_pic_base(void *self) {
+ ir_node *block;
+ ia32_code_gen_t *cg = self;
+ ir_node *get_eip = cg->get_eip;
+ if (get_eip != NULL)
+ return get_eip;
+
+ block = get_irg_start_block(cg->irg);
+ get_eip = new_rd_ia32_GetEIP(NULL, cg->irg, block);
+ cg->get_eip = get_eip;
+
+ add_irn_dep(get_eip, get_irg_frame(cg->irg));
+
+ return get_eip;
+}
+
static void *ia32_cg_init(be_irg_t *birg);
static const arch_code_generator_if_t ia32_code_gen_if = {
ia32_cg_init,
+ ia32_get_pic_base, /* return node used as base in pic code addresses */
ia32_before_abi, /* before abi introduce hook */
ia32_prepare_graph,
NULL, /* spill */
* Initializes a IA32 code generator.
*/
static void *ia32_cg_init(be_irg_t *birg) {
- ia32_isa_t *isa = (ia32_isa_t *)birg->main_env->arch_env->isa;
+ ia32_isa_t *isa = (ia32_isa_t *)birg->main_env->arch_env.isa;
ia32_code_gen_t *cg = xcalloc(1, sizeof(*cg));
cg->impl = &ia32_code_gen_if;
cg->irg = birg->irg;
cg->reg_set = new_set(ia32_cmp_irn_reg_assoc, 1024);
- cg->arch_env = birg->main_env->arch_env;
+ cg->arch_env = &birg->main_env->arch_env;
cg->isa = isa;
cg->birg = birg;
cg->blk_sched = NULL;
cg->dump = (birg->main_env->options->dump_flags & DUMP_BE) ? 1 : 0;
+ cg->gprof = (birg->main_env->options->gprof) ? 1 : 0;
+
+ if (cg->gprof) {
+ /* Linux gprof implementation needs base pointer */
+ birg->main_env->options->omit_fp = 0;
+ }
/* enter it */
isa->cg = cg;
&ia32_gp_regs[REG_ESP], /* stack pointer register */
&ia32_gp_regs[REG_EBP], /* base pointer register */
-1, /* stack direction */
+ 16, /* stack alignment */
NULL, /* main environment */
7, /* costs for a spill instruction */
5, /* costs for a reload instruction */
}
-static const void *ia32_get_irn_ops(const arch_irn_handler_t *self,
- const ir_node *irn)
+static const void *ia32_get_irn_ops(const ir_node *irn)
{
- (void) self;
(void) irn;
return &ia32_irn_ops;
}
-const arch_irn_handler_t ia32_irn_handler = {
- ia32_get_irn_ops
-};
-
-const arch_irn_handler_t *ia32_get_irn_handler(const void *self)
+arch_get_irn_ops_t *ia32_get_irn_handler(const void *self)
{
(void) self;
- return &ia32_irn_handler;
+ return &ia32_get_irn_ops;
}
int ia32_to_appear_in_schedule(void *block_env, const ir_node *irn)
*/
static int ia32_is_psi_allowed(ir_node *sel, ir_node *phi_list, int i, int j)
{
- ir_node *phi;
-
- (void)sel;
- (void)i;
- (void)j;
+ ir_node *phi, *left;
+ ir_node *cmp = NULL;
+ ir_mode *cmp_mode;
+
+ if (ia32_cg_config.use_cmov) {
+ /* we can't handle psis with 64bit compares yet */
+ if (is_Proj(sel)) {
+ cmp = get_Proj_pred(sel);
+ if (is_Cmp(cmp)) {
+ left = get_Cmp_left(cmp);
+ cmp_mode = get_irn_mode(left);
+ if (!mode_is_float(cmp_mode) && get_mode_size_bits(cmp_mode) > 32)
+ return 0;
+ } else {
+ cmp = NULL;
+ }
+ }
- if(!ia32_cg_config.use_cmov) {
- /* TODO: we could still handle abs(x)... */
- return 0;
- }
+ if (ia32_cg_config.use_sse2 && cmp != NULL) {
+ pn_Cmp pn = get_Proj_proj(sel);
+ ir_node *cl = get_Cmp_left(cmp);
+ ir_node *cr = get_Cmp_right(cmp);
+
+ /* check the Phi nodes: no 64bit and no floating point cmov */
+ for (phi = phi_list; phi; phi = get_irn_link(phi)) {
+ ir_mode *mode = get_irn_mode(phi);
+
+ if (mode_is_float(mode)) {
+ /* check for Min, Max */
+ ir_node *t = get_Phi_pred(phi, i);
+ ir_node *f = get_Phi_pred(phi, j);
+ int res = 0;
+
+ /* SSE2 supports Min & Max */
+ if (pn == pn_Cmp_Lt || pn == pn_Cmp_Le || pn == pn_Cmp_Ge || pn == pn_Cmp_Gt) {
+ if (cl == t && cr == f) {
+ /* Psi(a <=/>= b, a, b) => MIN, MAX */
+ res = 1;
+ } else if (cl == f && cr == t) {
+ /* Psi(a <=/>= b, b, a) => MAX, MIN */
+ res = 1;
+ }
+ }
+ if (! res)
+ return 0;
+
+ } else if (get_mode_size_bits(mode) > 32)
+ return 0;
+ }
+ } else {
+ /* check the Phi nodes: no 64bit and no floating point cmov */
+ for (phi = phi_list; phi; phi = get_irn_link(phi)) {
+ ir_mode *mode = get_irn_mode(phi);
- /* we can't handle psis with 64bit compares yet */
- if(is_Proj(sel)) {
- ir_node *pred = get_Proj_pred(sel);
- if(is_Cmp(pred)) {
- ir_node *left = get_Cmp_left(pred);
- ir_mode *cmp_mode = get_irn_mode(left);
- if(!mode_is_float(cmp_mode) && get_mode_size_bits(cmp_mode) > 32)
- return 0;
+ if (mode_is_float(mode) || get_mode_size_bits(mode) > 32)
+ return 0;
+ }
}
- }
- /* check the Phi nodes */
- for (phi = phi_list; phi; phi = get_irn_link(phi)) {
- ir_mode *mode = get_irn_mode(phi);
+ return 1;
+ } else {
+ ir_node *cl, *cr;
+ pn_Cmp pn;
- if (mode_is_float(mode) || get_mode_size_bits(mode) > 32)
+ /* No cmov, only some special cases */
+ if (! is_Proj(sel))
+ return 0;
+ cmp = get_Proj_pred(sel);
+ if (! is_Cmp(cmp))
return 0;
- }
- return 1;
+ left = get_Cmp_left(cmp);
+ cmp_mode = get_irn_mode(left);
+
+ /* Now some supported cases here */
+ pn = get_Proj_proj(sel);
+ cl = get_Cmp_left(cmp);
+ cr = get_Cmp_right(cmp);
+
+ for (phi = phi_list; phi; phi = get_irn_link(phi)) {
+ ir_mode *mode = get_irn_mode(phi);
+ int res = 0;
+ ir_node *t, *f;
+
+ t = get_Phi_pred(phi, i);
+ f = get_Phi_pred(phi, j);
+
+ /* no floating point and no 64bit yet */
+ if (mode_is_float(mode) || get_mode_size_bits(mode) > 32)
+ return 0;
+
+ if (is_Const(t) && is_Const(f)) {
+ if ((is_Const_null(t) && is_Const_one(f)) || (is_Const_one(t) && is_Const_null(f))) {
+ /* always support Psi(x, C1, C2) */
+ res = 1;
+ }
+ } else if (pn == pn_Cmp_Lt || pn == pn_Cmp_Le || pn == pn_Cmp_Ge || pn == pn_Cmp_Gt) {
+ if (0) {
+#if 0
+ } else if (cl == t && cr == f) {
+ /* Psi(a <=/>= b, a, b) => Min, Max */
+ res = 1;
+ } else if (cl == f && cr == t) {
+ /* Psi(a <=/>= b, b, a) => Max, Min */
+ res = 1;
+#endif
+ } else if ((pn & pn_Cmp_Gt) && !mode_is_signed(mode) &&
+ is_Const(f) && is_Const_null(f) && is_Sub(t) &&
+ get_Sub_left(t) == cl && get_Sub_right(t) == cr) {
+ /* Psi(a >=u b, a - b, 0) unsigned Doz */
+ res = 1;
+ } else if ((pn & pn_Cmp_Lt) && !mode_is_signed(mode) &&
+ is_Const(t) && is_Const_null(t) && is_Sub(f) &&
+ get_Sub_left(f) == cl && get_Sub_right(f) == cr) {
+ /* Psi(a <=u b, 0, a - b) unsigned Doz */
+ res = 1;
+ } else if (is_Const(cr) && is_Const_null(cr)) {
+ if (cl == t && is_Minus(f) && get_Minus_op(f) == cl) {
+ /* Psi(a <=/>= 0 ? a : -a) Nabs/Abs */
+ res = 1;
+ } else if (cl == f && is_Minus(t) && get_Minus_op(t) == cl) {
+ /* Psi(a <=/>= 0 ? -a : a) Abs/Nabs */
+ res = 1;
+ }
+ }
+ }
+ if (! res)
+ return 0;
+ }
+ /* all checks passed */
+ return 1;
+ }
+ return 0;
}
/**
}
static const lc_opt_enum_int_items_t gas_items[] = {
- { "normal", GAS_FLAVOUR_NORMAL },
+ { "elf", GAS_FLAVOUR_ELF },
{ "mingw", GAS_FLAVOUR_MINGW },
+ { "yasm", GAS_FLAVOUR_YASM },
+ { "macho", GAS_FLAVOUR_MACH_O },
{ NULL, 0 }
};
static const lc_opt_table_entry_t ia32_options[] = {
LC_OPT_ENT_ENUM_INT("gasmode", "set the GAS compatibility mode", &gas_var),
+ LC_OPT_ENT_INT("stackalign", "set stack alignment for calls",
+ &ia32_isa_template.arch_isa.stack_alignment),
LC_OPT_LAST
};