#include "irprintf.h"
#include "iredges_t.h"
#include "ircons.h"
+#include "irflag.h"
#include "irgmod.h"
#include "irgopt.h"
#include "irbitset.h"
#include "irgopt.h"
-#include "irdump_grgen.h"
#include "pdeq.h"
#include "pset.h"
#include "debug.h"
#include "ia32_new_nodes.h"
#include "gen_ia32_regalloc_if.h"
#include "gen_ia32_machine.h"
+#include "ia32_common_transform.h"
#include "ia32_transform.h"
#include "ia32_emitter.h"
#include "ia32_map_regs.h"
if (env->flags.try_omit_fp) {
/* simply remove the stack frame here */
curr_sp = be_new_IncSP(arch_env->sp, irg, bl, curr_sp, BE_STACK_FRAME_SIZE_SHRINK, 0);
- add_irn_dep(curr_sp, *mem);
} else {
ir_mode *mode_bp = arch_env->bp->reg_class->mode;
/* the old SP is not needed anymore (kill the proj) */
assert(is_Proj(curr_sp));
- be_kill_node(curr_sp);
+ kill_node(curr_sp);
/* copy ebp to esp */
curr_sp = be_new_Copy(&ia32_reg_classes[CLASS_ia32_gp], irg, bl, curr_bp);
(we assume they are in cache), other memory operations cost 20
cycles.
*/
- if(is_ia32_use_frame(irn) ||
- (is_ia32_NoReg_GP(get_irn_n(irn, 0)) &&
- is_ia32_NoReg_GP(get_irn_n(irn, 1)))) {
+ if (is_ia32_use_frame(irn) || (
+ is_ia32_NoReg_GP(get_irn_n(irn, n_ia32_base)) &&
+ is_ia32_NoReg_GP(get_irn_n(irn, n_ia32_index))
+ )) {
cost += 5;
} else {
cost += 20;
static void ia32_perform_memory_operand(ir_node *irn, ir_node *spill,
unsigned int i)
{
+ ir_mode *load_mode;
+ ir_mode *dest_op_mode;
+
ia32_code_gen_t *cg = ia32_current_cg;
assert(ia32_possible_memory_operand(irn, i) && "Cannot perform memory operand change");
}
set_ia32_op_type(irn, ia32_AddrModeS);
- set_ia32_ls_mode(irn, get_irn_mode(get_irn_n(irn, i)));
+
+ load_mode = get_irn_mode(get_irn_n(irn, i));
+ dest_op_mode = get_ia32_ls_mode(irn);
+ if (get_mode_size_bits(load_mode) <= get_mode_size_bits(dest_op_mode)) {
+ set_ia32_ls_mode(irn, load_mode);
+ }
set_ia32_use_frame(irn);
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_mem, spill);
+ set_ia32_is_reload(irn);
/* immediates are only allowed on the right side */
if (i == n_ia32_binary_left && is_ia32_Immediate(get_irn_n(irn, n_ia32_binary_left))) {
}
}
+transformer_t be_transformer = TRANSFORMER_DEFAULT;
+
/**
* Transforms the standard firm graph into
* an ia32 firm graph
static void ia32_prepare_graph(void *self) {
ia32_code_gen_t *cg = self;
- /* do local optimisations */
+ /* do local optimizations */
optimize_graph_df(cg->irg);
/* TODO: we often have dead code reachable through out-edges here. So for
if (cg->dump)
be_dump(cg->irg, "-pre_transform", dump_ir_block_graph_sched);
+ switch (be_transformer) {
+ case TRANSFORMER_DEFAULT:
+ /* transform remaining nodes into assembler instructions */
+ ia32_transform_graph(cg);
+ break;
+
#ifdef FIRM_GRGEN_BE
- /* transform nodes into assembler instructions by PBQP magic */
- ia32_transform_graph_by_pbqp(cg);
-#endif
+ case TRANSFORMER_PBQP:
+ // disable CSE, because of two-step node-construction
+ set_opt_cse(0);
- if (cg->dump)
- be_dump(cg->irg, "-after_pbqp_transform", dump_ir_block_graph_sched);
+ /* transform nodes into assembler instructions by PBQP magic */
+ ia32_transform_graph_by_pbqp(cg);
+
+ if (cg->dump)
+ be_dump(cg->irg, "-after_pbqp_transform", dump_ir_block_graph_sched);
+ set_opt_cse(1);
+ break;
+#endif
- /* transform remaining nodes into assembler instructions */
- ia32_transform_graph(cg);
+ default: panic("invalid transformer");
+ }
- /* do local optimisations (mainly CSE) */
+ /* do local optimizations (mainly CSE) */
optimize_graph_df(cg->irg);
if (cg->dump)
if (is_ia32_need_stackent(node) || is_ia32_Load(node)) {
const ir_mode *mode = get_ia32_ls_mode(node);
const ia32_attr_t *attr = get_ia32_attr_const(node);
- int align = get_mode_size_bytes(mode);
+ int align;
+
+ if (is_ia32_is_reload(node)) {
+ mode = get_spill_mode_mode(mode);
+ }
if(attr->data.need_64bit_stackent) {
mode = mode_Ls;
if(attr->data.need_32bit_stackent) {
mode = mode_Is;
}
+ align = get_mode_size_bytes(mode);
be_node_needs_frame_entity(env, node, mode, align);
} else if (is_ia32_vfild(node) || is_ia32_xLoad(node)
|| is_ia32_vfld(node)) {
#endif
};
+static void init_asm_constraints(void)
+{
+ be_init_default_asm_constraint_flags();
+
+ asm_constraint_flags['a'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['b'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['c'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['d'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['D'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['S'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['Q'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['q'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['A'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['l'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['R'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['r'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['p'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['f'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['t'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['u'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['Y'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['X'] = ASM_CONSTRAINT_FLAG_SUPPORTS_REGISTER;
+ asm_constraint_flags['n'] = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
+ asm_constraint_flags['g'] = ASM_CONSTRAINT_FLAG_SUPPORTS_IMMEDIATE;
+
+ /* no support for autodecrement/autoincrement */
+ asm_constraint_flags['<'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+ asm_constraint_flags['>'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+ /* no float consts */
+ asm_constraint_flags['E'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+ asm_constraint_flags['F'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+ /* makes no sense on x86 */
+ asm_constraint_flags['s'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+ /* no support for sse consts yet */
+ asm_constraint_flags['C'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+ /* no support for x87 consts yet */
+ asm_constraint_flags['G'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+ /* no support for mmx registers yet */
+ asm_constraint_flags['y'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+ /* not available in 32bit mode */
+ asm_constraint_flags['Z'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+ asm_constraint_flags['e'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+
+ /* no code yet to determine register class needed... */
+ asm_constraint_flags['X'] = ASM_CONSTRAINT_FLAG_NO_SUPPORT;
+}
+
/**
* Initializes the backend ISA.
*/
static arch_env_t *ia32_init(FILE *file_handle) {
static int inited = 0;
ia32_isa_t *isa;
+ int i, n;
if (inited)
return NULL;
intrinsic_env.isa = isa;
ia32_handle_intrinsics();
+ /* emit asm includes */
+ n = get_irp_n_asms();
+ for (i = 0; i < n; ++i) {
+ be_emit_cstring("#APP\n");
+ be_emit_ident(get_irp_asm(i));
+ be_emit_cstring("\n#NO_APP\n");
+ }
+
/* needed for the debug support */
be_gas_emit_switch_section(GAS_SECTION_TEXT);
be_emit_cstring(".Ltext0:\n");
ir_mode *mode;
unsigned cc;
int n, i, regnum;
+ int pop_amount = 0;
be_abi_call_flags_t call_flags = be_abi_call_get_flags(abi);
+
(void) self;
/* set abi flags for calls */
call_flags.bits.store_args_sequential = 0;
/* call_flags.bits.try_omit_fp not changed: can handle both settings */
call_flags.bits.fp_free = 0; /* the frame pointer is fixed in IA32 */
- call_flags.bits.call_has_imm = 1; /* IA32 calls can have immediate address */
+ call_flags.bits.call_has_imm = 1; /* No call immediates, we handle this by ourselves */
/* set parameter passing style */
be_abi_call_set_flags(abi, call_flags, &ia32_abi_callbacks);
cc = cc_cdecl_set;
} else {
cc = get_method_calling_convention(method_type);
- if (get_method_additional_properties(method_type) & mtp_property_private
- && (ia32_cg_config.optimize_cc)) {
+ if (get_method_additional_properties(method_type) & mtp_property_private &&
+ ia32_cg_config.optimize_cc) {
/* set the calling conventions to register parameter */
cc = (cc & ~cc_bits) | cc_reg_param;
}
/* we have to pop the shadow parameter ourself for compound calls */
if( (get_method_calling_convention(method_type) & cc_compound_ret)
&& !(cc & cc_reg_param)) {
- be_abi_call_set_pop(abi, get_mode_size_bytes(mode_P_data));
+ pop_amount += get_mode_size_bytes(mode_P_data);
}
n = get_method_n_params(method_type);
/* Micro optimisation: if the mode is shorter than 4 bytes, load 4 bytes.
* movl has a shorter opcode than mov[sz][bw]l */
ir_mode *load_mode = mode;
- if (mode != NULL && get_mode_size_bytes(mode) < 4) load_mode = mode_Iu;
+
+ if (mode != NULL) {
+ unsigned size = get_mode_size_bytes(mode);
+
+ if (cc & cc_callee_clear_stk) {
+ pop_amount += (size + 3U) & ~3U;
+ }
+
+ if (size < 4) load_mode = mode_Iu;
+ }
+
be_abi_call_param_stack(abi, i, load_mode, 4, 0, 0);
}
}
+ be_abi_call_set_pop(abi, pop_amount);
+
/* set return registers */
n = get_method_n_ress(method_type);
return 0;
}
+static asm_constraint_flags_t ia32_parse_asm_constraint(const void *self, const char **c)
+{
+ (void) self;
+ (void) c;
+
+ /* we already added all our simple flags to the flags modifier list in
+ * init, so this flag we don't know. */
+ return ASM_CONSTRAINT_FLAG_INVALID;
+}
+
+static int ia32_is_valid_clobber(const void *self, const char *clobber)
+{
+ (void) self;
+
+ return ia32_get_clobber_register(clobber) != NULL;
+}
+
/**
* Returns the libFirm configuration parameter for this backend.
*/
ia32_setup_cg_config();
+ /* doesn't really belong here, but this is the earliest place the backend
+ * is called... */
+ init_asm_constraints();
+
p.dep_param = &ad;
p.if_conv_info = &ifconv;
return &p;
(int*) &be_gas_flavour, gas_items
};
+static const lc_opt_enum_int_items_t transformer_items[] = {
+ { "default", TRANSFORMER_DEFAULT },
+#ifdef FIRM_GRGEN_BE
+ { "pbqp", TRANSFORMER_PBQP },
+#endif
+ { NULL, 0 }
+};
+
+static lc_opt_enum_int_var_t transformer_var = {
+ (int*)&be_transformer, transformer_items
+};
+
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_ENUM_INT("transformer", "the transformer used for code selection", &transformer_var),
LC_OPT_ENT_INT("stackalign", "set power of two stack alignment for calls",
&ia32_isa_template.arch_env.stack_alignment),
LC_OPT_LAST
ia32_get_allowed_execution_units,
ia32_get_machine,
ia32_get_irg_list,
+ ia32_parse_asm_constraint,
+ ia32_is_valid_clobber
};
void ia32_init_emitter(void);