Commit 58b0168a authored by Matthias Braun's avatar Matthias Braun
Browse files

Remove produces_sp register constraint

We can easily identify the outputs producing a stack pointer by looking
if the stack pointer register is assigned. Unfortunately this also
needed a new mechanism to tell the verifier that some registers are not
in SSA form (all the time) which needs a few extra lines in each
backend.
parent a315f5e9
......@@ -193,7 +193,7 @@ Jmp => {
Start => {
irn_flags => [ "schedule_first" ],
state => "pinned",
our_reqs => [ "sp:I|S", "r0", "r1", "r2", "r3", "none" ],
our_reqs => [ "sp:I", "r0", "r1", "r2", "r3", "none" ],
outs => [ "stack", "arg0", "arg1", "arg2", "arg3", "M" ],
ins => [],
},
......
......@@ -11,6 +11,7 @@
#include "TEMPLATE_new_nodes.h"
#include "TEMPLATE_transform.h"
#include "be_t.h"
#include "beirg.h"
#include "bemodule.h"
#include "benode.h"
#include "bera.h"
......@@ -61,11 +62,14 @@ static const regalloc_if_t TEMPLATE_regalloc_if = {
static void TEMPLATE_generate_code(FILE *output, const char *cup_name)
{
be_begin(output, cup_name);
unsigned *const sp_is_non_ssa = rbitset_malloc(N_TEMPLATE_REGISTERS);
rbitset_set(sp_is_non_ssa, REG_SP);
foreach_irp_irg(i, irg) {
if (!be_step_first(irg))
continue;
be_birg_from_irg(irg)->non_ssa_regs = sp_is_non_ssa;
TEMPLATE_select_instructions(irg);
be_step_schedule(irg);
......@@ -73,6 +77,7 @@ static void TEMPLATE_generate_code(FILE *output, const char *cup_name)
be_step_regalloc(irg, &TEMPLATE_regalloc_if);
be_fix_stack_nodes(irg, &TEMPLATE_registers[REG_SP]);
be_birg_from_irg(irg)->non_ssa_regs = NULL;
TEMPLATE_emit_function(irg);
......
......@@ -216,7 +216,7 @@ push_am => {
op_flags => [ "uses_memory" ],
state => "exc_pinned",
in_reqs => "...",
out_reqs => [ "rsp:I|S", "none" ],
out_reqs => [ "rsp:I", "none" ],
outs => [ "stack", "M" ],
attr_type => "amd64_addr_attr_t",
attr => "amd64_insn_mode_t insn_mode, amd64_addr_t addr",
......@@ -228,7 +228,7 @@ push_reg => {
op_flags => [ "uses_memory" ],
state => "exc_pinned",
in_reqs => [ "rsp", "gp" ],
out_reqs => [ "rsp:I|S" ],
out_reqs => [ "rsp:I" ],
ins => [ "stack", "val" ],
outs => [ "stack" ],
fixed => "amd64_op_mode_t op_mode = AMD64_OP_NONE;\n",
......@@ -239,7 +239,7 @@ pop_am => {
op_flags => [ "uses_memory" ],
state => "exc_pinned",
in_reqs => "...",
out_reqs => [ "rsp:I|S", "none" ],
out_reqs => [ "rsp:I", "none" ],
outs => [ "stack", "M" ],
attr_type => "amd64_addr_attr_t",
attr => "amd64_insn_mode_t insn_mode, amd64_addr_t addr",
......@@ -250,7 +250,7 @@ pop_am => {
sub_sp => {
state => "pinned",
in_reqs => "...",
out_reqs => [ "rsp:I|S", "gp", "none" ],
out_reqs => [ "rsp:I", "gp", "none" ],
outs => [ "stack", "addr", "M" ],
attr_type => "amd64_binop_addr_attr_t",
attr => "const amd64_binop_addr_attr_t *attr_init",
......@@ -263,7 +263,7 @@ leave => {
op_flags => [ "uses_memory" ],
state => "exc_pinned",
in_reqs => [ "rbp" ],
out_reqs => [ "rbp:I", "rsp:I|S" ],
out_reqs => [ "rbp:I", "rsp:I" ],
outs => [ "frame", "stack" ],
fixed => "amd64_op_mode_t op_mode = AMD64_OP_NONE;\n",
emit => "leave",
......
......@@ -1440,7 +1440,7 @@ static ir_node *gen_Start(ir_node *node)
be_make_start_mem(&start_mem, start, o++);
/* the stack pointer */
be_make_start_out(&start_val[REG_RSP], start, o++, &amd64_registers[REG_RSP], arch_register_req_type_ignore | arch_register_req_type_produces_sp);
be_make_start_out(&start_val[REG_RSP], start, o++, &amd64_registers[REG_RSP], arch_register_req_type_ignore);
/* function parameters in registers */
const unsigned *allocatable_regs = be_birg_from_irg(irg)->allocatable_regs;
......
......@@ -626,6 +626,7 @@ static void amd64_finish_and_emit(ir_graph *irg)
/* fix stack entity offsets */
be_fix_stack_nodes(irg, &amd64_registers[REG_RSP]);
be_birg_from_irg(irg)->non_ssa_regs = NULL;
be_abi_fix_stack_bias(irg, amd64_get_sp_bias, amd64_set_frame_offset,
amd64_get_frame_entity);
......@@ -654,11 +655,14 @@ static void amd64_generate_code(FILE *output, const char *cup_name)
{
amd64_constants = pmap_create();
be_begin(output, cup_name);
unsigned *const sp_is_non_ssa = rbitset_malloc(N_AMD64_REGISTERS);
rbitset_set(sp_is_non_ssa, REG_RSP);
foreach_irp_irg(i, irg) {
if (!be_step_first(irg))
continue;
be_birg_from_irg(irg)->non_ssa_regs = sp_is_non_ssa;
amd64_select_instructions(irg);
be_step_schedule(irg);
......
......@@ -184,6 +184,7 @@ void arm_finish_graph(ir_graph *irg)
/* fix stack entity offsets */
be_fix_stack_nodes(irg, &arm_registers[REG_SP]);
be_birg_from_irg(irg)->non_ssa_regs = NULL;
be_abi_fix_stack_bias(irg, arm_get_sp_bias, arm_set_frame_offset,
arm_get_frame_entity);
......
......@@ -1729,7 +1729,7 @@ static ir_node *gen_Start(ir_node *node)
be_make_start_mem(&start_mem, start, o++);
be_make_start_out(&start_sp, start, o++, &arm_registers[REG_SP], arch_register_req_type_ignore | arch_register_req_type_produces_sp);
be_make_start_out(&start_sp, start, o++, &arm_registers[REG_SP], arch_register_req_type_ignore);
/* function parameters in registers */
start_params_offset = o;
......
......@@ -13,6 +13,7 @@
#include "arm_transform.h"
#include "be_t.h"
#include "bearch_arm_t.h"
#include "beirg.h"
#include "beflags.h"
#include "begnuas.h"
#include "bemodule.h"
......@@ -176,6 +177,8 @@ static void arm_generate_code(FILE *output, const char *cup_name)
be_gas_elf_type_char = '%';
be_begin(output, cup_name);
unsigned *const sp_is_non_ssa = rbitset_malloc(N_ARM_REGISTERS);
rbitset_set(sp_is_non_ssa, REG_SP);
arm_emit_file_prologue();
......@@ -183,6 +186,7 @@ static void arm_generate_code(FILE *output, const char *cup_name)
if (!be_step_first(irg))
continue;
be_birg_from_irg(irg)->non_ssa_regs = sp_is_non_ssa;
arm_select_instructions(irg);
be_step_schedule(irg);
......
......@@ -34,10 +34,6 @@ typedef enum arch_register_req_type_t {
arch_register_req_type_aligned = 1U << 2,
/** ignore while allocating registers */
arch_register_req_type_ignore = 1U << 3,
/** the output produces a new value for the stack pointer
* (this is not really a constraint but a marker to guide the stackpointer
* rewiring logic) */
arch_register_req_type_produces_sp = 1U << 4,
} arch_register_req_type_t;
ENUM_BITSET(arch_register_req_type_t)
......
......@@ -210,8 +210,6 @@ static void dump_register_req(FILE *const F, arch_register_req_t const *const re
fputs(" aligned", F);
if (arch_register_req_is(req, ignore))
fputs(" ignore", F);
if (arch_register_req_is(req, produces_sp))
fputs(" produces_sp", F);
}
static void dump_req_reg(FILE *const F, char const *const ctx, unsigned const idx, arch_register_req_t const *const req, arch_register_t const *const reg)
......
......@@ -70,6 +70,10 @@ typedef struct be_irg_t {
be_stack_layout_t stack_layout;
/** bitset of registers available for the allocator */
unsigned *allocatable_regs;
/** bitset of registers for which verification errors are not reported.
* A typical use is for the stackpointer for which SSA form is only built
* once late in the compilation. May be NULL. */
const unsigned *non_ssa_regs;
/** obstack (mainly used to keep register constraints which we can't keep
* in the irg obst, because it gets replaced during code selection) */
struct obstack obst;
......
......@@ -255,11 +255,11 @@ static void be_sched_verify(ir_graph *irg)
}
}
static void be_regalloc_verify(ir_graph *const irg, bool const ignore_sp_problems)
static void be_regalloc_verify(ir_graph *const irg)
{
if (be_options.do_verify) {
be_timer_push(T_VERIFY);
bool const fine = be_verify_register_allocation(irg, ignore_sp_problems);
bool const fine = be_verify_register_allocation(irg);
be_check_verify_result(fine, irg);
be_timer_pop(T_VERIFY);
}
......@@ -570,7 +570,7 @@ void be_step_regalloc(ir_graph *irg, const regalloc_if_t *regif)
/* Do register allocation */
be_allocate_registers(irg, regif);
be_regalloc_verify(irg, true);
be_regalloc_verify(irg);
if (stat_ev_enabled) {
stat_ev_dbl("bemain_costs_after_ra", be_estimate_irg_costs(irg));
......@@ -589,7 +589,7 @@ void be_step_last(ir_graph *irg)
}
be_dump(DUMP_FINAL, irg, "final");
be_regalloc_verify(irg, false);
be_regalloc_verify(irg);
be_timer_pop(T_OTHER);
......
......@@ -245,7 +245,6 @@ ir_node *be_new_IncSP(const arch_register_t *sp, ir_node *bl,
/* Set output constraint to stack register. */
be_node_set_register_req_in(irn, 0, sp->cls->class_req);
arch_copy_irn_out_info(irn, 0, old_sp);
assert(arch_register_req_is(arch_get_irn_register_req(irn), produces_sp));
return irn;
}
......
......@@ -180,16 +180,9 @@ void be_abi_fix_stack_bias(ir_graph *irg, get_sp_bias_func get_sp_bias,
irg_block_walk_graph(irg, stack_bias_walker, NULL, &bw);
}
static bool is_irn_sp_producer(ir_node const *const node)
{
if (get_irn_mode(node) == mode_T)
return false;
arch_register_req_t const *const req = arch_get_irn_register_req(node);
return arch_register_req_is(req, produces_sp);
}
typedef struct fix_stack_walker_env_t {
ir_node **sp_nodes;
const arch_register_t *sp;
ir_node **sp_nodes;
} fix_stack_walker_env_t;
/**
......@@ -198,22 +191,23 @@ typedef struct fix_stack_walker_env_t {
static void collect_stack_nodes_walker(ir_node *node, void *data)
{
fix_stack_walker_env_t *const env = (fix_stack_walker_env_t*)data;
if (is_irn_sp_producer(node))
if (get_irn_mode(node) != mode_T && arch_get_irn_register(node) == env->sp)
ARR_APP1(ir_node*, env->sp_nodes, node);
}
void be_fix_stack_nodes(ir_graph *const irg, arch_register_t const *const sp)
{
be_irg_t *const birg = be_birg_from_irg(irg);
arch_register_req_type_t type = arch_register_req_type_produces_sp;
if (!rbitset_is_set(birg->allocatable_regs, sp->global_index))
type |= arch_register_req_type_ignore;
struct obstack *const obst = be_get_be_obst(irg);
const arch_register_req_t *sp_req = be_create_reg_req(obst, sp, type);
const arch_register_req_t *sp_req;
if (!rbitset_is_set(birg->allocatable_regs, sp->global_index)) {
struct obstack *const obst = be_get_be_obst(irg);
sp_req = be_create_reg_req(obst, sp, arch_register_req_type_ignore);
} else {
sp_req = sp->single_req;
}
fix_stack_walker_env_t walker_env;
walker_env.sp = sp;
walker_env.sp_nodes = NEW_ARR_F(ir_node*, 0);
irg_walk_graph(irg, collect_stack_nodes_walker, NULL, &walker_env);
......@@ -260,7 +254,7 @@ void be_fix_stack_nodes(ir_graph *const irg, arch_register_t const *const sp)
* producers. */
ir_node *end = get_irg_end(irg);
foreach_irn_in_r(end, i, in) {
if (is_irn_sp_producer(in)) {
if (get_irn_mode(in) != mode_T && arch_get_irn_register(in) == sp) {
remove_End_n(end, i);
if (get_irn_n_edges(in) == 0) {
if (!is_Proj(in))
......
......@@ -555,7 +555,6 @@ static bool my_values_interfere(const ir_node *a, const ir_node *b)
typedef struct be_verify_reg_alloc_env_t {
be_lv_t *lv;
bool ignore_sp_problems;
bool problem_found;
} be_verify_reg_alloc_env_t;
......@@ -635,6 +634,14 @@ static void check_input_constraints(be_verify_reg_alloc_env_t *const env, ir_nod
}
}
static bool ignore_error_for_reg(ir_graph *irg, const arch_register_t *reg)
{
be_irg_t *birg = be_birg_from_irg(irg);
if (birg->non_ssa_regs == NULL)
return false;
return rbitset_is_set(birg->non_ssa_regs, reg->global_index);
}
static void value_used(be_verify_reg_alloc_env_t *const env, ir_node const **const registers, ir_node const *const block, ir_node const *const node)
{
const arch_register_t *reg = arch_get_irn_register(node);
......@@ -647,8 +654,7 @@ static void value_used(be_verify_reg_alloc_env_t *const env, ir_node const **con
for (unsigned i = 0; i < req->width; ++i) {
ir_node const *const reg_node = registers[idx + i];
if (reg_node != NULL && reg_node != node
&& (!env->ignore_sp_problems
|| !(req->type & arch_register_req_type_produces_sp))) {
&& !ignore_error_for_reg(get_irn_irg(block), reg)) {
verify_warnf(block, "register %s assigned more than once (nodes %+F and %+F)", reg->name, node, reg_node);
env->problem_found = true;
}
......@@ -674,9 +680,7 @@ static void value_def(be_verify_reg_alloc_env_t *const env, ir_node const **cons
if (reg_node == NULL && get_irn_n_edges(node) == 0)
return;
if (reg_node != node
&& (!env->ignore_sp_problems
|| !(req->type & arch_register_req_type_produces_sp))) {
if (reg_node != node && !ignore_error_for_reg(get_irn_irg(node), reg)) {
verify_warnf(node, "%+F not registered as value for register %s (but %+F)", node, reg->name, reg_node);
env->problem_found = true;
}
......@@ -724,11 +728,10 @@ static void verify_block_register_allocation(ir_node *block, void *data)
}
}
bool be_verify_register_allocation(ir_graph *const irg, bool const ignore_sp_problems)
bool be_verify_register_allocation(ir_graph *const irg)
{
be_verify_reg_alloc_env_t env = {
.lv = be_liveness_new(irg),
.ignore_sp_problems = ignore_sp_problems,
.problem_found = false,
};
......
......@@ -48,11 +48,9 @@ bool be_verify_spillslots(ir_graph *irg,
* assigned.
*
* @param irg The graph to check
* @param ignore_sp_problems if true do not report problems involving values
* with arch_register_req_type_produces_sp
* @return true if verify succeeded, false otherwise
*/
bool be_verify_register_allocation(ir_graph *irg, bool ignore_sp_problems);
bool be_verify_register_allocation(ir_graph *irg);
/**
* Check the given liveness information against a freshly computed one.
......
......@@ -1098,6 +1098,7 @@ static void ia32_emit(ir_graph *irg)
/* fix stack entity offsets */
be_fix_stack_nodes(irg, &ia32_registers[REG_ESP]);
be_birg_from_irg(irg)->non_ssa_regs = NULL;
be_abi_fix_stack_bias(irg, ia32_get_sp_bias, ia32_set_frame_offset,
ia32_get_frame_entity);
......@@ -1451,11 +1452,14 @@ static void ia32_generate_code(FILE *output, const char *cup_name)
ia32_tv_ent = pmap_create();
be_begin(output, cup_name);
unsigned *const sp_is_non_ssa = rbitset_malloc(N_IA32_REGISTERS);
rbitset_set(sp_is_non_ssa, REG_ESP);
foreach_irp_irg(i, irg) {
if (!be_step_first(irg))
continue;
be_birg_from_irg(irg)->non_ssa_regs = sp_is_non_ssa;
ia32_select_instructions(irg);
be_step_schedule(irg);
......
......@@ -1040,7 +1040,7 @@ Lea => {
Push => {
state => "exc_pinned",
in_reqs => [ "gp", "gp", "none", "gp", "esp" ],
out_reqs => [ "none", "esp:I|S" ],
out_reqs => [ "none", "esp:I" ],
ins => [ "base", "index", "mem", "val", "stack" ],
emit => "push%M %AS3",
outs => [ "M", "stack" ],
......@@ -1053,7 +1053,7 @@ Push => {
PushEax => {
state => "exc_pinned",
in_reqs => [ "esp" ],
out_reqs => [ "esp:I|S" ],
out_reqs => [ "esp:I" ],
ins => [ "stack" ],
outs => [ "stack" ],
emit => "pushl %%eax",
......@@ -1065,10 +1065,10 @@ Pop => {
state => "exc_pinned",
constructors => {
"" => {
out_reqs => [ "gp", "none", "none", "esp:I|S" ],
out_reqs => [ "gp", "none", "none", "esp:I" ],
},
"ebp" => {
out_reqs => [ "ebp:I", "none", "none", "esp:I|S" ],
out_reqs => [ "ebp:I", "none", "none", "esp:I" ],
}
},
in_reqs => [ "none", "esp" ],
......@@ -1082,7 +1082,7 @@ Pop => {
CopyEbpEsp => {
state => "exc_pinned",
in_reqs => [ "ebp" ],
out_reqs => [ "esp:I|S" ],
out_reqs => [ "esp:I" ],
ins => [ "ebp" ],
outs => [ "esp" ],
emit => "movl %S0, %D0",
......@@ -1093,7 +1093,7 @@ CopyEbpEsp => {
PopMem => {
state => "exc_pinned",
in_reqs => [ "gp", "gp", "none", "esp" ],
out_reqs => [ "none", "none", "none", "esp:I|S" ],
out_reqs => [ "none", "none", "none", "esp:I" ],
ins => [ "base", "index", "mem", "stack" ],
outs => [ "unused0", "unused1", "M", "stack" ],
emit => "pop%M %AM",
......@@ -1102,7 +1102,7 @@ PopMem => {
Enter => {
in_reqs => [ "esp" ],
out_reqs => [ "ebp", "esp:I|S", "none" ],
out_reqs => [ "ebp", "esp:I", "none" ],
emit => "enter",
outs => [ "frame", "stack", "M" ],
latency => 15,
......@@ -1110,7 +1110,7 @@ Enter => {
Leave => {
in_reqs => [ "none", "ebp" ],
out_reqs => [ "ebp:I", "none", "esp:I|S" ],
out_reqs => [ "ebp:I", "none", "esp:I" ],
emit => "leave",
outs => [ "frame", "M", "stack" ],
latency => 3,
......@@ -1120,7 +1120,7 @@ Leave => {
AddSP => {
state => "pinned",
in_reqs => [ "gp", "gp", "none", "esp", "gp" ],
out_reqs => [ "esp:I|S", "none" ],
out_reqs => [ "esp:I", "none" ],
ins => [ "base", "index", "mem", "stack", "size" ],
am => "source,binary",
emit => "addl %B",
......@@ -1132,7 +1132,7 @@ AddSP => {
SubSP => {
state => "pinned",
in_reqs => [ "gp", "gp", "none", "esp", "gp" ],
out_reqs => [ "esp:I|S", "gp", "none" ],
out_reqs => [ "esp:I", "gp", "none" ],
ins => [ "base", "index", "mem", "stack", "size" ],
am => "source,binary",
emit => "subl %B\n".
......
......@@ -4161,7 +4161,7 @@ static ir_node *gen_Start(ir_node *node)
be_make_start_mem(&start_mem, start, o++);
/* the stack pointer */
be_make_start_out(&start_val[REG_ESP], start, o++, &ia32_registers[REG_ESP], arch_register_req_type_ignore | arch_register_req_type_produces_sp);
be_make_start_out(&start_val[REG_ESP], start, o++, &ia32_registers[REG_ESP], arch_register_req_type_ignore);
/* function parameters in registers */
start_params_offset = o;
......
......@@ -1020,8 +1020,6 @@ sub generate_requirements {
foreach my $f (split(/|/, $flags)) {
if ($f eq "I") {
push(@req_type_mask, "arch_register_req_type_ignore");
} elsif ($f eq "S") {
push(@req_type_mask, "arch_register_req_type_produces_sp");
} elsif ($f eq "a") {
push(@req_type_mask, "arch_register_req_type_aligned");
} elsif ($f eq "2" or $f eq "4" or $f eq "8") {
......
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