Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Zwinkau
libfirm
Commits
8a40be44
Commit
8a40be44
authored
Aug 09, 2010
by
Matthias Braun
Browse files
cleanup spill code; assert that no wide values are used yet
[r27905]
parent
2b889c0b
Changes
3
Hide whitespace changes
Inline
Side-by-side
ir/be/beprefalloc.c
View file @
8a40be44
...
...
@@ -182,8 +182,9 @@ static const arch_register_req_t *get_default_req_current_cls(void)
struct
obstack
*
obst
=
get_irg_obstack
(
irg
);
arch_register_req_t
*
req
=
OALLOCZ
(
obst
,
arch_register_req_t
);
req
->
type
=
arch_register_req_type_normal
;
req
->
cls
=
cls
;
req
->
type
=
arch_register_req_type_normal
;
req
->
cls
=
cls
;
req
->
width
=
1
;
default_cls_req
=
req
;
}
...
...
ir/be/bespillbelady.c
View file @
8a40be44
...
...
@@ -72,19 +72,19 @@ DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
typedef
struct
loc_t
{
ir_node
*
node
;
unsigned
time
;
/**< A use time (see beuses.h). */
bool
spilled
;
/**<
the
value was already spilled on this path */
bool
spilled
;
/**< value was already spilled on this path */
}
loc_t
;
typedef
struct
_workset_t
{
int
len
;
/**< current length */
loc_t
vals
[
0
];
/**< inlined
array of the values/distances in this working set */
unsigned
len
;
/**< current length */
loc_t
vals
[
0
];
/**<
array of the values/distances in this working set */
}
workset_t
;
static
struct
obstack
obst
;
static
const
arch_register_class_t
*
cls
;
static
const
be_lv_t
*
lv
;
static
be_loopana_t
*
loop_ana
;
static
int
n_regs
;
static
unsigned
n_regs
;
static
workset_t
*
ws
;
/**< the main workset used while
processing a block. */
static
be_uses_t
*
uses
;
/**< env for the next-use magic */
...
...
@@ -103,19 +103,12 @@ static int remat_bonus = 10;
static
const
lc_opt_table_entry_t
options
[]
=
{
LC_OPT_ENT_BOOL
(
"movespills"
,
"try to move spills out of loops"
,
&
move_spills
),
LC_OPT_ENT_BOOL
(
"respectloopdepth"
,
"
exprimental (
outermost loop cutting
)
"
,
&
respectloopdepth
),
LC_OPT_ENT_BOOL
(
"improveknownpreds"
,
"
experimental (
known preds cutting
)
"
,
&
improve_known_preds
),
LC_OPT_ENT_BOOL
(
"respectloopdepth"
,
"outermost loop cutting"
,
&
respectloopdepth
),
LC_OPT_ENT_BOOL
(
"improveknownpreds"
,
"known preds cutting"
,
&
improve_known_preds
),
LC_OPT_ENT_INT
(
"rematbonus"
,
"give bonus to rematerialisable nodes"
,
&
remat_bonus
),
LC_OPT_LAST
};
static
int
loc_compare
(
const
void
*
a
,
const
void
*
b
)
{
const
loc_t
*
p
=
a
;
const
loc_t
*
q
=
b
;
return
p
->
time
-
q
->
time
;
}
/**
* Alloc a new workset on obstack @p ob with maximum size @p max
*/
...
...
@@ -160,8 +153,8 @@ static void workset_bulk_fill(workset_t *workset, int count, const loc_t *locs)
*/
static
void
workset_insert
(
workset_t
*
workset
,
ir_node
*
val
,
bool
spilled
)
{
loc_t
*
loc
;
int
i
;
loc_t
*
loc
;
unsigned
i
;
/* check for current regclass */
assert
(
arch_irn_consider_in_reg_alloc
(
cls
,
val
));
...
...
@@ -196,9 +189,9 @@ static void workset_clear(workset_t *workset)
/**
* Removes the value @p val from the workset if present.
*/
static
inline
void
workset_remove
(
workset_t
*
workset
,
ir_node
*
val
)
static
void
workset_remove
(
workset_t
*
workset
,
ir_node
*
val
)
{
int
i
;
unsigned
i
;
for
(
i
=
0
;
i
<
workset
->
len
;
++
i
)
{
if
(
workset
->
vals
[
i
].
node
==
val
)
{
workset
->
vals
[
i
]
=
workset
->
vals
[
--
workset
->
len
];
...
...
@@ -207,11 +200,9 @@ static inline void workset_remove(workset_t *workset, ir_node *val)
}
}
static
inline
const
loc_t
*
workset_contains
(
const
workset_t
*
ws
,
const
ir_node
*
val
)
static
const
loc_t
*
workset_contains
(
const
workset_t
*
ws
,
const
ir_node
*
val
)
{
int
i
;
unsigned
i
;
for
(
i
=
0
;
i
<
ws
->
len
;
++
i
)
{
if
(
ws
->
vals
[
i
].
node
==
val
)
return
&
ws
->
vals
[
i
];
...
...
@@ -220,22 +211,52 @@ static inline const loc_t *workset_contains(const workset_t *ws,
return
NULL
;
}
static
int
loc_compare
(
const
void
*
a
,
const
void
*
b
)
{
const
loc_t
*
p
=
a
;
const
loc_t
*
q
=
b
;
return
p
->
time
-
q
->
time
;
}
static
void
workset_sort
(
workset_t
*
workset
)
{
qsort
(
workset
->
vals
,
workset
->
len
,
sizeof
(
workset
->
vals
[
0
]),
loc_compare
);
}
static
inline
unsigned
workset_get_time
(
const
workset_t
*
workset
,
unsigned
idx
)
{
return
workset
->
vals
[
idx
].
time
;
}
static
inline
void
workset_set_time
(
workset_t
*
workset
,
unsigned
idx
,
unsigned
time
)
{
workset
->
vals
[
idx
].
time
=
time
;
}
static
inline
unsigned
workset_get_length
(
const
workset_t
*
workset
)
{
return
workset
->
len
;
}
static
inline
void
workset_set_length
(
workset_t
*
workset
,
unsigned
len
)
{
workset
->
len
=
len
;
}
static
inline
ir_node
*
workset_get_val
(
const
workset_t
*
workset
,
unsigned
idx
)
{
return
workset
->
vals
[
idx
].
node
;
}
/**
* Iterates over all values in the working set.
* @p ws The workset to iterate
* @p v A variable to put the current value in
* @p i An integer for internal use
*/
#define workset_foreach(ws, v, i) for (i=0; \
v=(i < ws->len) ? ws->vals[i].node : NULL, i < ws->len; \
++i)
#define workset_set_time(ws, i, t) (ws)->vals[i].time=t
#define workset_get_time(ws, i) (ws)->vals[i].time
#define workset_set_length(ws, length) (ws)->len = length
#define workset_get_length(ws) ((ws)->len)
#define workset_get_val(ws, i) ((ws)->vals[i].node)
#define workset_sort(ws) do { qsort((ws)->vals, (ws)->len, sizeof((ws)->vals[0]), loc_compare); } while(0)
#define workset_foreach(ws, v, i) \
for (i=0; v=(i < ws->len) ? ws->vals[i].node : NULL, i < ws->len; ++i)
typedef
struct
_block_info_t
{
...
...
@@ -243,20 +264,26 @@ typedef struct _block_info_t
workset_t
*
end_workset
;
}
block_info_t
;
static
block_info_t
*
new_block_info
(
void
)
{
return
OALLOCZ
(
&
obst
,
block_info_t
);
}
#define get_block_info(block) ((block_info_t *)get_irn_link(block))
#define set_block_info(block, info) set_irn_link(block, info)
static
inline
block_info_t
*
get_block_info
(
const
ir_node
*
block
)
{
return
get_irn_link
(
block
);
}
static
inline
void
set_block_info
(
ir_node
*
block
,
block_info_t
*
info
)
{
set_irn_link
(
block
,
info
);
}
/**
* @return The distance to the next use or 0 if irn has dont_spill flag set
*/
static
inline
unsigned
get_distance
(
ir_node
*
from
,
unsigned
from_step
,
const
ir_node
*
def
,
int
skip_from_uses
)
static
unsigned
get_distance
(
ir_node
*
from
,
unsigned
from_step
,
const
ir_node
*
def
,
int
skip_from_uses
)
{
be_next_use_t
use
;
unsigned
costs
;
...
...
@@ -301,7 +328,7 @@ static void displace(workset_t *new_vals, int is_usage)
int
len
;
int
spills_needed
;
int
demand
;
int
iter
;
unsigned
iter
;
/* 1. Identify the number of needed slots and the values to reload */
demand
=
0
;
...
...
@@ -464,7 +491,7 @@ static loc_t to_take_or_not_to_take(ir_node* first, ir_node *node,
next_use
=
be_get_next_use
(
uses
,
first
,
0
,
node
,
0
);
if
(
USES_IS_INFINITE
(
next_use
.
time
))
{
/
/
the nodes marked as live in shouldn't be dead, so it must be a phi
/
*
the nodes marked as live in shouldn't be dead, so it must be a phi
*/
assert
(
is_Phi
(
node
));
loc
.
time
=
USES_INFINITY
;
DB
((
dbg
,
DBG_START
,
" %+F not taken (dead)
\n
"
,
node
));
...
...
@@ -512,7 +539,10 @@ static void decide_start_workset(const ir_node *block)
loc_t
loc
;
loc_t
*
starters
;
loc_t
*
delayed
;
int
i
,
len
,
ws_count
;
unsigned
len
;
unsigned
i
;
int
in
;
unsigned
ws_count
;
int
free_slots
,
free_pressure_slots
;
unsigned
pressure
;
int
arity
;
...
...
@@ -523,15 +553,15 @@ static void decide_start_workset(const ir_node *block)
arity
=
get_irn_arity
(
block
);
pred_worksets
=
ALLOCAN
(
workset_t
*
,
arity
);
all_preds_known
=
true
;
for
(
i
=
0
;
i
<
arity
;
++
i
)
{
ir_node
*
pred_block
=
get_Block_cfgpred_block
(
block
,
i
);
for
(
i
n
=
0
;
i
n
<
arity
;
++
i
n
)
{
ir_node
*
pred_block
=
get_Block_cfgpred_block
(
block
,
i
n
);
block_info_t
*
pred_info
=
get_block_info
(
pred_block
);
if
(
pred_info
==
NULL
)
{
pred_worksets
[
i
]
=
NULL
;
all_preds_known
=
false
;
pred_worksets
[
i
n
]
=
NULL
;
all_preds_known
=
false
;
}
else
{
pred_worksets
[
i
]
=
pred_info
->
end_workset
;
pred_worksets
[
i
n
]
=
pred_info
->
end_workset
;
}
}
...
...
@@ -570,8 +600,8 @@ static void decide_start_workset(const ir_node *block)
}
/* check all Live-Ins */
be_lv_foreach
(
lv
,
block
,
be_lv_state_in
,
i
)
{
ir_node
*
node
=
be_lv_get_irn
(
lv
,
block
,
i
);
be_lv_foreach
(
lv
,
block
,
be_lv_state_in
,
i
n
)
{
ir_node
*
node
=
be_lv_get_irn
(
lv
,
block
,
i
n
);
unsigned
available
;
if
(
all_preds_known
)
{
...
...
@@ -602,6 +632,7 @@ static void decide_start_workset(const ir_node *block)
DB
((
dbg
,
DBG_START
,
"Loop pressure %d, taking %d delayed vals
\n
"
,
pressure
,
free_slots
));
if
(
free_slots
>
0
)
{
int
i
;
qsort
(
delayed
,
ARR_LEN
(
delayed
),
sizeof
(
delayed
[
0
]),
loc_compare
);
for
(
i
=
0
;
i
<
ARR_LEN
(
delayed
)
&&
free_slots
>
0
;
++
i
)
{
...
...
@@ -639,7 +670,8 @@ static void decide_start_workset(const ir_node *block)
/* spill phis (the actual phis not just their values) that are in this block
* but not in the start workset */
for
(
i
=
ARR_LEN
(
delayed
)
-
1
;
i
>=
0
;
--
i
)
{
len
=
ARR_LEN
(
delayed
);
for
(
i
=
0
;
i
<
len
;
++
i
)
{
ir_node
*
node
=
delayed
[
i
].
node
;
if
(
node
==
NULL
||
!
is_Phi
(
node
)
||
get_nodes_block
(
node
)
!=
block
)
continue
;
...
...
@@ -653,7 +685,7 @@ static void decide_start_workset(const ir_node *block)
qsort
(
starters
,
ARR_LEN
(
starters
),
sizeof
(
starters
[
0
]),
loc_compare
);
/* Copy the best ones from starters to start workset */
ws_count
=
MIN
(
ARR_LEN
(
starters
),
n_regs
);
ws_count
=
MIN
(
(
unsigned
)
ARR_LEN
(
starters
),
n_regs
);
workset_clear
(
ws
);
workset_bulk_fill
(
ws
,
ws_count
,
starters
);
...
...
@@ -722,11 +754,11 @@ static void decide_start_workset(const ir_node *block)
*/
static
void
process_block
(
ir_node
*
block
)
{
workset_t
*
new_vals
;
ir_node
*
irn
;
int
iter
;
block_info_t
*
block_info
;
int
arity
;
workset_t
*
new_vals
;
ir_node
*
irn
;
unsigned
iter
;
block_info_t
*
block_info
;
int
arity
;
/* no need to process a block twice */
assert
(
get_block_info
(
block
)
==
NULL
);
...
...
@@ -797,6 +829,7 @@ static void process_block(ir_node *block)
/* allocate all values _defined_ by this instruction */
workset_clear
(
new_vals
);
be_foreach_definition
(
irn
,
cls
,
value
,
assert
(
req_
->
width
==
1
);
workset_insert
(
new_vals
,
value
,
false
);
);
displace
(
new_vals
,
0
);
...
...
@@ -808,8 +841,7 @@ static void process_block(ir_node *block)
block_info
->
end_workset
=
workset_clone
(
ws
);
DB
((
dbg
,
DBG_WSETS
,
"End workset for %+F:
\n
"
,
block
));
workset_foreach
(
ws
,
irn
,
iter
)
DB
((
dbg
,
DBG_WSETS
,
" %+F (%u)
\n
"
,
irn
,
workset_get_time
(
ws
,
iter
)));
DB
((
dbg
,
DBG_WSETS
,
" %+F (%u)
\n
"
,
irn
,
workset_get_time
(
ws
,
iter
)));
}
/**
...
...
@@ -819,10 +851,10 @@ static void process_block(ir_node *block)
*/
static
void
fix_block_borders
(
ir_node
*
block
,
void
*
data
)
{
workset_t
*
start_workset
;
int
arity
;
int
i
;
int
iter
;
workset_t
*
start_workset
;
int
arity
;
int
i
;
unsigned
iter
;
(
void
)
data
;
DB
((
dbg
,
DBG_FIX
,
"
\n
"
));
...
...
@@ -846,7 +878,7 @@ static void fix_block_borders(ir_node *block, void *data)
/* spill all values not used anymore */
workset_foreach
(
pred_end_workset
,
node
,
iter
)
{
ir_node
*
n2
;
int
iter2
;
unsigned
iter2
;
bool
found
=
false
;
workset_foreach
(
start_workset
,
n2
,
iter2
)
{
if
(
n2
==
node
)
{
...
...
ir/be/bespilldaemel.c
View file @
8a40be44
...
...
@@ -24,9 +24,9 @@
* @date 20.09.2005
* @version $Id: bespillbelady.c 13913 2007-05-18 12:48:56Z matze $
* @brief
* This implements a naive spilling algorithm. It is designed to produce
similar
* effects to the spill decisions produced by traditional graph
coloring
* register allocators that spill while they are coloring the graph.
* This implements a naive spilling algorithm. It is designed to produce
*
similar
effects to the spill decisions produced by traditional graph
*
coloring
register allocators that spill while they are coloring the graph.
*
* This spiller walks over all blocks and looks for places with too high
* register pressure where it spills the values that are cheapest to spill.
...
...
@@ -101,8 +101,6 @@ static double get_spill_costs(ir_node *node)
}
}
/* TODO cache costs? */
return
costs
;
}
...
...
@@ -153,6 +151,7 @@ static void do_spilling(ir_nodeset_t *live_nodes, ir_node *node)
ir_node
*
value
;
be_foreach_definition
(
node
,
cls
,
value
,
assert
(
req_
->
width
==
1
);
/* no support for wide-values yet */
++
values_defined
;
);
...
...
@@ -167,7 +166,7 @@ static void do_spilling(ir_nodeset_t *live_nodes, ir_node *node)
}
/* we can reuse all reloaded values for the defined values, but we might
need even more registers */
*
need even more registers */
if
(
values_defined
>
free_regs_needed
)
free_regs_needed
=
values_defined
;
...
...
@@ -198,15 +197,14 @@ static void do_spilling(ir_nodeset_t *live_nodes, ir_node *node)
/* spill cheapest ones */
cand_idx
=
0
;
while
(
spills_needed
>
0
)
{
bool
is_use
=
false
;
spill_candidate_t
*
candidate
;
ir_node
*
cand_node
;
int
is_use
;
if
(
cand_idx
>=
n_live_nodes
)
{
panic
(
"can't spill enough values for node %+F"
,
node
);
}
candidate
=
&
candidates
[
cand_idx
];
cand_node
=
candidate
->
node
;
++
cand_idx
;
...
...
@@ -215,11 +213,10 @@ static void do_spilling(ir_nodeset_t *live_nodes, ir_node *node)
continue
;
/* make sure the node is not an argument of the instruction */
is_use
=
0
;
for
(
i
=
0
;
i
<
arity
;
++
i
)
{
ir_node
*
in
=
get_irn_n
(
node
,
i
);
if
(
in
==
cand_node
)
{
is_use
=
1
;
is_use
=
true
;
break
;
}
}
...
...
@@ -239,9 +236,8 @@ static void do_spilling(ir_nodeset_t *live_nodes, ir_node *node)
static
void
remove_defs
(
ir_node
*
node
,
ir_nodeset_t
*
nodeset
)
{
ir_node
*
value
;
/* You should better break out of your loop when hitting the first phi
* function. */
assert
(
!
is_Phi
(
node
)
&&
"liveness_transfer produces invalid results for phi nodes"
);
/* You must break out of your loop when hitting the first phi function. */
assert
(
!
is_Phi
(
node
));
be_foreach_definition
(
node
,
cls
,
value
,
ir_nodeset_remove
(
nodeset
,
value
);
...
...
@@ -319,8 +315,7 @@ static void spill_block(ir_node *block, void *data)
/* until now only the values of some phis have been spilled the phis itself
* are still there and occupy registers, so we need to count them and might
* have to spill some of them.
*/
* have to spill some of them. */
n_phi_values_spilled
=
0
;
sched_foreach
(
block
,
node
)
{
if
(
!
is_Phi
(
node
))
...
...
@@ -359,7 +354,6 @@ static void spill_block(ir_node *block, void *data)
static
void
be_spill_daemel
(
ir_graph
*
irg
,
const
arch_register_class_t
*
new_cls
)
{
n_regs
=
new_cls
->
n_regs
-
be_put_ignore_regs
(
irg
,
new_cls
,
NULL
);
if
(
n_regs
==
0
)
return
;
...
...
@@ -375,12 +369,9 @@ static void be_spill_daemel(ir_graph *irg, const arch_register_class_t *new_cls)
irg_block_walk_graph
(
irg
,
spill_block
,
NULL
,
NULL
);
bitset_free
(
spilled_nodes
);
spilled_nodes
=
NULL
;
be_insert_spills_reloads
(
spill_env
);
be_delete_spill_env
(
spill_env
);
spill_env
=
NULL
;
}
BE_REGISTER_MODULE_CONSTRUCTOR
(
be_init_daemelspill
);
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment