/* Compare two constructor-element-type constants. Return 1 if the lists
are known to be equal; otherwise return 0. */
-static bool
+bool
simple_cst_list_equal (const_tree l1, const_tree l2)
{
while (l1 != NULL_TREE && l2 != NULL_TREE)
extern tree build_decl_attribute_variant (tree, tree);
extern tree build_type_attribute_qual_variant (tree, tree, int);
+extern bool simple_cst_list_equal (const_tree, const_tree);
extern bool attribute_value_equal (const_tree, const_tree);
/* Return 0 if the attributes for two types are incompatible, 1 if they
return t;
}
+static GTY(()) tree target_attribute_cache[3];
+
/* Hook to validate attribute((target("string"))). */
bool
&& strcmp (TREE_STRING_POINTER (TREE_VALUE (args)), "default") == 0)
return true;
+ if ((DECL_FUNCTION_SPECIFIC_TARGET (fndecl) == target_attribute_cache[1]
+ || DECL_FUNCTION_SPECIFIC_TARGET (fndecl) == NULL_TREE)
+ && (DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl)
+ == target_attribute_cache[2]
+ || DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl) == NULL_TREE)
+ && simple_cst_list_equal (args, target_attribute_cache[0]))
+ {
+ DECL_FUNCTION_SPECIFIC_TARGET (fndecl) = target_attribute_cache[1];
+ DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl)
+ = target_attribute_cache[2];
+ return true;
+ }
+
tree old_optimize = build_optimization_node (&global_options,
&global_options_set);
if (new_target == error_mark_node)
ret = false;
- else if (fndecl && new_target)
+ else if (new_target)
{
+ if (DECL_FUNCTION_SPECIFIC_TARGET (fndecl) == NULL_TREE
+ && DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl) == NULL_TREE)
+ {
+ target_attribute_cache[0] = copy_list (args);
+ target_attribute_cache[1] = new_target;
+ target_attribute_cache[2]
+ = old_optimize != new_optimize ? new_optimize : NULL_TREE;
+ }
+
DECL_FUNCTION_SPECIFIC_TARGET (fndecl) = new_target;
if (old_optimize != new_optimize)