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

rework const/pure/has_loop function attributes, cleanup funccall ana

- We have no_write, pure and terminates now (terminates instead of
  has_loop means that more flags is more specific information, so the
  fixpoint algos are less confusing)
- funccall ana also detects noreturn attribute now (but isn't optimizing
  it)
parent 1fa46d66
......@@ -221,39 +221,35 @@ typedef enum cond_jmp_predicate {
typedef enum mtp_additional_properties {
/** No additional properties */
mtp_no_property = 0,
/** This method does not access memory and calculates its return values
* solely from its parameters. The only observable effect of a const
* function must be its return value. So they must not exhibit infinite
* loops or wait for user input. The return value must not depend on any
* global variables/state.
* GCC: __attribute__((const)). */
mtp_property_const = 1u << 0,
/** This method does not write to memory and calculates its return values
* solely from its parameters and the memory they points to (or global
* vars). The only observable effect of a const function must be its return
* value. So they must not exhibit infinite loops or wait for user input.
* GCC: __attribute__((pure)). */
/** This method does not change any memory known to the rest of the
* program. */
mtp_property_no_write = 1u << 0,
/** The behaviour of the method does not depend on any global/external
* state. This mostly means that no waiting/reading of user input
* is performed, no global variables read, or pointers to memory visible
* outside of the function dereferenced. The result of the function
* solely depends on its arguments. */
mtp_property_pure = 1u << 1,
/** This method never returns. The method may for example abort or exit the
* program or contain an infinite loop).
* GCC: __attribute__((noreturn)). */
mtp_property_noreturn = 1u << 2,
/** The function is guaranteed not to end in an endless and to not abort
* the program. */
mtp_property_terminates = 1u << 3,
/** This method cannot throw an exception. GCC: __attribute__((nothrow)). */
mtp_property_nothrow = 1u << 3,
mtp_property_nothrow = 1u << 4,
/** This method is naked. GCC: __attribute__((naked)). */
mtp_property_naked = 1u << 4,
mtp_property_naked = 1u << 5,
/** This method returns newly allocate memory.
* GCC: __attribute__((malloc)). */
mtp_property_malloc = 1u << 5,
mtp_property_malloc = 1u << 6,
/** This method can return more than once (typically setjmp).
* GCC: __attribute__((returns_twice)). */
mtp_property_returns_twice = 1u << 6,
mtp_property_returns_twice = 1u << 7,
/** All method invocations are known and inside the current compilation
* unit, the backend can freely choose the calling convention. */
mtp_property_private = 1u << 7,
/** Set, if this method contains one possibly endless loop. Must not be
* set if all loops are guaranteed to terminate eventually. */
mtp_property_has_loop = 1u << 8,
mtp_property_private = 1u << 8,
/** Try to always inline this function, even if it seems nonprofitable */
mtp_property_always_inline = 1u << 9,
/** The function should not be inlined */
......
......@@ -41,15 +41,15 @@ static const bitflag_name_t ir_linkage_names[] = {
{ 0, NULL },
};
static const bitflag_name_t mtp_property_names[] = {
{ mtp_property_const, "const" },
{ mtp_property_no_write, "no_write" },
{ mtp_property_pure, "pure" },
{ mtp_property_noreturn, "noreturn" },
{ mtp_property_terminates, "terminates" },
{ mtp_property_nothrow, "nothrow" },
{ mtp_property_naked, "naked" },
{ mtp_property_malloc, "malloc" },
{ mtp_property_returns_twice, "returns_twice" },
{ mtp_property_private, "private" },
{ mtp_property_has_loop, "has_loop" },
{ mtp_property_always_inline, "always_inline" },
{ mtp_property_noinline, "noinline" },
{ mtp_property_inline_recommended, "inline_recommended" },
......
......@@ -952,16 +952,12 @@ static bool is_call_no_write(const ir_node *node)
{
ir_type *call_tp = get_Call_type(node);
unsigned prop = get_method_additional_properties(call_tp);
/* check first the call type */
if ((prop & (mtp_property_const|mtp_property_pure)) == 0) {
/* try the called entity */
ir_entity *callee = get_Call_callee(node);
if (callee != NULL) {
prop = get_entity_additional_properties(callee);
}
}
return prop & (mtp_property_const|mtp_property_pure);
if (prop & mtp_property_no_write)
return true;
ir_entity *entity = get_Call_callee(node);
if (entity == NULL)
return false;
return get_entity_additional_properties(entity) & mtp_property_no_write;
}
int is_irn_const_memory(const ir_node *node)
......
......@@ -196,9 +196,9 @@ static ir_type *lower_mtp(compound_call_lowering_flags flags, ir_type *mtp)
set_method_calling_convention(lowered, cconv);
mtp_additional_properties mtp_properties = get_method_additional_properties(mtp);
/* after lowering the call is not const anymore, since it writes to the
/* after lowering the call is not const/pure anymore, since it writes to the
* memory for the return value passed to it */
mtp_properties &= ~mtp_property_const;
mtp_properties &= ~(mtp_property_no_write | mtp_property_pure);
set_method_additional_properties(lowered, mtp_properties);
/* associate the lowered type with the original one for easier access */
......
This diff is collapsed.
......@@ -482,26 +482,11 @@ static memop_t *clone_memop_phi(memop_t *op, ir_node *phi)
return m;
}
/**
* Return the memory properties of a call node.
*
* @param call the call node
*
* return a bitset of mtp_property_const and mtp_property_pure
*/
static unsigned get_Call_memory_properties(ir_node *call)
static bool is_Call_pure(const ir_node *call)
{
ir_type *call_tp = get_Call_type(call);
unsigned prop = get_method_additional_properties(call_tp);
/* check first the call type */
if ((prop & (mtp_property_const|mtp_property_pure)) == 0) {
/* try the called entity */
ir_entity *callee = get_Call_callee(call);
if (callee != NULL)
prop = get_entity_additional_properties(callee);
}
return prop & (mtp_property_const|mtp_property_pure);
mtp_additional_properties prop = get_method_additional_properties(call_tp);
return prop & mtp_property_pure;
}
/**
......@@ -709,17 +694,12 @@ static void update_Store_memop(memop_t *m)
*/
static void update_Call_memop(memop_t *m)
{
ir_node *call = m->node;
unsigned prop = get_Call_memory_properties(call);
if (prop & mtp_property_const) {
/* A constant call did NOT use memory at all, we
can kick it from the list. */
} else if (prop & mtp_property_pure) {
/* pure calls READ memory */
ir_node *call = m->node;
if (is_Call_pure(call)) {
m->flags = 0;
} else
} else {
m->flags = FLAG_KILL_ALL;
}
foreach_irn_out_r(call, i, proj) {
/* beware of keep edges */
......
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