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

sparc: model restore as explicit node, refactor Save node

[r28068]
parent eb25552b
......@@ -107,12 +107,15 @@ static void sparc_set_frame_offset(ir_node *node, int offset)
static int sparc_get_sp_bias(const ir_node *node)
{
if (is_sparc_Save(node)) {
const sparc_save_attr_t *attr = get_sparc_save_attr_const(node);
/* Note we do not retport the change of the SPARC_MIN_STACKSIZE
const sparc_attr_t *attr = get_sparc_attr_const(node);
if (get_irn_arity(node) == 3)
panic("no support for _reg variant yet");
/* Note we do not report the change of the SPARC_MIN_STACKSIZE
* size, since we have additional magic in the emitter which
* calculates that! */
assert(attr->initial_stacksize >= SPARC_MIN_STACKSIZE);
return attr->initial_stacksize - SPARC_MIN_STACKSIZE;
assert(attr->immediate_value <= -SPARC_MIN_STACKSIZE);
return attr->immediate_value + SPARC_MIN_STACKSIZE;
}
return 0;
}
......
......@@ -366,6 +366,8 @@ static bool is_no_instruction(const ir_node *node)
if (src_reg == dest_reg)
return true;
}
if (be_is_IncSP(node) && be_get_IncSP_offset(node) == 0)
return true;
/* Ba is not emitted if it is a simple fallthrough */
if (is_sparc_Ba(node) && ba_is_fallthrough(node))
return true;
......@@ -381,7 +383,8 @@ static bool has_delay_slot(const ir_node *node)
return is_sparc_Bicc(node) || is_sparc_fbfcc(node) || is_sparc_Ba(node)
|| is_sparc_SwitchJmp(node) || is_sparc_Call(node)
|| is_sparc_SDiv(node) || is_sparc_UDiv(node);
|| is_sparc_SDiv(node) || is_sparc_UDiv(node)
|| be_is_Return(node);
}
/** returns true if the emitter for this sparc node can produce more than one
......@@ -396,7 +399,7 @@ static bool emits_multiple_instructions(const ir_node *node)
return true;
return is_sparc_Mulh(node) || is_sparc_SDiv(node) || is_sparc_UDiv(node)
|| be_is_MemPerm(node) || be_is_Perm(node) || be_is_Return(node);
|| be_is_MemPerm(node) || be_is_Perm(node);
}
/**
......@@ -427,6 +430,20 @@ static const ir_node *pick_delay_slot_for(const ir_node *node)
/* the Call also destroys the value of %o7, but since this is currently
* marked as ignore register in the backend, it should never be used by
* the instruction in the delay slot. */
} else if (be_is_Return(node)) {
/* we only have to check the jump destination value */
int arity = get_irn_arity(node);
int i;
check = NULL;
for (i = 0; i < arity; ++i) {
ir_node *in = get_irn_n(node, i);
const arch_register_t *reg = arch_get_irn_register(in);
if (reg == &sparc_gp_regs[REG_O7]) {
check = skip_Proj(in);
break;
}
}
} else {
check = node;
}
......@@ -485,19 +502,6 @@ static void emit_be_IncSP(const ir_node *irn)
be_emit_finish_line_gas(irn);
}
/**
* emits code for save instruction with min. required stack space
*/
static void emit_sparc_Save(const ir_node *irn)
{
const sparc_save_attr_t *save_attr = get_sparc_save_attr_const(irn);
be_emit_cstring("\tsave ");
sparc_emit_source_register(irn, 0);
be_emit_irprintf(", %d, ", -save_attr->initial_stacksize);
sparc_emit_dest_register(irn, 0);
be_emit_finish_line_gas(irn);
}
/**
* emits code for mulh
*/
......@@ -566,18 +570,6 @@ static void emit_sparc_UDiv(const ir_node *node)
emit_sparc_Div(node, false);
}
/**
* Emits code for return node
*/
static void emit_be_Return(const ir_node *irn)
{
be_emit_cstring("\tret");
//be_emit_cstring("\tjmp %i7+8");
be_emit_finish_line_gas(irn);
be_emit_cstring("\trestore");
be_emit_finish_line_gas(irn);
}
/**
* Emits code for Call node
*/
......@@ -688,6 +680,24 @@ static void emit_be_MemPerm(const ir_node *node)
assert(sp_change == 0);
}
static void emit_be_Return(const ir_node *node)
{
const char *destreg = "%o7";
/* hack: we don't explicitely model register changes because of the
* restore node. So we have to do it manually here */
if (delay_slot_filler != NULL &&
(is_sparc_Restore(delay_slot_filler)
|| is_sparc_RestoreZero(delay_slot_filler))) {
destreg = "%i7";
}
be_emit_cstring("\tjmp ");
be_emit_string(destreg);
be_emit_cstring("+8");
be_emit_finish_line_gas(node);
fill_delay_slot();
}
static void emit_sparc_FrameAddr(const ir_node *node)
{
const sparc_attr_t *attr = get_sparc_attr_const(node);
......@@ -1014,7 +1024,6 @@ static void sparc_register_emitters(void)
set_emitter(op_sparc_fbfcc, emit_sparc_fbfcc);
set_emitter(op_sparc_FrameAddr, emit_sparc_FrameAddr);
set_emitter(op_sparc_Mulh, emit_sparc_Mulh);
set_emitter(op_sparc_Save, emit_sparc_Save);
set_emitter(op_sparc_SDiv, emit_sparc_SDiv);
set_emitter(op_sparc_SwitchJmp, emit_sparc_SwitchJmp);
set_emitter(op_sparc_UDiv, emit_sparc_UDiv);
......
......@@ -60,11 +60,6 @@ static bool has_switch_jmp_attr(const ir_node *node)
return is_sparc_SwitchJmp(node);
}
static bool has_save_attr(const ir_node *node)
{
return is_sparc_Save(node);
}
static bool has_fp_attr(const ir_node *node)
{
return is_sparc_fadd(node) || is_sparc_fsub(node)
......@@ -105,10 +100,6 @@ static void sparc_dump_node(FILE *F, ir_node *n, dump_reason_t reason)
} else {
ir_fprintf(F, "immediate value: %d\n", attr->immediate_value);
}
if (has_save_attr(n)) {
const sparc_save_attr_t *attr = get_sparc_save_attr_const(n);
fprintf(F, "initial stacksize: %d\n", attr->initial_stacksize);
}
if (sparc_has_load_store_attr(n)) {
const sparc_load_store_attr_t *attr = get_sparc_load_store_attr_const(n);
ir_fprintf(F, "load store mode: %+F\n", attr->load_store_mode);
......@@ -205,18 +196,6 @@ const sparc_switch_jmp_attr_t *get_sparc_switch_jmp_attr_const(const ir_node *no
return (const sparc_switch_jmp_attr_t*) get_irn_generic_attr_const(node);
}
sparc_save_attr_t *get_sparc_save_attr(ir_node *node)
{
assert(has_save_attr(node));
return (sparc_save_attr_t*) get_irn_generic_attr_const(node);
}
const sparc_save_attr_t *get_sparc_save_attr_const(const ir_node *node)
{
assert(has_save_attr(node));
return (const sparc_save_attr_t*) get_irn_generic_attr_const(node);
}
sparc_fp_attr_t *get_sparc_fp_attr(ir_node *node)
{
assert(has_fp_attr(node));
......@@ -275,12 +254,6 @@ static void init_sparc_load_store_attributes(ir_node *res, ir_mode *ls_mode,
attr->is_reg_reg = is_reg_reg;
}
static void init_sparc_save_attributes(ir_node *res, int initial_stacksize)
{
sparc_save_attr_t *attr = get_sparc_save_attr(res);
attr->initial_stacksize = initial_stacksize;
}
static void init_sparc_fp_attributes(ir_node *res, ir_mode *fp_mode)
{
sparc_fp_attr_t *attr = get_sparc_fp_attr(res);
......@@ -370,17 +343,6 @@ static int cmp_attr_sparc_switch_jmp(ir_node *a, ir_node *b)
return attr_a->default_proj_num != attr_b->default_proj_num;
}
static int cmp_attr_sparc_save(ir_node *a, ir_node *b)
{
const sparc_save_attr_t *attr_a = get_sparc_save_attr_const(a);
const sparc_save_attr_t *attr_b = get_sparc_save_attr_const(b);
if (cmp_attr_sparc(a, b))
return 1;
return attr_a->initial_stacksize != attr_b->initial_stacksize;
}
static int cmp_attr_sparc_fp(ir_node *a, ir_node *b)
{
const sparc_fp_attr_t *attr_a = get_sparc_fp_attr_const(a);
......
......@@ -44,9 +44,6 @@ const sparc_jmp_cond_attr_t *get_sparc_jmp_cond_attr_const(const ir_node *node);
sparc_switch_jmp_attr_t *get_sparc_switch_jmp_attr(ir_node *node);
const sparc_switch_jmp_attr_t *get_sparc_switch_jmp_attr_const(const ir_node *node);
sparc_save_attr_t *get_sparc_save_attr(ir_node *node);
const sparc_save_attr_t *get_sparc_save_attr_const(const ir_node *node);
sparc_fp_attr_t *get_sparc_fp_attr(ir_node *node);
const sparc_fp_attr_t *get_sparc_fp_attr_const(const ir_node *node);
......
......@@ -62,15 +62,6 @@ struct sparc_fp_conv_attr_t {
ir_mode *dest_mode;
};
/**
* attribute for save instruction
*/
typedef struct sparc_save_attr_t sparc_save_attr_t;
struct sparc_save_attr_t {
sparc_attr_t base; /**< generic attribute */
int initial_stacksize; /* the min. stack size required by the sparc ABI */
};
/**
* attributes for load/store adressing modes
*/
......
......@@ -139,7 +139,6 @@ $default_copy_attr = "sparc_copy_attr";
sparc_jmp_cond_attr_t => "\tinit_sparc_attributes(res, flags, in_reqs, exec_units, n_res);",
sparc_switch_jmp_attr_t => "\tinit_sparc_attributes(res, flags, in_reqs, exec_units, n_res);\n".
"\tinit_sparc_switch_jmp_attributes(res, default_pn, jump_table);\n",
sparc_save_attr_t => "\tinit_sparc_attributes(res, flags, in_reqs, exec_units, n_res);",
sparc_fp_attr_t => "\tinit_sparc_attributes(res, flags, in_reqs, exec_units, n_res);\n".
"\tinit_sparc_fp_attributes(res, fp_mode);\n",
sparc_fp_conv_attr_t => "\tinit_sparc_attributes(res, flags, in_reqs, exec_units, n_res);".
......@@ -151,7 +150,6 @@ $default_copy_attr = "sparc_copy_attr";
sparc_load_store_attr_t => "cmp_attr_sparc_load_store",
sparc_jmp_cond_attr_t => "cmp_attr_sparc_jmp_cond",
sparc_switch_jmp_attr_t => "cmp_attr_sparc_switch_jmp",
sparc_save_attr_t => "cmp_attr_sparc_save",
sparc_fp_attr_t => "cmp_attr_sparc_fp",
sparc_fp_conv_attr_t => "cmp_attr_sparc_fp_conv",
);
......@@ -161,9 +159,6 @@ $default_copy_attr = "sparc_copy_attr";
modifies_fp_flags => "sparc_arch_irn_flag_modifies_fp_flags",
);
# addressing modes: imm, reg, reg +/- imm, reg + reg
# max. imm = 13 bits signed (-4096 ... 4096)
my %cmp_operand_constructors = (
imm => {
attr => "ir_entity *immediate_entity, int32_t immediate_value",
......@@ -260,7 +255,6 @@ Sub => {
constructors => \%binop_operand_constructors,
},
# Load / Store
Ld => {
op_flags => [ "labeled", "fragile" ],
......@@ -320,15 +314,44 @@ St => {
},
Save => {
reg_req => {
in => [ "sp", "none"],
out => [ "sp:I|S", "frame_pointer:I", "none" ]
emit => '. save %S0, %R1I, %D0',
outs => [ "stack" ],
constructors => {
imm => {
attr => "ir_entity *immediate_entity, int32_t immediate_value",
custominit => "sparc_set_attr_imm(res, immediate_entity, immediate_value);",
reg_req => { in => [ "sp" ], out => [ "sp:I|S" ] },
ins => [ "stack" ],
},
reg => {
reg_req => { in => [ "sp", "gp" ], out => [ "sp:I|S" ] },
ins => [ "stack", "increment" ],
}
},
ins => [ "stack", "mem" ],
outs => [ "stack", "frame", "mem" ],
attr => "int initial_stacksize",
attr_type => "sparc_save_attr_t",
init_attr => "\tinit_sparc_save_attributes(res, initial_stacksize);",
},
Restore => {
emit => '. restore %S0, %R1I, %D0',
outs => [ "stack" ],
constructors => {
imm => {
attr => "ir_entity *immediate_entity, int32_t immediate_value",
custominit => "sparc_set_attr_imm(res, immediate_entity, immediate_value);",
reg_req => { in => [ "sp" ], out => [ "sp:I|S" ] },
ins => [ "stack" ],
},
reg => {
reg_req => { in => [ "sp", "gp" ], out => [ "sp:I|S" ] },
ins => [ "stack", "increment" ],
}
},
},
RestoreZero => {
emit => '. restore',
outs => [ ],
ins => [ ],
mode => "mode_T",
},
SubSP => {
......@@ -384,6 +407,25 @@ Ba => {
mode => "mode_X",
},
# This is a JumpLink instruction, but with the addition that you can add custom
# register constraints to model your calling conventions
Return => {
arity => "variable",
out_arity => "variable",
constructors => {
imm => {
attr => "ir_entity *entity, int32_t offset",
custominit => "\tsparc_set_attr_imm(res, entity, offset);",
arity => "variable",
out_arity => "variable",
},
reg => {
arity => "variable",
out_arity => "variable",
}
},
},
Call => {
irn_flags => [ "modifies_flags", "modifies_fp_flags" ],
state => "exc_pinned",
......
......@@ -1282,7 +1282,6 @@ static ir_node *gen_Start(ir_node *node)
ir_node *mem;
ir_node *start;
ir_node *sp;
ir_node *fp;
ir_node *barrier;
ir_node *save;
int i;
......@@ -1305,16 +1304,10 @@ static ir_node *gen_Start(ir_node *node)
mem = be_prolog_get_memory(abihelper);
sp = be_prolog_get_reg_value(abihelper, sp_reg);
save = new_bd_sparc_Save(NULL, block, sp, mem, SPARC_MIN_STACKSIZE);
fp = new_r_Proj(save, mode_gp, pn_sparc_Save_frame);
save = new_bd_sparc_Save_imm(NULL, block, sp, NULL, -SPARC_MIN_STACKSIZE);
sp = new_r_Proj(save, mode_gp, pn_sparc_Save_stack);
mem = new_r_Proj(save, mode_M, pn_sparc_Save_mem);
arch_set_irn_register(fp, fp_reg);
arch_set_irn_register(sp, sp_reg);
be_prolog_add_reg(abihelper, fp_reg, arch_register_req_type_ignore);
be_prolog_set_reg_value(abihelper, fp_reg, fp);
sp = be_new_IncSP(sp_reg, new_block, sp, BE_STACK_FRAME_SIZE_EXPAND, 0);
be_prolog_set_reg_value(abihelper, sp_reg, sp);
be_prolog_set_memory(abihelper, mem);
......@@ -1360,6 +1353,7 @@ static ir_node *gen_Return(ir_node *node)
ir_node *sp_proj = get_stack_pointer_for(node);
int n_res = get_Return_n_ress(node);
ir_node *bereturn;
ir_node *restore;
ir_node *incsp;
int i;
......@@ -1390,6 +1384,10 @@ static ir_node *gen_Return(ir_node *node)
BE_STACK_FRAME_SIZE_SHRINK, 0);
be_epilog_set_reg_value(abihelper, sp_reg, incsp);
/* we need a restore instruction */
restore = new_bd_sparc_RestoreZero(NULL, block);
keep_alive(restore);
bereturn = be_epilog_create_return(abihelper, dbgi, new_block);
return bereturn;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment