1, /* OMP_CLAUSE_PRIVATE */
1, /* OMP_CLAUSE_SHARED */
1, /* OMP_CLAUSE_FIRSTPRIVATE */
- 1, /* OMP_CLAUSE_LASTPRIVATE */
+ 2, /* OMP_CLAUSE_LASTPRIVATE */
4, /* OMP_CLAUSE_REDUCTION */
1, /* OMP_CLAUSE_COPYIN */
1, /* OMP_CLAUSE_COPYPRIVATE */
1, /* OMP_CLAUSE_SCHEDULE */
0, /* OMP_CLAUSE_NOWAIT */
0, /* OMP_CLAUSE_ORDERED */
- 0 /* OMP_CLAUSE_DEFAULT */
+ 0, /* OMP_CLAUSE_DEFAULT */
+ 3, /* OMP_CLAUSE_COLLAPSE */
+ 0 /* OMP_CLAUSE_UNTIED */
};
const char * const omp_clause_code_name[] =
"schedule",
"nowait",
"ordered",
- "default"
+ "default",
+ "collapse",
+ "untied"
};
\f
/* Init tree.c. */
tree_contains_struct[TRANSLATION_UNIT_DECL][TS_DECL_MINIMAL] = 1;
tree_contains_struct[LABEL_DECL][TS_DECL_MINIMAL] = 1;
tree_contains_struct[FIELD_DECL][TS_DECL_MINIMAL] = 1;
- tree_contains_struct[STRUCT_FIELD_TAG][TS_DECL_MINIMAL] = 1;
tree_contains_struct[NAME_MEMORY_TAG][TS_DECL_MINIMAL] = 1;
tree_contains_struct[SYMBOL_MEMORY_TAG][TS_DECL_MINIMAL] = 1;
tree_contains_struct[MEMORY_PARTITION_TAG][TS_DECL_MINIMAL] = 1;
- tree_contains_struct[STRUCT_FIELD_TAG][TS_MEMORY_TAG] = 1;
tree_contains_struct[NAME_MEMORY_TAG][TS_MEMORY_TAG] = 1;
tree_contains_struct[SYMBOL_MEMORY_TAG][TS_MEMORY_TAG] = 1;
tree_contains_struct[MEMORY_PARTITION_TAG][TS_MEMORY_TAG] = 1;
- tree_contains_struct[STRUCT_FIELD_TAG][TS_STRUCT_FIELD_TAG] = 1;
tree_contains_struct[MEMORY_PARTITION_TAG][TS_MEMORY_PARTITION_TAG] = 1;
tree_contains_struct[VAR_DECL][TS_DECL_WITH_VIS] = 1;
case NAME_MEMORY_TAG:
case SYMBOL_MEMORY_TAG:
return sizeof (struct tree_memory_tag);
- case STRUCT_FIELD_TAG:
- return sizeof (struct tree_struct_field_tag);
case MEMORY_PARTITION_TAG:
return sizeof (struct tree_memory_partition_tag);
default:
case tcc_constant:
TREE_CONSTANT (t) = 1;
- TREE_INVARIANT (t) = 1;
break;
case tcc_expression:
memset (s, 0, sizeof (struct tree_common));
TREE_SET_CODE (s, STRING_CST);
TREE_CONSTANT (s) = 1;
- TREE_INVARIANT (s) = 1;
TREE_STRING_LENGTH (s) = len;
memcpy (s->string.str, str, len);
s->string.str[len] = '\0';
really_constant_p (const_tree exp)
{
/* This is not quite the same as STRIP_NOPS. It does more. */
- while (TREE_CODE (exp) == NOP_EXPR
- || TREE_CODE (exp) == CONVERT_EXPR
+ while (CONVERT_EXPR_P (exp)
|| TREE_CODE (exp) == NON_LVALUE_EXPR)
exp = TREE_OPERAND (exp, 0);
return TREE_CONSTANT (exp);
switch (TREE_CODE (t))
{
- case NOP_EXPR: case CONVERT_EXPR: case NON_LVALUE_EXPR:
+ CASE_CONVERT: case NON_LVALUE_EXPR:
/* If we have conversions, we know that the alignment of the
object must meet each of the alignments of the types. */
align0 = expr_align (TREE_OPERAND (t, 0));
return NULL;
}
}
+
\f
+
+
+/* Return whether OP is a DECL whose address is function-invariant. */
+
+bool
+decl_address_invariant_p (const_tree op)
+{
+ /* The conditions below are slightly less strict than the one in
+ staticp. */
+
+ switch (TREE_CODE (op))
+ {
+ case PARM_DECL:
+ case RESULT_DECL:
+ case LABEL_DECL:
+ case FUNCTION_DECL:
+ return true;
+
+ case VAR_DECL:
+ if (((TREE_STATIC (op) || DECL_EXTERNAL (op))
+ && !DECL_DLLIMPORT_P (op))
+ || DECL_THREAD_LOCAL_P (op)
+ || DECL_CONTEXT (op) == current_function_decl
+ || decl_function_context (op) == current_function_decl)
+ return true;
+ break;
+
+ case CONST_DECL:
+ if ((TREE_STATIC (op) || DECL_EXTERNAL (op))
+ || decl_function_context (op) == current_function_decl)
+ return true;
+ break;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+
+/* Return true if T is function-invariant (internal function, does
+ not handle arithmetic; that's handled in skip_simple_arithmetic and
+ tree_invariant_p). */
+
+static bool tree_invariant_p (tree t);
+
+static bool
+tree_invariant_p_1 (tree t)
+{
+ tree op;
+
+ if (TREE_CONSTANT (t)
+ || (TREE_READONLY (t) && !TREE_SIDE_EFFECTS (t)))
+ return true;
+
+ switch (TREE_CODE (t))
+ {
+ case SAVE_EXPR:
+ return true;
+
+ case ADDR_EXPR:
+ op = TREE_OPERAND (t, 0);
+ while (handled_component_p (op))
+ {
+ switch (TREE_CODE (op))
+ {
+ case ARRAY_REF:
+ case ARRAY_RANGE_REF:
+ if (!tree_invariant_p (TREE_OPERAND (op, 1))
+ || TREE_OPERAND (op, 2) != NULL_TREE
+ || TREE_OPERAND (op, 3) != NULL_TREE)
+ return false;
+ break;
+
+ case COMPONENT_REF:
+ if (TREE_OPERAND (op, 2) != NULL_TREE)
+ return false;
+ break;
+
+ default:;
+ }
+ op = TREE_OPERAND (op, 0);
+ }
+
+ return CONSTANT_CLASS_P (op) || decl_address_invariant_p (op);
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+/* Return true if T is function-invariant. */
+
+static bool
+tree_invariant_p (tree t)
+{
+ tree inner = skip_simple_arithmetic (t);
+ return tree_invariant_p_1 (inner);
+}
+
/* Wrap a SAVE_EXPR around EXPR, if appropriate.
Do this to any expression which may be used in more than one place,
but must be evaluated only once.
Since it is no problem to reevaluate literals, we just return the
literal node. */
inner = skip_simple_arithmetic (t);
+ if (TREE_CODE (inner) == ERROR_MARK)
+ return inner;
- if (TREE_INVARIANT (inner)
- || (TREE_READONLY (inner) && ! TREE_SIDE_EFFECTS (inner))
- || TREE_CODE (inner) == SAVE_EXPR
- || TREE_CODE (inner) == ERROR_MARK)
+ if (tree_invariant_p_1 (inner))
return t;
/* If INNER contains a PLACEHOLDER_EXPR, we must evaluate it each time, since
value was computed on both sides of the jump. So make sure it isn't
eliminated as dead. */
TREE_SIDE_EFFECTS (t) = 1;
- TREE_INVARIANT (t) = 1;
return t;
}
inner = TREE_OPERAND (inner, 0);
else if (BINARY_CLASS_P (inner))
{
- if (TREE_INVARIANT (TREE_OPERAND (inner, 1)))
+ if (tree_invariant_p (TREE_OPERAND (inner, 1)))
inner = TREE_OPERAND (inner, 0);
- else if (TREE_INVARIANT (TREE_OPERAND (inner, 0)))
+ else if (tree_invariant_p (TREE_OPERAND (inner, 0)))
inner = TREE_OPERAND (inner, 1);
else
break;
return TS_FUNCTION_DECL;
case SYMBOL_MEMORY_TAG:
case NAME_MEMORY_TAG:
- case STRUCT_FIELD_TAG:
case MEMORY_PARTITION_TAG:
return TS_MEMORY_TAG;
default:
{
enum tree_code code = TREE_CODE (exp);
tree op0, op1, op2, op3;
- tree new;
- tree inner;
+ tree new, inner;
/* We handle TREE_LIST and COMPONENT_REF separately. */
if (code == TREE_LIST)
for (i = 1; i < TREE_OPERAND_LENGTH (exp); i++)
{
tree op = TREE_OPERAND (exp, i);
- tree newop = SUBSTITUTE_IN_EXPR (op, f, r);
- if (newop != op)
+ tree new_op = SUBSTITUTE_IN_EXPR (op, f, r);
+ if (new_op != op)
{
- copy = copy_node (exp);
- TREE_OPERAND (copy, i) = newop;
+ if (!copy)
+ copy = copy_node (exp);
+ TREE_OPERAND (copy, i) = new_op;
}
}
+
if (copy)
new = fold (copy);
else
{
tree copy = NULL_TREE;
int i;
- int n = TREE_OPERAND_LENGTH (exp);
- for (i = 1; i < n; i++)
+
+ for (i = 1; i < TREE_OPERAND_LENGTH (exp); i++)
{
tree op = TREE_OPERAND (exp, i);
- tree newop = SUBSTITUTE_PLACEHOLDER_IN_EXPR (op, obj);
- if (newop != op)
+ tree new_op = SUBSTITUTE_PLACEHOLDER_IN_EXPR (op, obj);
+ if (new_op != op)
{
if (!copy)
copy = copy_node (exp);
- TREE_OPERAND (copy, i) = newop;
+ TREE_OPERAND (copy, i) = new_op;
}
}
+
if (copy)
return fold (copy);
else
/* No action is needed in this case. */
return ref;
- case NOP_EXPR:
- case CONVERT_EXPR:
+ CASE_CONVERT:
case FLOAT_EXPR:
case FIX_TRUNC_EXPR:
result = build_nt (code, stabilize_reference (TREE_OPERAND (ref, 0)));
ignore things that are actual constant or that already have been
handled by this function. */
- if (TREE_INVARIANT (e))
+ if (tree_invariant_p (e))
return e;
switch (TREE_CODE_CLASS (code))
TREE_READONLY (result) = TREE_READONLY (e);
TREE_SIDE_EFFECTS (result) = TREE_SIDE_EFFECTS (e);
TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (e);
- TREE_INVARIANT (result) = 1;
return result;
}
/* Low-level constructors for expressions. */
/* A helper function for build1 and constant folders. Set TREE_CONSTANT,
- TREE_INVARIANT, and TREE_SIDE_EFFECTS for an ADDR_EXPR. */
+ and TREE_SIDE_EFFECTS for an ADDR_EXPR. */
void
recompute_tree_invariant_for_addr_expr (tree t)
{
tree node;
- bool tc = true, ti = true, se = false;
+ bool tc = true, se = false;
/* We started out assuming this address is both invariant and constant, but
does not have side effects. Now go down any handled components and see if
??? Note that this code makes no attempt to deal with the case where
taking the address of something causes a copy due to misalignment. */
-#define UPDATE_TITCSE(NODE) \
+#define UPDATE_FLAGS(NODE) \
do { tree _node = (NODE); \
- if (_node && !TREE_INVARIANT (_node)) ti = false; \
if (_node && !TREE_CONSTANT (_node)) tc = false; \
if (_node && TREE_SIDE_EFFECTS (_node)) se = true; } while (0)
|| TREE_CODE (node) == ARRAY_RANGE_REF)
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (node, 0))) == ARRAY_TYPE)
{
- UPDATE_TITCSE (TREE_OPERAND (node, 1));
+ UPDATE_FLAGS (TREE_OPERAND (node, 1));
if (TREE_OPERAND (node, 2))
- UPDATE_TITCSE (TREE_OPERAND (node, 2));
+ UPDATE_FLAGS (TREE_OPERAND (node, 2));
if (TREE_OPERAND (node, 3))
- UPDATE_TITCSE (TREE_OPERAND (node, 3));
+ UPDATE_FLAGS (TREE_OPERAND (node, 3));
}
/* Likewise, just because this is a COMPONENT_REF doesn't mean we have a
FIELD_DECL, apparently. The G++ front end can put something else
&& TREE_CODE (TREE_OPERAND (node, 1)) == FIELD_DECL)
{
if (TREE_OPERAND (node, 2))
- UPDATE_TITCSE (TREE_OPERAND (node, 2));
+ UPDATE_FLAGS (TREE_OPERAND (node, 2));
}
else if (TREE_CODE (node) == BIT_FIELD_REF)
- UPDATE_TITCSE (TREE_OPERAND (node, 2));
+ UPDATE_FLAGS (TREE_OPERAND (node, 2));
}
- node = lang_hooks.expr_to_decl (node, &tc, &ti, &se);
+ node = lang_hooks.expr_to_decl (node, &tc, &se);
/* Now see what's inside. If it's an INDIRECT_REF, copy our properties from
- the address, since &(*a)->b is a form of addition. If it's a decl, it's
- invariant and constant if the decl is static. It's also invariant if it's
- a decl in the current function. Taking the address of a volatile variable
- is not volatile. If it's a constant, the address is both invariant and
- constant. Otherwise it's neither. */
+ the address, since &(*a)->b is a form of addition. If it's a constant, the
+ address is constant too. If it's a decl, its address is constant if the
+ decl is static. Everything else is not constant and, furthermore,
+ taking the address of a volatile variable is not volatile. */
if (TREE_CODE (node) == INDIRECT_REF)
- UPDATE_TITCSE (TREE_OPERAND (node, 0));
- else if (DECL_P (node))
- {
- if (staticp (node))
- ;
- else if (decl_function_context (node) == current_function_decl
- /* Addresses of thread-local variables are invariant. */
- || (TREE_CODE (node) == VAR_DECL
- && DECL_THREAD_LOCAL_P (node)))
- tc = false;
- else
- ti = tc = false;
- }
+ UPDATE_FLAGS (TREE_OPERAND (node, 0));
else if (CONSTANT_CLASS_P (node))
;
+ else if (DECL_P (node))
+ tc &= (staticp (node) != NULL_TREE);
else
{
- ti = tc = false;
+ tc = false;
se |= TREE_SIDE_EFFECTS (node);
}
+
TREE_CONSTANT (t) = tc;
- TREE_INVARIANT (t) = ti;
TREE_SIDE_EFFECTS (t) = se;
-#undef UPDATE_TITCSE
+#undef UPDATE_FLAGS
}
/* Build an expression of code CODE, data type TYPE, and operands as
&& node && !TYPE_P (node)
&& TREE_CONSTANT (node))
TREE_CONSTANT (t) = 1;
- if ((TREE_CODE_CLASS (code) == tcc_unary || code == VIEW_CONVERT_EXPR)
- && node && TREE_INVARIANT (node))
- TREE_INVARIANT (t) = 1;
if (TREE_CODE_CLASS (code) == tcc_reference
&& node && TREE_THIS_VOLATILE (node))
TREE_THIS_VOLATILE (t) = 1;
read_only = 0; \
if (!TREE_CONSTANT (arg##N)) \
constant = 0; \
- if (!TREE_INVARIANT (arg##N)) \
- invariant = 0; \
} \
} while (0)
tree
build2_stat (enum tree_code code, tree tt, tree arg0, tree arg1 MEM_STAT_DECL)
{
- bool constant, read_only, side_effects, invariant;
+ bool constant, read_only, side_effects;
tree t;
gcc_assert (TREE_CODE_LENGTH (code) == 2);
|| TREE_CODE_CLASS (code) == tcc_binary);
read_only = 1;
side_effects = TREE_SIDE_EFFECTS (t);
- invariant = constant;
PROCESS_ARG(0);
PROCESS_ARG(1);
TREE_READONLY (t) = read_only;
TREE_CONSTANT (t) = constant;
- TREE_INVARIANT (t) = invariant;
TREE_SIDE_EFFECTS (t) = side_effects;
TREE_THIS_VOLATILE (t)
= (TREE_CODE_CLASS (code) == tcc_reference
build3_stat (enum tree_code code, tree tt, tree arg0, tree arg1,
tree arg2 MEM_STAT_DECL)
{
- bool constant, read_only, side_effects, invariant;
+ bool constant, read_only, side_effects;
tree t;
gcc_assert (TREE_CODE_LENGTH (code) == 3);
build4_stat (enum tree_code code, tree tt, tree arg0, tree arg1,
tree arg2, tree arg3 MEM_STAT_DECL)
{
- bool constant, read_only, side_effects, invariant;
+ bool constant, read_only, side_effects;
tree t;
gcc_assert (TREE_CODE_LENGTH (code) == 4);
build5_stat (enum tree_code code, tree tt, tree arg0, tree arg1,
tree arg2, tree arg3, tree arg4 MEM_STAT_DECL)
{
- bool constant, read_only, side_effects, invariant;
+ bool constant, read_only, side_effects;
tree t;
gcc_assert (TREE_CODE_LENGTH (code) == 5);
tree arg2, tree arg3, tree arg4, tree arg5,
tree arg6 MEM_STAT_DECL)
{
- bool constant, read_only, side_effects, invariant;
+ bool constant, read_only, side_effects;
tree t;
gcc_assert (code == TARGET_MEM_REF);
}
else if (DECL_DLLIMPORT_P (old) && !DECL_DLLIMPORT_P (new))
{
- /* Warn about overriding a symbol that has already been used. eg:
+ /* Warn about overriding a symbol that has already been used, e.g.:
extern int __attribute__ ((dllimport)) foo;
int* bar () {return &foo;}
int foo;
"after being referenced with dll linkage", new);
/* If we have used a variable's address with dllimport linkage,
keep the old DECL_DLLIMPORT_P flag: the ADDR_EXPR using the
- decl may already have had TREE_INVARIANT and TREE_CONSTANT
- computed.
+ decl may already have had TREE_CONSTANT computed.
We still remove the attribute so that assembler code refers
to '&foo rather than '_imp__foo'. */
if (TREE_CODE (old) == VAR_DECL && TREE_ADDRESSABLE (old))
return t;
}
-/* Return the TYPE of the elements comprising
- the innermost dimension of ARRAY. */
+/* Recursively examines the array elements of TYPE, until a non-array
+ element type is found. */
tree
-get_inner_array_type (const_tree array)
+strip_array_types (tree type)
{
- tree type = TREE_TYPE (array);
-
while (TREE_CODE (type) == ARRAY_TYPE)
type = TREE_TYPE (type);
If FOR_TYPE is nonzero, we return a value which, if converted to
type FOR_TYPE, would be equivalent to converting OP to type FOR_TYPE.
- If FOR_TYPE is nonzero, unaligned bit-field references may be changed to the
- narrowest type that can hold the value, even if they don't exactly fit.
- Otherwise, bit-field references are changed to a narrower type
- only if they can be fetched directly from memory in that type.
-
OP must have integer, real or enumeral type. Pointers are not allowed!
There are some cases where the obvious value we could return
&& TYPE_UNSIGNED (type));
tree win = op;
- while (TREE_CODE (op) == NOP_EXPR
- || TREE_CODE (op) == CONVERT_EXPR)
+ while (CONVERT_EXPR_P (op))
{
int bitschange;
Let's avoid computing it if it does not affect WIN
and if UNS will not be needed again. */
if ((uns
- || TREE_CODE (op) == NOP_EXPR
- || TREE_CODE (op) == CONVERT_EXPR)
+ || CONVERT_EXPR_P (op))
&& TYPE_UNSIGNED (TREE_TYPE (op)))
{
uns = 1;
}
}
- if (TREE_CODE (op) == COMPONENT_REF
- /* Since type_for_size always gives an integer type. */
- && TREE_CODE (type) != REAL_TYPE
- && TREE_CODE (type) != FIXED_POINT_TYPE
- /* Don't crash if field not laid out yet. */
- && DECL_SIZE (TREE_OPERAND (op, 1)) != 0
- && host_integerp (DECL_SIZE (TREE_OPERAND (op, 1)), 1))
- {
- unsigned int innerprec
- = tree_low_cst (DECL_SIZE (TREE_OPERAND (op, 1)), 1);
- int unsignedp = (DECL_UNSIGNED (TREE_OPERAND (op, 1))
- || TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op, 1))));
- type = lang_hooks.types.type_for_size (innerprec, unsignedp);
-
- /* We can get this structure field in the narrowest type it fits in.
- If FOR_TYPE is 0, do this only for a field that matches the
- narrower type exactly and is aligned for it
- The resulting extension to its nominal type (a fullword type)
- must fit the same conditions as for other extensions. */
-
- if (type != 0
- && INT_CST_LT_UNSIGNED (TYPE_SIZE (type), TYPE_SIZE (TREE_TYPE (op)))
- && (for_type || ! DECL_BIT_FIELD (TREE_OPERAND (op, 1)))
- && (! uns || final_prec <= innerprec || unsignedp))
- {
- win = build3 (COMPONENT_REF, type, TREE_OPERAND (op, 0),
- TREE_OPERAND (op, 1), NULL_TREE);
- TREE_SIDE_EFFECTS (win) = TREE_SIDE_EFFECTS (op);
- TREE_THIS_VOLATILE (win) = TREE_THIS_VOLATILE (op);
- }
- }
-
return win;
}
\f
if (ecf_flags & ECF_CONST)
TREE_READONLY (decl) = 1;
if (ecf_flags & ECF_PURE)
- DECL_IS_PURE (decl) = 1;
+ DECL_PURE_P (decl) = 1;
+ if (ecf_flags & ECF_LOOPING_CONST_OR_PURE)
+ DECL_LOOPING_CONST_OR_PURE_P (decl) = 1;
if (ecf_flags & ECF_NORETURN)
TREE_THIS_VOLATILE (decl) = 1;
if (ecf_flags & ECF_NOTHROW)
/* Calls have side-effects, except those to const or
pure functions. */
i = call_expr_flags (t);
- if (!(i & (ECF_CONST | ECF_PURE)))
+ if ((i & ECF_LOOPING_CONST_OR_PURE) || !(i & (ECF_CONST | ECF_PURE)))
side_effects = 1;
}
TREE_SIDE_EFFECTS (t) = side_effects;
case OMP_CLAUSE_PRIVATE:
case OMP_CLAUSE_SHARED:
case OMP_CLAUSE_FIRSTPRIVATE:
- case OMP_CLAUSE_LASTPRIVATE:
case OMP_CLAUSE_COPYIN:
case OMP_CLAUSE_COPYPRIVATE:
case OMP_CLAUSE_IF:
case OMP_CLAUSE_NOWAIT:
case OMP_CLAUSE_ORDERED:
case OMP_CLAUSE_DEFAULT:
+ case OMP_CLAUSE_UNTIED:
+ WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp));
+
+ case OMP_CLAUSE_LASTPRIVATE:
+ WALK_SUBTREE (OMP_CLAUSE_DECL (*tp));
+ WALK_SUBTREE (OMP_CLAUSE_LASTPRIVATE_STMT (*tp));
WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp));
+ case OMP_CLAUSE_COLLAPSE:
+ {
+ int i;
+ for (i = 0; i < 3; i++)
+ WALK_SUBTREE (OMP_CLAUSE_OPERAND (*tp, i));
+ WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp));
+ }
+
case OMP_CLAUSE_REDUCTION:
{
int i;