#include "irtools.h"
#include "irdump.h"
#include "lowering.h"
+#include "lower_dw.h"
#include "bitset.h"
#include "debug.h"
/* fill register allocator interface */
-static const arch_irn_ops_t sparc_irn_ops = {
+const arch_irn_ops_t sparc_irn_ops = {
sparc_classify,
sparc_get_frame_entity,
sparc_set_frame_offset,
NULL, /* find pointer type */
NULL, /* ret_compound_in_regs */
};
-
lower_calls_with_compounds(¶ms);
+ sparc_lower_64bit();
+
for (i = 0; i < n_irgs; ++i) {
ir_graph *irg = get_irp_irg(i);
ir_lower_mode_b(irg, &lower_mode_b_config);
ir_mode *mode; /**< The mode of the irn */
};
+extern const arch_irn_ops_t sparc_irn_ops;
+
/**
* SPARC ABI requires some space which is always available at the top of
* the stack. It contains:
void sparc_introduce_prolog_epilog(ir_graph *irg);
+void sparc_lower_64bit(void);
+
#endif
*/
void sparc_emit_reg_or_imm(const ir_node *node, int pos)
{
- if (get_irn_arity(node) > pos) {
- // we have reg input
- sparc_emit_source_register(node, pos);
- } else {
+ if (arch_irn_get_flags(node) & ((arch_irn_flags_t)sparc_arch_irn_flag_immediate_form)) {
// we have a imm input
sparc_emit_immediate(node);
+ } else {
+ // we have reg input
+ sparc_emit_source_register(node, pos);
}
}
--- /dev/null
+/*
+ * Copyright (C) 1995-2010 University of Karlsruhe. All right reserved.
+ *
+ * This file is part of libFirm.
+ *
+ * This file may be distributed and/or modified under the terms of the
+ * GNU General Public License version 2 as published by the Free Software
+ * Foundation and appearing in the file LICENSE.GPL included in the
+ * packaging of this file.
+ *
+ * Licensees holding valid libFirm Professional Edition licenses may use
+ * this file in accordance with the libFirm Commercial License.
+ * Agreement provided with the Software.
+ *
+ * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+/**
+ * @file
+ * @brief Sparc 64bit lowering
+ * @author Matthias Braun
+ */
+#include "config.h"
+
+#include "bearch_sparc_t.h"
+#include "gen_sparc_new_nodes.h"
+#include "lower_dw.h"
+#include "ircons_t.h"
+#include "util.h"
+
+static void lower64_add(ir_node *node, ir_mode *mode)
+{
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_node *block = get_nodes_block(node);
+ ir_node *left = get_Add_left(node);
+ ir_node *right = get_Add_right(node);
+ ir_node *left_low = get_lowered_low(left);
+ ir_node *left_high = get_lowered_high(left);
+ ir_node *right_low = get_lowered_low(right);
+ ir_node *right_high = get_lowered_high(right);
+ ir_node *addcc = new_bd_sparc_AddCC_t(dbgi, block, left_low,
+ right_low);
+ ir_node *res_low = new_r_Proj(addcc, mode_Iu, pn_sparc_AddCC_t_res);
+ ir_node *res_flags = new_r_Proj(addcc, mode_ANY, pn_sparc_AddCC_t_flags);
+ ir_node *addx = new_bd_sparc_AddX_t(dbgi, block, left_high,
+ right_high, res_flags, mode);
+ ir_set_dw_lowered(node, res_low, addx);
+}
+
+static void lower64_sub(ir_node *node, ir_mode *mode)
+{
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_node *block = get_nodes_block(node);
+ ir_node *left = get_Sub_left(node);
+ ir_node *right = get_Sub_right(node);
+ ir_node *left_low = get_lowered_low(left);
+ ir_node *left_high = get_lowered_high(left);
+ ir_node *right_low = get_lowered_low(right);
+ ir_node *right_high = get_lowered_high(right);
+ ir_node *subcc = new_bd_sparc_SubCC_t(dbgi, block, left_low,
+ right_low);
+ ir_node *res_low = new_r_Proj(subcc, mode_Iu, pn_sparc_SubCC_t_res);
+ ir_node *res_flags = new_r_Proj(subcc, mode_ANY, pn_sparc_SubCC_t_flags);
+ ir_node *subx = new_bd_sparc_SubX_t(dbgi, block, left_high,
+ right_high, res_flags, mode);
+ ir_set_dw_lowered(node, res_low, subx);
+}
+
+static void lower64_minus(ir_node *node, ir_mode *mode)
+{
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_graph *irg = get_irn_irg(node);
+ ir_node *block = get_nodes_block(node);
+ ir_node *op = get_Minus_op(node);
+ ir_node *right_low = get_lowered_low(op);
+ ir_node *right_high = get_lowered_high(op);
+ ir_mode *low_unsigned = get_irn_mode(right_low);
+ ir_node *left_low = new_r_Const(irg, get_mode_null(low_unsigned));
+ ir_node *left_high = new_r_Const(irg, get_mode_null(mode));
+ ir_node *subcc = new_bd_sparc_SubCC_t(dbgi, block, left_low,
+ right_low);
+ ir_node *res_low = new_r_Proj(subcc, mode_Iu, pn_sparc_SubCC_t_res);
+ ir_node *res_flags = new_r_Proj(subcc, mode_ANY, pn_sparc_SubCC_t_flags);
+ ir_node *subx = new_bd_sparc_SubX_t(dbgi, block, left_high,
+ right_high, res_flags, mode);
+ ir_set_dw_lowered(node, res_low, subx);
+}
+
+static ir_entity *create_64_intrinsic_fkt(ir_type *method, const ir_op *op,
+ const ir_mode *imode,
+ const ir_mode *omode, void *context)
+{
+ ir_type *glob = get_glob_type();
+ const char *name;
+ ident *id;
+ ir_entity *result;
+ (void) context;
+ (void) omode;
+
+ if (op == op_Mul) {
+ name = "__muldi3";
+ } else if (op == op_Div) {
+ name = mode_is_signed(imode) ? "__divdi3" : "__udivdi3";
+ } else if (op == op_Mod) {
+ name = mode_is_signed(imode) ? "__moddi3" : "__umoddi3";
+ } else {
+ panic("Can't lower unexpected 64bit operation %s", get_op_name(op));
+ }
+ id = new_id_from_str(name);
+ result = new_entity(glob, id, method);
+ set_entity_ld_ident(result, id);
+ set_entity_visibility(result, ir_visibility_external);
+ return result;
+}
+
+void sparc_lower_64bit(void)
+{
+ lwrdw_param_t lower_dw_params = {
+ 0, /* big endian */
+ 64, /* doubleword size */
+ create_64_intrinsic_fkt,
+ NULL
+ };
+
+ /* make sure opcodes are initialized */
+ sparc_create_opcodes(&sparc_irn_ops);
+
+ ir_prepare_dw_lowering(&lower_dw_params);
+ ir_register_dw_lower_function(op_Add, lower64_add);
+ ir_register_dw_lower_function(op_Minus, lower64_minus);
+ ir_register_dw_lower_function(op_Sub, lower64_sub);
+ ir_lower_dw_ops();
+}
break;
case dump_node_info_txt:
+ if (is_sparc_AddX_t(n) || is_sparc_AddCC_t(n))
+ break;
+
arch_dump_reqs_and_registers(F, n);
attr = get_sparc_attr_const(n);
if (attr->immediate_value_entity) {
sparc_attr_t *attr = (sparc_attr_t*)get_irn_generic_attr(res);
attr->immediate_value_entity = entity;
attr->immediate_value = immediate_value;
+ arch_irn_add_flags(res, (arch_irn_flags_t)sparc_arch_irn_flag_immediate_form);
}
static void init_sparc_jmp_cond_attr(ir_node *node, ir_relation relation,
sparc_arch_irn_flag_modifies_flags = arch_irn_flags_backend << 0,
sparc_arch_irn_flag_modifies_fp_flags = arch_irn_flags_backend << 1,
sparc_arch_irn_flag_needs_64bit_spillslot = arch_irn_flags_backend << 2,
+ sparc_arch_irn_flag_immediate_form = arch_irn_flags_backend << 3,
};
/**
},
);
+my %binopcc_operand_constructors = (
+ imm => {
+ attr => "ir_entity *immediate_entity, int32_t immediate_value",
+ custominit => "sparc_set_attr_imm(res, immediate_entity, immediate_value);",
+ reg_req => { in => [ "gp" ], out => [ "gp", "flags" ] },
+ ins => [ "left" ],
+ },
+ reg => {
+ reg_req => { in => [ "gp", "gp" ], out => [ "gp", "flags" ] },
+ ins => [ "left", "right" ],
+ },
+);
+
+my %binopx_operand_constructors = (
+ imm => {
+ attr => "ir_entity *immediate_entity, int32_t immediate_value",
+ custominit => "sparc_set_attr_imm(res, immediate_entity, immediate_value);",
+ reg_req => { in => [ "gp", "flags" ], out => [ "gp" ] },
+ ins => [ "left", "carry" ],
+ },
+ reg => {
+ reg_req => { in => [ "gp", "gp", "flags" ], out => [ "gp" ] },
+ ins => [ "left", "right", "carry" ],
+ },
+);
+
+
my %binopcczero_operand_constructors = (
imm => {
attr => "ir_entity *immediate_entity, int32_t immediate_value",
constructors => \%binop_operand_constructors,
},
+AddCC => {
+ irn_flags => [ "rematerializable" ],
+ emit => '. addcc %S0, %R1I, %D0',
+ outs => [ "res", "flags" ],
+ constructors => \%binopcc_operand_constructors,
+},
+
+AddX => {
+ # At the moment not rematerializable because of assert in beflags.c/
+ # (it claims that spiller can't rematerialize flag stuff correctly)
+ #irn_flags => [ "rematerializable" ],
+ emit => '. addx %S0, %R1I, %D0',
+ constructors => \%binopx_operand_constructors,
+ mode => $mode_gp,
+},
+
+AddCC_t => {
+ ins => [ "left", "right" ],
+ outs => [ "res", "flags" ],
+ attr_type => "",
+},
+
+AddX_t => {
+ ins => [ "left", "right", "flags_input" ],
+ attr_type => "",
+},
+
Sub => {
irn_flags => [ "rematerializable" ],
mode => $mode_gp,
constructors => \%binop_operand_constructors,
},
+SubCC => {
+ irn_flags => [ "rematerializable" ],
+ emit => '. subcc %S0, %R1I, %D0',
+ outs => [ "res", "flags" ],
+ constructors => \%binopcc_operand_constructors,
+},
+
+SubX => {
+ # Not rematerializable (see AddX)
+ emit => '. subx %S0, %R1I, %D0',
+ constructors => \%binopx_operand_constructors,
+ mode => $mode_gp,
+},
+
+SubCC_t => {
+ ins => [ "left", "right" ],
+ outs => [ "res", "flags" ],
+ attr_type => "",
+},
+
+SubX_t => {
+ ins => [ "left", "right", "flags_input" ],
+ attr_type => "",
+},
+
# Load / Store
Ld => {
op_flags => [ "labeled", "fragile" ],
static const arch_register_t *fp_reg = &sparc_registers[REG_FRAME_POINTER];
static calling_convention_t *cconv = NULL;
static ir_mode *mode_gp;
+static ir_mode *mode_flags;
static ir_mode *mode_fp;
static ir_mode *mode_fp2;
//static ir_mode *mode_fp4;
panic("unsupported mode %+F for float op", mode);
}
+typedef ir_node* (*new_binopx_imm_func)(dbg_info *dbgi, ir_node *block,
+ ir_node *op1, ir_node *flags,
+ ir_entity *imm_entity, int32_t imm);
+
+typedef ir_node* (*new_binopx_reg_func)(dbg_info *dbgi, ir_node *block,
+ ir_node *op1, ir_node *op2,
+ ir_node *flags);
+
+static ir_node *gen_helper_binopx(ir_node *node, match_flags_t match_flags,
+ new_binopx_reg_func new_binopx_reg,
+ new_binopx_imm_func new_binopx_imm)
+{
+ dbg_info *dbgi = get_irn_dbg_info(node);
+ ir_node *block = be_transform_node(get_nodes_block(node));
+ ir_node *op1 = get_irn_n(node, 0);
+ ir_node *op2 = get_irn_n(node, 1);
+ ir_node *flags = get_irn_n(node, 2);
+ ir_node *new_flags = be_transform_node(flags);
+ ir_node *new_op1;
+ ir_node *new_op2;
+
+ /* only support for mode-neutral implemented so far */
+ assert(match_flags & MATCH_MODE_NEUTRAL);
+
+ if (is_imm_encodeable(op2)) {
+ ir_node *new_op1 = be_transform_node(op1);
+ int32_t immediate = get_tarval_long(get_Const_tarval(op2));
+ return new_binopx_imm(dbgi, block, new_op1, new_flags, NULL, immediate);
+ }
+ new_op2 = be_transform_node(op2);
+ if ((match_flags & MATCH_COMMUTATIVE) && is_imm_encodeable(op1)) {
+ int32_t immediate = get_tarval_long(get_Const_tarval(op1));
+ return new_binopx_imm(dbgi, block, new_op2, new_flags, NULL, immediate);
+ }
+ new_op1 = be_transform_node(op1);
+ return new_binopx_reg(dbgi, block, new_op1, new_op2, new_flags);
+
+}
+
static ir_node *get_g0(void)
{
return be_prolog_get_reg_value(abihelper, &sparc_registers[REG_G0]);
new_bd_sparc_Add_reg, new_bd_sparc_Add_imm);
}
+static ir_node *gen_AddCC_t(ir_node *node)
+{
+ return gen_helper_binop(node, MATCH_COMMUTATIVE | MATCH_MODE_NEUTRAL,
+ new_bd_sparc_AddCC_reg, new_bd_sparc_AddCC_imm);
+}
+
+static ir_node *gen_Proj_AddCC_t(ir_node *node)
+{
+ long pn = get_Proj_proj(node);
+ ir_node *pred = get_Proj_pred(node);
+ ir_node *new_pred = be_transform_node(pred);
+
+ switch (pn) {
+ case pn_sparc_AddCC_t_res:
+ return new_r_Proj(new_pred, mode_gp, pn_sparc_AddCC_res);
+ case pn_sparc_AddCC_t_flags:
+ return new_r_Proj(new_pred, mode_flags, pn_sparc_AddCC_flags);
+ default:
+ panic("Invalid AddCC_t proj found");
+ }
+}
+
+static ir_node *gen_AddX_t(ir_node *node)
+{
+ return gen_helper_binopx(node, MATCH_COMMUTATIVE | MATCH_MODE_NEUTRAL,
+ new_bd_sparc_AddX_reg, new_bd_sparc_AddX_imm);
+}
+
/**
* Creates an sparc Sub.
*
new_bd_sparc_Sub_reg, new_bd_sparc_Sub_imm);
}
+static ir_node *gen_SubCC_t(ir_node *node)
+{
+ return gen_helper_binop(node, MATCH_MODE_NEUTRAL,
+ new_bd_sparc_SubCC_reg, new_bd_sparc_SubCC_imm);
+}
+
+static ir_node *gen_Proj_SubCC_t(ir_node *node)
+{
+ long pn = get_Proj_proj(node);
+ ir_node *pred = get_Proj_pred(node);
+ ir_node *new_pred = be_transform_node(pred);
+
+ switch (pn) {
+ case pn_sparc_SubCC_t_res:
+ return new_r_Proj(new_pred, mode_gp, pn_sparc_SubCC_res);
+ case pn_sparc_SubCC_t_flags:
+ return new_r_Proj(new_pred, mode_flags, pn_sparc_SubCC_flags);
+ default:
+ panic("Invalid SubCC_t proj found");
+ }
+}
+
+static ir_node *gen_SubX_t(ir_node *node)
+{
+ return gen_helper_binopx(node, MATCH_MODE_NEUTRAL,
+ new_bd_sparc_SubX_reg, new_bd_sparc_SubX_imm);
+}
+
static ir_node *create_ldf(dbg_info *dbgi, ir_node *block, ir_node *ptr,
ir_node *mem, ir_mode *mode, ir_entity *entity,
long offset, bool is_frame_entity)
/* FALLTHROUGH */
}
default:
+ if (is_sparc_AddCC_t(pred)) {
+ return gen_Proj_AddCC_t(node);
+ } else if (is_sparc_SubCC_t(pred)) {
+ return gen_Proj_SubCC_t(node);
+ }
panic("code selection didn't expect Proj after %+F\n", pred);
}
}
be_set_transform_function(op_SymConst, gen_SymConst);
be_set_transform_function(op_Unknown, gen_Unknown);
+ be_set_transform_function(op_sparc_AddX_t, gen_AddX_t);
+ be_set_transform_function(op_sparc_AddCC_t,gen_AddCC_t);
be_set_transform_function(op_sparc_Save, be_duplicate_node);
+ be_set_transform_function(op_sparc_SubX_t, gen_SubX_t);
+ be_set_transform_function(op_sparc_SubCC_t,gen_SubCC_t);
}
/**
node_to_stack = pmap_create();
- mode_gp = mode_Iu;
- mode_fp = mode_F;
- mode_fp2 = mode_D;
+ mode_gp = mode_Iu;
+ mode_fp = mode_F;
+ mode_fp2 = mode_D;
+ mode_flags = mode_Bu;
//mode_fp4 = ?
abihelper = be_abihelper_prepare(irg);
entry->high_word = new_high;
}
+ir_mode *ir_get_low_unsigned_mode(void)
+{
+ return env->low_unsigned;
+}
+
/**
* Translate a Constant: create two.
*/
set_Proj_pred(proj, call);
set_Proj_proj(proj, pn_Call_M);
break;
- case pn_Div_X_except: /* Execution result if exception occurred. */
- /* reroute to the call */
+ case pn_Div_X_regular:
+ set_Proj_pred(proj, call);
+ set_Proj_proj(proj, pn_Call_X_regular);
+ break;
+ case pn_Div_X_except:
set_Proj_pred(proj, call);
set_Proj_proj(proj, pn_Call_X_except);
break;
set_Proj_pred(proj, call);
set_Proj_proj(proj, pn_Call_M);
break;
- case pn_Mod_X_except: /* Execution result if exception occurred. */
- /* reroute to the call */
+ case pn_Div_X_regular:
+ set_Proj_pred(proj, call);
+ set_Proj_proj(proj, pn_Call_X_regular);
+ break;
+ case pn_Mod_X_except:
set_Proj_pred(proj, call);
set_Proj_proj(proj, pn_Call_X_except);
break;
ir_node *not_shiftval = new_rd_Not(dbgi, block_true, right,
low_unsigned);
ir_node *conv = create_conv(block_true, left_low, mode);
- ir_node *one = new_r_Const(irg, get_mode_one(mode));
+ ir_node *one = new_r_Const(irg, get_mode_one(low_unsigned));
ir_node *carry0 = new_rd_Shr(dbgi, block_true, conv, one, mode);
ir_node *carry1 = new_rd_Shr(dbgi, block_true, carry0,
not_shiftval, mode);
return get_node_entry(node)->high_word;
}
+/**
+ * Return the unsigned variant of the lowered mode
+ * Note: you must only call this during a dw_lowering (= in a lowering callback)
+ */
+ir_mode *ir_get_low_unsigned_mode(void);
+
/**
* Default implementation. Context is unused.
*/