From ed0e4ce9a109277e1a63f48f2aca7750f473bc6a Mon Sep 17 00:00:00 2001 From: Matthias Braun Date: Wed, 11 May 2011 14:36:05 +0200 Subject: [PATCH] sparc: implement 64bit lowering --- ir/be/sparc/bearch_sparc.c | 6 +- ir/be/sparc/bearch_sparc_t.h | 4 + ir/be/sparc/sparc_emitter.c | 8 +- ir/be/sparc/sparc_lower64.c | 135 +++++++++++++++++++++++++++++++++ ir/be/sparc/sparc_new_nodes.c | 4 + ir/be/sparc/sparc_nodes_attr.h | 1 + ir/be/sparc/sparc_spec.pl | 79 +++++++++++++++++++ ir/be/sparc/sparc_transform.c | 112 ++++++++++++++++++++++++++- ir/lower/lower_dw.c | 21 +++-- ir/lower/lower_dw.h | 6 ++ 10 files changed, 362 insertions(+), 14 deletions(-) create mode 100644 ir/be/sparc/sparc_lower64.c diff --git a/ir/be/sparc/bearch_sparc.c b/ir/be/sparc/bearch_sparc.c index cdb5877eb..e342111c9 100644 --- a/ir/be/sparc/bearch_sparc.c +++ b/ir/be/sparc/bearch_sparc.c @@ -38,6 +38,7 @@ #include "irtools.h" #include "irdump.h" #include "lowering.h" +#include "lower_dw.h" #include "bitset.h" #include "debug.h" @@ -125,7 +126,7 @@ static int sparc_get_sp_bias(const ir_node *node) /* 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, @@ -555,9 +556,10 @@ static void sparc_lower_for_target(void) 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); diff --git a/ir/be/sparc/bearch_sparc_t.h b/ir/be/sparc/bearch_sparc_t.h index 650ec68cf..6e69d804e 100644 --- a/ir/be/sparc/bearch_sparc_t.h +++ b/ir/be/sparc/bearch_sparc_t.h @@ -50,6 +50,8 @@ struct sparc_transform_env_t { 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: @@ -76,4 +78,6 @@ void sparc_finish(ir_graph *irg); void sparc_introduce_prolog_epilog(ir_graph *irg); +void sparc_lower_64bit(void); + #endif diff --git a/ir/be/sparc/sparc_emitter.c b/ir/be/sparc/sparc_emitter.c index d55c6daa9..d9734a69f 100644 --- a/ir/be/sparc/sparc_emitter.c +++ b/ir/be/sparc/sparc_emitter.c @@ -176,12 +176,12 @@ void sparc_emit_dest_register(const ir_node *node, int pos) */ 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); } } diff --git a/ir/be/sparc/sparc_lower64.c b/ir/be/sparc/sparc_lower64.c new file mode 100644 index 000000000..0e9e5b0c1 --- /dev/null +++ b/ir/be/sparc/sparc_lower64.c @@ -0,0 +1,135 @@ +/* + * 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(); +} diff --git a/ir/be/sparc/sparc_new_nodes.c b/ir/be/sparc/sparc_new_nodes.c index 235d25890..6a5896002 100644 --- a/ir/be/sparc/sparc_new_nodes.c +++ b/ir/be/sparc/sparc_new_nodes.c @@ -93,6 +93,9 @@ static void sparc_dump_node(FILE *F, ir_node *n, dump_reason_t reason) 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) { @@ -141,6 +144,7 @@ static void sparc_set_attr_imm(ir_node *res, ir_entity *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, diff --git a/ir/be/sparc/sparc_nodes_attr.h b/ir/be/sparc/sparc_nodes_attr.h index 02acff260..4a44251d2 100644 --- a/ir/be/sparc/sparc_nodes_attr.h +++ b/ir/be/sparc/sparc_nodes_attr.h @@ -45,6 +45,7 @@ enum sparc_arch_irn_flags_t { 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, }; /** diff --git a/ir/be/sparc/sparc_spec.pl b/ir/be/sparc/sparc_spec.pl index 332c25325..a2d4d1b87 100644 --- a/ir/be/sparc/sparc_spec.pl +++ b/ir/be/sparc/sparc_spec.pl @@ -174,6 +174,33 @@ my %binop_operand_constructors = ( }, ); +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", @@ -237,6 +264,33 @@ Add => { 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, @@ -244,6 +298,31 @@ Sub => { 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" ], diff --git a/ir/be/sparc/sparc_transform.c b/ir/be/sparc/sparc_transform.c index 238d827b6..b83d466a3 100644 --- a/ir/be/sparc/sparc_transform.c +++ b/ir/be/sparc/sparc_transform.c @@ -66,6 +66,7 @@ static const arch_register_t *sp_reg = &sparc_registers[REG_SP]; 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; @@ -336,6 +337,45 @@ static ir_node *gen_helper_unfpop(ir_node *node, ir_mode *mode, 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]); @@ -446,6 +486,34 @@ static ir_node *gen_Add(ir_node *node) 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. * @@ -465,6 +533,34 @@ static ir_node *gen_Sub(ir_node *node) 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) @@ -2012,6 +2108,11 @@ static ir_node *gen_Proj(ir_node *node) /* 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); } } @@ -2064,7 +2165,11 @@ static void sparc_register_transformers(void) 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); } /** @@ -2079,9 +2184,10 @@ void sparc_transform_graph(ir_graph *irg) 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); diff --git a/ir/lower/lower_dw.c b/ir/lower/lower_dw.c index 9966df7bd..35980750d 100644 --- a/ir/lower/lower_dw.c +++ b/ir/lower/lower_dw.c @@ -304,6 +304,11 @@ void ir_set_dw_lowered(ir_node *old, ir_node *new_low, ir_node *new_high) entry->high_word = new_high; } +ir_mode *ir_get_low_unsigned_mode(void) +{ + return env->low_unsigned; +} + /** * Translate a Constant: create two. */ @@ -532,8 +537,11 @@ static void lower_Div(ir_node *node, ir_mode *mode) 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; @@ -604,8 +612,11 @@ static void lower_Mod(ir_node *node, ir_mode *mode) 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; @@ -975,7 +986,7 @@ static void lower_Shl(ir_node *node, ir_mode *mode) 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); diff --git a/ir/lower/lower_dw.h b/ir/lower/lower_dw.h index e55f3d3a5..19792bf32 100644 --- a/ir/lower/lower_dw.h +++ b/ir/lower/lower_dw.h @@ -104,6 +104,12 @@ static inline ir_node *get_lowered_high(ir_node *node) 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. */ -- 2.20.1