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
e51bd960
Commit
e51bd960
authored
Jan 07, 2007
by
Michael Beck
Browse files
BugFix: find_constant_entity() now checks global entities to be constant
Memory disambiguator calls added [r8502]
parent
e059f092
Changes
2
Hide whitespace changes
Inline
Side-by-side
ir/opt/ldstopt.c
View file @
e51bd960
...
...
@@ -5,7 +5,7 @@
* Author: Michael Beck
* Created:
* CVS-ID: $Id$
* Copyright: (c) 1998-200
4
Universitt Karlsruhe
* Copyright: (c) 1998-200
7
Universitt Karlsruhe
* Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
*/
#ifdef HAVE_CONFIG_H
...
...
@@ -39,6 +39,7 @@
#include
"iredges.h"
#include
"irtools.h"
#include
"opt_polymorphy.h"
#include
"irmemory.h"
#ifdef DO_CACHEOPT
#include
"cacheopt/cachesim.h"
...
...
@@ -50,47 +51,47 @@
#define MAX_PROJ IMAX(pn_Load_max, pn_Store_max)
enum
changes_t
{
DF_CHANGED
=
1
,
/**< data flow changed */
CF_CHANGED
=
2
,
/**< control flow changed */
DF_CHANGED
=
1
,
/**< data flow changed */
CF_CHANGED
=
2
,
/**< control flow changed */
};
/**
* walker environment
*/
typedef
struct
_walk_env_t
{
struct
obstack
obst
;
/**< list of all stores */
unsigned
changes
;
/**< a bitmask of graph changes */
struct
obstack
obst
;
/**< list of all stores */
unsigned
changes
;
/**< a bitmask of graph changes */
}
walk_env_t
;
/**
* flags for Load/Store
*/
enum
ldst_flags_t
{
LDST_VISITED
=
1
/**< if set, this Load/Store is already visited */
LDST_VISITED
=
1
/**< if set, this Load/Store is already visited */
};
/** A Load/Store info. */
typedef
struct
_ldst_info_t
{
ir_node
*
projs
[
MAX_PROJ
];
/**< list of Proj's of this node */
ir_node
*
exc_block
;
/**< the exception block if available */
int
exc_idx
;
/**< predecessor index in the exception block */
unsigned
flags
;
/**< flags */
unsigned
visited
;
/**< visited counter for breaking loops */
ir_node
*
projs
[
MAX_PROJ
];
/**< list of Proj's of this node */
ir_node
*
exc_block
;
/**< the exception block if available */
int
exc_idx
;
/**< predecessor index in the exception block */
unsigned
flags
;
/**< flags */
unsigned
visited
;
/**< visited counter for breaking loops */
}
ldst_info_t
;
/**
* flags for control flow.
*/
enum
block_flags_t
{
BLOCK_HAS_COND
=
1
,
/**< Block has conditional control flow */
BLOCK_HAS_EXC
=
2
/**< Block has exceptional control flow */
BLOCK_HAS_COND
=
1
,
/**< Block has conditional control flow */
BLOCK_HAS_EXC
=
2
/**< Block has exceptional control flow */
};
/**
* a Block info.
*/
typedef
struct
_block_info_t
{
unsigned
flags
;
/**< flags for the block */
unsigned
flags
;
/**< flags for the block */
}
block_info_t
;
/** the master visited flag for loop detection. */
...
...
@@ -104,54 +105,49 @@ static unsigned master_visited = 0;
* get the Load/Store info of a node
*/
static
ldst_info_t
*
get_ldst_info
(
ir_node
*
node
,
walk_env_t
*
env
)
{
ldst_info_t
*
info
=
get_irn_link
(
node
);
ldst_info_t
*
info
=
get_irn_link
(
node
);
if
(
!
info
)
{
info
=
obstack_alloc
(
&
env
->
obst
,
sizeof
(
*
info
));
memset
(
info
,
0
,
sizeof
(
*
info
));
set_irn_link
(
node
,
info
);
}
return
info
;
}
if
(
!
info
)
{
info
=
obstack_alloc
(
&
env
->
obst
,
sizeof
(
*
info
));
memset
(
info
,
0
,
sizeof
(
*
info
));
set_irn_link
(
node
,
info
);
}
return
info
;
}
/* get_ldst_info */
/**
* get the Block info of a node
*/
static
block_info_t
*
get_block_info
(
ir_node
*
node
,
walk_env_t
*
env
)
{
block_info_t
*
info
=
get_irn_link
(
node
);
if
(
!
info
)
{
info
=
obstack_alloc
(
&
env
->
obst
,
sizeof
(
*
info
));
static
block_info_t
*
get_block_info
(
ir_node
*
node
,
walk_env_t
*
env
)
{
block_info_t
*
info
=
get_irn_link
(
node
);
memset
(
info
,
0
,
sizeof
(
*
info
));
set_irn_link
(
node
,
info
);
}
return
info
;
}
if
(
!
info
)
{
info
=
obstack_alloc
(
&
env
->
obst
,
sizeof
(
*
info
));
memset
(
info
,
0
,
sizeof
(
*
info
));
set_irn_link
(
node
,
info
);
}
return
info
;
}
/* get_block_info */
/**
* update the projection info for a Load/Store
*/
static
unsigned
update_projs
(
ldst_info_t
*
info
,
ir_node
*
proj
)
{
long
nr
=
get_Proj_proj
(
proj
);
long
nr
=
get_Proj_proj
(
proj
);
assert
(
0
<=
nr
&&
nr
<=
MAX_PROJ
&&
"Wrong proj from LoadStore"
);
assert
(
0
<=
nr
&&
nr
<=
MAX_PROJ
&&
"Wrong proj from LoadStore"
);
if
(
info
->
projs
[
nr
])
{
/* there is already one, do CSE */
exchange
(
proj
,
info
->
projs
[
nr
]);
return
DF_CHANGED
;
}
else
{
info
->
projs
[
nr
]
=
proj
;
return
0
;
}
}
if
(
info
->
projs
[
nr
])
{
/* there is already one, do CSE */
exchange
(
proj
,
info
->
projs
[
nr
]);
return
DF_CHANGED
;
}
else
{
info
->
projs
[
nr
]
=
proj
;
return
0
;
}
}
/* update_projs */
/**
* update the exception block info for a Load/Store node.
...
...
@@ -162,12 +158,12 @@ static unsigned update_projs(ldst_info_t *info, ir_node *proj)
*/
static
unsigned
update_exc
(
ldst_info_t
*
info
,
ir_node
*
block
,
int
pos
)
{
assert
(
info
->
exc_block
==
NULL
&&
"more than one exception block found"
);
assert
(
info
->
exc_block
==
NULL
&&
"more than one exception block found"
);
info
->
exc_block
=
block
;
info
->
exc_idx
=
pos
;
return
0
;
}
info
->
exc_block
=
block
;
info
->
exc_idx
=
pos
;
return
0
;
}
/* update_exc */
/** Return the number of uses of an address node */
#define get_irn_n_uses(adr) get_irn_n_edges(adr)
...
...
@@ -179,166 +175,169 @@ static unsigned update_exc(ldst_info_t *info, ir_node *block, int pos)
*/
static
void
collect_nodes
(
ir_node
*
node
,
void
*
env
)
{
ir_op
*
op
=
get_irn_op
(
node
);
ir_node
*
pred
,
*
blk
,
*
pred_blk
;
ldst_info_t
*
ldst_info
;
walk_env_t
*
wenv
=
env
;
if
(
op
==
op_Proj
)
{
ir_node
*
adr
;
ir_op
*
op
;
pred
=
get_Proj_pred
(
node
);
op
=
get_irn_op
(
pred
);
if
(
op
==
op_Load
)
{
ldst_info
=
get_ldst_info
(
pred
,
wenv
);
wenv
->
changes
|=
update_projs
(
ldst_info
,
node
);
if
((
ldst_info
->
flags
&
LDST_VISITED
)
==
0
)
{
adr
=
get_Load_ptr
(
pred
);
ldst_info
->
flags
|=
LDST_VISITED
;
}
/*
* Place the Proj's to the same block as the
* predecessor Load. This is always ok and prevents
* "non-SSA" form after optimizations if the Proj
* is in a wrong block.
*/
blk
=
get_nodes_block
(
node
);
pred_blk
=
get_nodes_block
(
pred
);
if
(
blk
!=
pred_blk
)
{
wenv
->
changes
|=
DF_CHANGED
;
set_nodes_block
(
node
,
pred_blk
);
}
}
else
if
(
op
==
op_Store
)
{
ldst_info
=
get_ldst_info
(
pred
,
wenv
);
wenv
->
changes
|=
update_projs
(
ldst_info
,
node
);
if
((
ldst_info
->
flags
&
LDST_VISITED
)
==
0
)
{
adr
=
get_Store_ptr
(
pred
);
ldst_info
->
flags
|=
LDST_VISITED
;
}
/*
* Place the Proj's to the same block as the
* predecessor Store. This is always ok and prevents
* "non-SSA" form after optimizations if the Proj
* is in a wrong block.
*/
blk
=
get_nodes_block
(
node
);
pred_blk
=
get_nodes_block
(
pred
);
if
(
blk
!=
pred_blk
)
{
wenv
->
changes
|=
DF_CHANGED
;
set_nodes_block
(
node
,
pred_blk
);
}
}
}
else
if
(
op
==
op_Block
)
{
int
i
;
for
(
i
=
get_Block_n_cfgpreds
(
node
)
-
1
;
i
>=
0
;
--
i
)
{
ir_node
*
pred_block
;
block_info_t
*
bl_info
;
pred
=
skip_Proj
(
get_Block_cfgpred
(
node
,
i
));
/* ignore Bad predecessors, they will be removed later */
if
(
is_Bad
(
pred
))
continue
;
pred_block
=
get_nodes_block
(
pred
);
bl_info
=
get_block_info
(
pred_block
,
wenv
);
if
(
is_fragile_op
(
pred
))
bl_info
->
flags
|=
BLOCK_HAS_EXC
;
else
if
(
is_irn_forking
(
pred
))
bl_info
->
flags
|=
BLOCK_HAS_COND
;
if
(
get_irn_op
(
pred
)
==
op_Load
||
get_irn_op
(
pred
)
==
op_Store
)
{
ldst_info
=
get_ldst_info
(
pred
,
wenv
);
wenv
->
changes
|=
update_exc
(
ldst_info
,
node
,
i
);
}
}
}
}
ir_op
*
op
=
get_irn_op
(
node
);
ir_node
*
pred
,
*
blk
,
*
pred_blk
;
ldst_info_t
*
ldst_info
;
walk_env_t
*
wenv
=
env
;
if
(
op
==
op_Proj
)
{
ir_node
*
adr
;
ir_op
*
op
;
pred
=
get_Proj_pred
(
node
);
op
=
get_irn_op
(
pred
);
if
(
op
==
op_Load
)
{
ldst_info
=
get_ldst_info
(
pred
,
wenv
);
wenv
->
changes
|=
update_projs
(
ldst_info
,
node
);
if
((
ldst_info
->
flags
&
LDST_VISITED
)
==
0
)
{
adr
=
get_Load_ptr
(
pred
);
ldst_info
->
flags
|=
LDST_VISITED
;
}
/*
* Place the Proj's to the same block as the
* predecessor Load. This is always ok and prevents
* "non-SSA" form after optimizations if the Proj
* is in a wrong block.
*/
blk
=
get_nodes_block
(
node
);
pred_blk
=
get_nodes_block
(
pred
);
if
(
blk
!=
pred_blk
)
{
wenv
->
changes
|=
DF_CHANGED
;
set_nodes_block
(
node
,
pred_blk
);
}
}
else
if
(
op
==
op_Store
)
{
ldst_info
=
get_ldst_info
(
pred
,
wenv
);
wenv
->
changes
|=
update_projs
(
ldst_info
,
node
);
if
((
ldst_info
->
flags
&
LDST_VISITED
)
==
0
)
{
adr
=
get_Store_ptr
(
pred
);
ldst_info
->
flags
|=
LDST_VISITED
;
}
/*
* Place the Proj's to the same block as the
* predecessor Store. This is always ok and prevents
* "non-SSA" form after optimizations if the Proj
* is in a wrong block.
*/
blk
=
get_nodes_block
(
node
);
pred_blk
=
get_nodes_block
(
pred
);
if
(
blk
!=
pred_blk
)
{
wenv
->
changes
|=
DF_CHANGED
;
set_nodes_block
(
node
,
pred_blk
);
}
}
}
else
if
(
op
==
op_Block
)
{
int
i
;
for
(
i
=
get_Block_n_cfgpreds
(
node
)
-
1
;
i
>=
0
;
--
i
)
{
ir_node
*
pred_block
;
block_info_t
*
bl_info
;
pred
=
skip_Proj
(
get_Block_cfgpred
(
node
,
i
));
/* ignore Bad predecessors, they will be removed later */
if
(
is_Bad
(
pred
))
continue
;
pred_block
=
get_nodes_block
(
pred
);
bl_info
=
get_block_info
(
pred_block
,
wenv
);
if
(
is_fragile_op
(
pred
))
bl_info
->
flags
|=
BLOCK_HAS_EXC
;
else
if
(
is_irn_forking
(
pred
))
bl_info
->
flags
|=
BLOCK_HAS_COND
;
if
(
get_irn_op
(
pred
)
==
op_Load
||
get_irn_op
(
pred
)
==
op_Store
)
{
ldst_info
=
get_ldst_info
(
pred
,
wenv
);
wenv
->
changes
|=
update_exc
(
ldst_info
,
node
,
i
);
}
}
}
}
/* collect_nodes */
/**
* Returns an entity if the address ptr points to a constant one.
*
* @param ptr the address
*
* @return an entity or NULL
*/
static
ir_entity
*
find_constant_entity
(
ir_node
*
ptr
)
{
for
(;;)
{
ir_op
*
op
=
get_irn_op
(
ptr
);
if
(
op
==
op_SymConst
&&
(
get_SymConst_kind
(
ptr
)
==
symconst_addr_ent
))
{
return
get_SymConst_entity
(
ptr
);
}
else
if
(
op
==
op_Sel
)
{
ir_entity
*
ent
=
get_Sel_entity
(
ptr
);
ir_type
*
tp
=
get_entity_owner
(
ent
);
/* Do not fiddle with polymorphism. */
if
(
is_Class_type
(
get_entity_owner
(
ent
))
&&
((
get_entity_n_overwrites
(
ent
)
!=
0
)
||
(
get_entity_n_overwrittenby
(
ent
)
!=
0
)
)
)
return
NULL
;
if
(
variability_constant
==
get_entity_variability
(
ent
))
return
ent
;
if
(
is_Array_type
(
tp
))
{
/* check bounds */
int
i
,
n
;
for
(
i
=
0
,
n
=
get_Sel_n_indexs
(
ptr
);
i
<
n
;
++
i
)
{
ir_node
*
bound
;
tarval
*
tlower
,
*
tupper
;
ir_node
*
index
=
get_Sel_index
(
ptr
,
i
);
tarval
*
tv
=
computed_value
(
index
);
/* check if the index is constant */
if
(
tv
==
tarval_bad
)
return
NULL
;
bound
=
get_array_lower_bound
(
tp
,
i
);
tlower
=
computed_value
(
bound
);
bound
=
get_array_upper_bound
(
tp
,
i
);
tupper
=
computed_value
(
bound
);
if
(
tlower
==
tarval_bad
||
tupper
==
tarval_bad
)
return
NULL
;
if
(
tarval_cmp
(
tv
,
tlower
)
&
pn_Cmp_Lt
)
return
NULL
;
if
(
tarval_cmp
(
tupper
,
tv
)
&
pn_Cmp_Lt
)
return
NULL
;
/* ok, bounds check finished */
}
}
/* try next */
ptr
=
get_Sel_ptr
(
ptr
);
}
else
return
NULL
;
}
}
for
(;;)
{
ir_op
*
op
=
get_irn_op
(
ptr
);
if
(
op
==
op_SymConst
&&
(
get_SymConst_kind
(
ptr
)
==
symconst_addr_ent
))
{
ir_entity
*
ent
=
get_SymConst_entity
(
ptr
);
if
(
variability_constant
==
get_entity_variability
(
ent
))
return
ent
;
return
NULL
;
}
else
if
(
op
==
op_Sel
)
{
ir_entity
*
ent
=
get_Sel_entity
(
ptr
);
ir_type
*
tp
=
get_entity_owner
(
ent
);
/* Do not fiddle with polymorphism. */
if
(
is_Class_type
(
get_entity_owner
(
ent
))
&&
((
get_entity_n_overwrites
(
ent
)
!=
0
)
||
(
get_entity_n_overwrittenby
(
ent
)
!=
0
)
)
)
return
NULL
;
if
(
is_Array_type
(
tp
))
{
/* check bounds */
int
i
,
n
;
for
(
i
=
0
,
n
=
get_Sel_n_indexs
(
ptr
);
i
<
n
;
++
i
)
{
ir_node
*
bound
;
tarval
*
tlower
,
*
tupper
;
ir_node
*
index
=
get_Sel_index
(
ptr
,
i
);
tarval
*
tv
=
computed_value
(
index
);
/* check if the index is constant */
if
(
tv
==
tarval_bad
)
return
NULL
;
bound
=
get_array_lower_bound
(
tp
,
i
);
tlower
=
computed_value
(
bound
);
bound
=
get_array_upper_bound
(
tp
,
i
);
tupper
=
computed_value
(
bound
);
if
(
tlower
==
tarval_bad
||
tupper
==
tarval_bad
)
return
NULL
;
if
(
tarval_cmp
(
tv
,
tlower
)
&
pn_Cmp_Lt
)
return
NULL
;
if
(
tarval_cmp
(
tupper
,
tv
)
&
pn_Cmp_Lt
)
return
NULL
;
/* ok, bounds check finished */
}
}
if
(
variability_constant
==
get_entity_variability
(
ent
))
return
ent
;
/* try next */
ptr
=
get_Sel_ptr
(
ptr
);
}
else
return
NULL
;
}
}
/* find_constant_entity */
/**
* Return the Selection index of a Sel node from dimension n
*/
static
long
get_Sel_array_index_long
(
ir_node
*
n
,
int
dim
)
{
ir_node
*
index
=
get_Sel_index
(
n
,
dim
);
assert
(
get_irn_op
(
index
)
==
op_Const
);
return
get_tarval_long
(
get_Const_tarval
(
index
));
}
ir_node
*
index
=
get_Sel_index
(
n
,
dim
);
assert
(
get_irn_op
(
index
)
==
op_Const
);
return
get_tarval_long
(
get_Const_tarval
(
index
));
}
/* get_Sel_array_index_long */
/**
* Returns the accessed component graph path for an
...
...
@@ -349,44 +348,43 @@ static long get_Sel_array_index_long(ir_node *n, int dim) {
* of the address
*/
static
compound_graph_path
*
rec_get_accessed_path
(
ir_node
*
ptr
,
int
depth
)
{
compound_graph_path
*
res
=
NULL
;
ir_entity
*
root
,
*
field
;
int
path_len
,
pos
;
if
(
get_irn_op
(
ptr
)
==
op_SymConst
)
{
/* a SymConst. If the depth is 0, this is an access to a global
* entity and we don't need a component path, else we know
* at least it's length.
*/
assert
(
get_SymConst_kind
(
ptr
)
==
symconst_addr_ent
);
root
=
get_SymConst_entity
(
ptr
);
res
=
(
depth
==
0
)
?
NULL
:
new_compound_graph_path
(
get_entity_type
(
root
),
depth
);
}
else
{
assert
(
get_irn_op
(
ptr
)
==
op_Sel
);
/* it's a Sel, go up until we find the root */
res
=
rec_get_accessed_path
(
get_Sel_ptr
(
ptr
),
depth
+
1
);
/* fill up the step in the path at the current position */
field
=
get_Sel_entity
(
ptr
);
path_len
=
get_compound_graph_path_length
(
res
);
pos
=
path_len
-
depth
-
1
;
set_compound_graph_path_node
(
res
,
pos
,
field
);
if
(
is_Array_type
(
get_entity_owner
(
field
)))
{
assert
(
get_Sel_n_indexs
(
ptr
)
==
1
&&
"multi dim arrays not implemented"
);
set_compound_graph_path_array_index
(
res
,
pos
,
get_Sel_array_index_long
(
ptr
,
0
));
}
}
return
res
;
}
compound_graph_path
*
res
=
NULL
;
ir_entity
*
root
,
*
field
;
int
path_len
,
pos
;
if
(
get_irn_op
(
ptr
)
==
op_SymConst
)
{
/* a SymConst. If the depth is 0, this is an access to a global
* entity and we don't need a component path, else we know
* at least it's length.
*/
assert
(
get_SymConst_kind
(
ptr
)
==
symconst_addr_ent
);
root
=
get_SymConst_entity
(
ptr
);
res
=
(
depth
==
0
)
?
NULL
:
new_compound_graph_path
(
get_entity_type
(
root
),
depth
);
}
else
{
assert
(
get_irn_op
(
ptr
)
==
op_Sel
);
/* it's a Sel, go up until we find the root */
res
=
rec_get_accessed_path
(
get_Sel_ptr
(
ptr
),
depth
+
1
);
/* fill up the step in the path at the current position */
field
=
get_Sel_entity
(
ptr
);
path_len
=
get_compound_graph_path_length
(
res
);
pos
=
path_len
-
depth
-
1
;
set_compound_graph_path_node
(
res
,
pos
,
field
);
if
(
is_Array_type
(
get_entity_owner
(
field
)))
{
assert
(
get_Sel_n_indexs
(
ptr
)
==
1
&&
"multi dim arrays not implemented"
);
set_compound_graph_path_array_index
(
res
,
pos
,
get_Sel_array_index_long
(
ptr
,
0
));
}
}
return
res
;
}
/* rec_get_accessed_path */
/** Returns an access path or NULL. The access path is only
* valid, if the graph is in phase_high and _no_ address computation is used.
*/
static
compound_graph_path
*
get_accessed_path
(
ir_node
*
ptr
)
{
return
rec_get_accessed_path
(
ptr
,
0
);
}
return
rec_get_accessed_path
(
ptr
,
0
);
}
/* get_accessed_path */
/* forward */
static
void
reduce_adr_usage
(
ir_node
*
ptr
);
...
...
@@ -395,482 +393,507 @@ static void reduce_adr_usage(ir_node *ptr);
* Update a Load that may lost it's usage.
*/
static
void
handle_load_update
(
ir_node
*
load
)
{
ldst_info_t
*
info
=
get_irn_link
(
load
);
ldst_info_t
*
info
=
get_irn_link
(
load
);
/* do NOT touch volatile loads for now */
if
(
get_Load_volatility
(
load
)
==
volatility_is_volatile
)
return
;
/* do NOT touch volatile loads for now */
if
(
get_Load_volatility
(
load
)
==
volatility_is_volatile
)
return
;
if
(
!
info
->
projs
[
pn_Load_res
]
&&
!
info
->
projs
[
pn_Load_X_except
])
{
ir_node
*
ptr
=
get_Load_ptr
(
load
);
ir_node
*
mem
=
get_Load_mem
(
load
);
if
(
!
info
->
projs
[
pn_Load_res
]
&&
!
info
->
projs
[
pn_Load_X_except
])
{
ir_node
*
ptr
=
get_Load_ptr
(
load
);
ir_node
*
mem
=
get_Load_mem
(
load
);
/* a Load which value is neither used nor exception checked, remove it */
exchange
(
info
->
projs
[
pn_Load_M
],
mem
);
exchange
(
load
,
new_Bad
());
reduce_adr_usage
(
ptr
);
}
}
/* a Load which value is neither used nor exception checked, remove it */
exchange
(
info
->
projs
[
pn_Load_M
],
mem
);
exchange
(
load
,
new_Bad
());
reduce_adr_usage
(
ptr
);
}
}
/* handle_load_update */
/**
* A Use of an address node is vanished. Check if this was a Proj
* node and update the counters.
*/
static
void
reduce_adr_usage
(
ir_node
*
ptr
)
{
if
(
is_Proj
(
ptr
))
{
if
(
get_irn_n_edges
(
ptr
)
<=
0
)
{
/* this Proj is dead now */
ir_node
*
pred
=
get_Proj_pred
(
ptr
);
opcode
code
=
get_irn_opcode
(
pred
);
if
(
code
==
iro_Load
)
{
ldst_info_t
*
info
=
get_irn_link
(
pred
);
info
->
projs
[
get_Proj_proj
(
ptr
)]
=
NULL
;
/* this node lost it's result proj, handle that */
handle_load_update
(
pred
);
}
}