Commit ed0e4ce9 authored by Matthias Braun's avatar Matthias Braun
Browse files

sparc: implement 64bit lowering

parent c300b600
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include "irtools.h" #include "irtools.h"
#include "irdump.h" #include "irdump.h"
#include "lowering.h" #include "lowering.h"
#include "lower_dw.h"
#include "bitset.h" #include "bitset.h"
#include "debug.h" #include "debug.h"
...@@ -125,7 +126,7 @@ static int sparc_get_sp_bias(const ir_node *node) ...@@ -125,7 +126,7 @@ static int sparc_get_sp_bias(const ir_node *node)
/* fill register allocator interface */ /* fill register allocator interface */
static const arch_irn_ops_t sparc_irn_ops = { const arch_irn_ops_t sparc_irn_ops = {
sparc_classify, sparc_classify,
sparc_get_frame_entity, sparc_get_frame_entity,
sparc_set_frame_offset, sparc_set_frame_offset,
...@@ -555,9 +556,10 @@ static void sparc_lower_for_target(void) ...@@ -555,9 +556,10 @@ static void sparc_lower_for_target(void)
NULL, /* find pointer type */ NULL, /* find pointer type */
NULL, /* ret_compound_in_regs */ NULL, /* ret_compound_in_regs */
}; };
lower_calls_with_compounds(&params); lower_calls_with_compounds(&params);
sparc_lower_64bit();
for (i = 0; i < n_irgs; ++i) { for (i = 0; i < n_irgs; ++i) {
ir_graph *irg = get_irp_irg(i); ir_graph *irg = get_irp_irg(i);
ir_lower_mode_b(irg, &lower_mode_b_config); ir_lower_mode_b(irg, &lower_mode_b_config);
......
...@@ -50,6 +50,8 @@ struct sparc_transform_env_t { ...@@ -50,6 +50,8 @@ struct sparc_transform_env_t {
ir_mode *mode; /**< The mode of the irn */ 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 * SPARC ABI requires some space which is always available at the top of
* the stack. It contains: * the stack. It contains:
...@@ -76,4 +78,6 @@ void sparc_finish(ir_graph *irg); ...@@ -76,4 +78,6 @@ void sparc_finish(ir_graph *irg);
void sparc_introduce_prolog_epilog(ir_graph *irg); void sparc_introduce_prolog_epilog(ir_graph *irg);
void sparc_lower_64bit(void);
#endif #endif
...@@ -176,12 +176,12 @@ void sparc_emit_dest_register(const ir_node *node, int pos) ...@@ -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) void sparc_emit_reg_or_imm(const ir_node *node, int pos)
{ {
if (get_irn_arity(node) > pos) { if (arch_irn_get_flags(node) & ((arch_irn_flags_t)sparc_arch_irn_flag_immediate_form)) {
// we have reg input
sparc_emit_source_register(node, pos);
} else {
// we have a imm input // we have a imm input
sparc_emit_immediate(node); sparc_emit_immediate(node);
} else {
// we have reg input
sparc_emit_source_register(node, pos);
} }
} }
......
/*
* 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();
}
...@@ -93,6 +93,9 @@ static void sparc_dump_node(FILE *F, ir_node *n, dump_reason_t reason) ...@@ -93,6 +93,9 @@ static void sparc_dump_node(FILE *F, ir_node *n, dump_reason_t reason)
break; break;
case dump_node_info_txt: case dump_node_info_txt:
if (is_sparc_AddX_t(n) || is_sparc_AddCC_t(n))
break;
arch_dump_reqs_and_registers(F, n); arch_dump_reqs_and_registers(F, n);
attr = get_sparc_attr_const(n); attr = get_sparc_attr_const(n);
if (attr->immediate_value_entity) { if (attr->immediate_value_entity) {
...@@ -141,6 +144,7 @@ static void sparc_set_attr_imm(ir_node *res, ir_entity *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); sparc_attr_t *attr = (sparc_attr_t*)get_irn_generic_attr(res);
attr->immediate_value_entity = entity; attr->immediate_value_entity = entity;
attr->immediate_value = immediate_value; 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, static void init_sparc_jmp_cond_attr(ir_node *node, ir_relation relation,
......
...@@ -45,6 +45,7 @@ enum sparc_arch_irn_flags_t { ...@@ -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_flags = arch_irn_flags_backend << 0,
sparc_arch_irn_flag_modifies_fp_flags = arch_irn_flags_backend << 1, 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_needs_64bit_spillslot = arch_irn_flags_backend << 2,
sparc_arch_irn_flag_immediate_form = arch_irn_flags_backend << 3,
}; };
/** /**
......
...@@ -174,6 +174,33 @@ my %binop_operand_constructors = ( ...@@ -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 = ( my %binopcczero_operand_constructors = (
imm => { imm => {
attr => "ir_entity *immediate_entity, int32_t immediate_value", attr => "ir_entity *immediate_entity, int32_t immediate_value",
...@@ -237,6 +264,33 @@ Add => { ...@@ -237,6 +264,33 @@ Add => {
constructors => \%binop_operand_constructors, 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 => { Sub => {
irn_flags => [ "rematerializable" ], irn_flags => [ "rematerializable" ],
mode => $mode_gp, mode => $mode_gp,
...@@ -244,6 +298,31 @@ Sub => { ...@@ -244,6 +298,31 @@ Sub => {
constructors => \%binop_operand_constructors, 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 # Load / Store
Ld => { Ld => {
op_flags => [ "labeled", "fragile" ], op_flags => [ "labeled", "fragile" ],
......
...@@ -66,6 +66,7 @@ static const arch_register_t *sp_reg = &sparc_registers[REG_SP]; ...@@ -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 const arch_register_t *fp_reg = &sparc_registers[REG_FRAME_POINTER];
static calling_convention_t *cconv = NULL; static calling_convention_t *cconv = NULL;
static ir_mode *mode_gp; static ir_mode *mode_gp;
static ir_mode *mode_flags;
static ir_mode *mode_fp; static ir_mode *mode_fp;
static ir_mode *mode_fp2; static ir_mode *mode_fp2;
//static ir_mode *mode_fp4; //static ir_mode *mode_fp4;
...@@ -336,6 +337,45 @@ static ir_node *gen_helper_unfpop(ir_node *node, ir_mode *mode, ...@@ -336,6 +337,45 @@ static ir_node *gen_helper_unfpop(ir_node *node, ir_mode *mode,
panic("unsupported mode %+F for float op", 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) static ir_node *get_g0(void)
{ {
return be_prolog_get_reg_value(abihelper, &sparc_registers[REG_G0]); return be_prolog_get_reg_value(abihelper, &sparc_registers[REG_G0]);
...@@ -446,6 +486,34 @@ static ir_node *gen_Add(ir_node *node) ...@@ -446,6 +486,34 @@ static ir_node *gen_Add(ir_node *node)
new_bd_sparc_Add_reg, new_bd_sparc_Add_imm); 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. * Creates an sparc Sub.
* *
...@@ -465,6 +533,34 @@ static ir_node *gen_Sub(ir_node *node) ...@@ -465,6 +533,34 @@ static ir_node *gen_Sub(ir_node *node)
new_bd_sparc_Sub_reg, new_bd_sparc_Sub_imm); 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, static ir_node *create_ldf(dbg_info *dbgi, ir_node *block, ir_node *ptr,
ir_node *mem, ir_mode *mode, ir_entity *entity, ir_node *mem, ir_mode *mode, ir_entity *entity,
long offset, bool is_frame_entity) long offset, bool is_frame_entity)
...@@ -2012,6 +2108,11 @@ static ir_node *gen_Proj(ir_node *node) ...@@ -2012,6 +2108,11 @@ static ir_node *gen_Proj(ir_node *node)
/* FALLTHROUGH */ /* FALLTHROUGH */
} }
default: 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); panic("code selection didn't expect Proj after %+F\n", pred);
} }
} }
...@@ -2064,7 +2165,11 @@ static void sparc_register_transformers(void) ...@@ -2064,7 +2165,11 @@ static void sparc_register_transformers(void)
be_set_transform_function(op_SymConst, gen_SymConst); be_set_transform_function(op_SymConst, gen_SymConst);
be_set_transform_function(op_Unknown, gen_Unknown); 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_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) ...@@ -2079,9 +2184,10 @@ void sparc_transform_graph(ir_graph *irg)
node_to_stack = pmap_create(); node_to_stack = pmap_create();
mode_gp = mode_Iu; mode_gp = mode_Iu;
mode_fp = mode_F; mode_fp = mode_F;
mode_fp2 = mode_D; mode_fp2 = mode_D;
mode_flags = mode_Bu;
//mode_fp4 = ? //mode_fp4 = ?
abihelper = be_abihelper_prepare(irg); abihelper = be_abihelper_prepare(irg);
......
...@@ -304,6 +304,11 @@ void ir_set_dw_lowered(ir_node *old, ir_node *new_low, ir_node *new_high) ...@@ -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; entry->high_word = new_high;
} }
ir_mode *ir_get_low_unsigned_mode(void)
{
return env->low_unsigned;
}
/** /**
* Translate a Constant: create two. * Translate a Constant: create two.
*/ */
...@@ -532,8 +537,11 @@ static void lower_Div(ir_node *node, ir_mode *mode) ...@@ -532,8 +537,11 @@ static void lower_Div(ir_node *node, ir_mode *mode)
set_Proj_pred(proj, call); set_Proj_pred(proj, call);
set_Proj_proj(proj, pn_Call_M); set_Proj_proj(proj, pn_Call_M);
break; break;
case pn_Div_X_except: /* Execution result if exception occurred. */ case pn_Div_X_regular:
/* reroute to the call */ 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_pred(proj, call);
set_Proj_proj(proj, pn_Call_X_except); set_Proj_proj(proj, pn_Call_X_except);
break; break;
...@@ -604,8 +612,11 @@ static void lower_Mod(ir_node *node, ir_mode *mode) ...@@ -604,8 +612,11 @@ static void lower_Mod(ir_node *node, ir_mode *mode)
set_Proj_pred(proj, call); set_Proj_pred(proj, call);
set_Proj_proj(proj, pn_Call_M); set_Proj_proj(proj, pn_Call_M);
break; break;
case pn_Mod_X_except: /* Execution result if exception occurred. */ case pn_Div_X_regular: