summaryrefslogtreecommitdiff
path: root/gcc/c-common.c
diff options
context:
space:
mode:
authormeissner <meissner@138bc75d-0d04-0410-961f-82ee72b054a4>2008-07-23 10:28:06 +0000
committermeissner <meissner@138bc75d-0d04-0410-961f-82ee72b054a4>2008-07-23 10:28:06 +0000
commit46f8e3b0dc1cbb88c7dde984d0f0c2ce8935011d (patch)
treeefd8e61a3d2ff9dcff5eb5bf03e25922191f7df5 /gcc/c-common.c
parente22d2ad745ca3d2ac08936833a802ffc161fc89b (diff)
downloadgcc-46f8e3b0dc1cbb88c7dde984d0f0c2ce8935011d.tar.gz
Add ability to set target options (ix86 only) and optimization options on a function specific basis
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@138075 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/c-common.c')
-rw-r--r--gcc/c-common.c245
1 files changed, 240 insertions, 5 deletions
diff --git a/gcc/c-common.c b/gcc/c-common.c
index cc13e056fd5..afdcac65f95 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -574,6 +574,8 @@ static tree handle_warn_unused_result_attribute (tree *, tree, tree, int,
static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *);
static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *);
static tree handle_alloc_size_attribute (tree *, tree, tree, int, bool *);
+static tree handle_option_attribute (tree *, tree, tree, int, bool *);
+static tree handle_optimize_attribute (tree *, tree, tree, int, bool *);
static void check_function_nonnull (tree, int, tree *);
static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT);
@@ -857,6 +859,10 @@ const struct attribute_spec c_common_attribute_table[] =
handle_error_attribute },
{ "error", 1, 1, true, false, false,
handle_error_attribute },
+ { "option", 1, -1, true, false, false,
+ handle_option_attribute },
+ { "optimize", 1, -1, true, false, false,
+ handle_optimize_attribute },
{ NULL, 0, 0, false, false, false, NULL }
};
@@ -5027,7 +5033,7 @@ handle_noreturn_attribute (tree *node, tree name, tree ARG_UNUSED (args),
static tree
handle_hot_attribute (tree *node, tree name, tree ARG_UNUSED (args),
- int ARG_UNUSED (flags), bool *no_add_attrs)
+ int ARG_UNUSED (flags), bool *no_add_attrs)
{
if (TREE_CODE (*node) == FUNCTION_DECL)
{
@@ -5037,8 +5043,34 @@ handle_hot_attribute (tree *node, tree name, tree ARG_UNUSED (args),
name, "cold");
*no_add_attrs = true;
}
- /* Do nothing else, just set the attribute. We'll get at
- it later with lookup_attribute. */
+
+ else
+ {
+ tree old_opts = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node);
+
+ /* If we are not at -O3, but are optimizing, turn on -O3
+ optimizations just for this one function. */
+ if (((optimize > 0 && optimize < 3) || optimize_size)
+ && (!old_opts || old_opts == optimization_default_node))
+ {
+ /* Create the hot optimization node if needed. */
+ if (!optimization_hot_node)
+ {
+ struct cl_optimization current_options;
+ static const char *os_argv[] = { NULL, "-O3", NULL };
+
+ cl_optimization_save (&current_options);
+ decode_options (2, os_argv);
+ optimization_hot_node = build_optimization_node ();
+ cl_optimization_restore (&current_options);
+ }
+
+ DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node)
+ = optimization_hot_node;
+ }
+ }
+ /* Most of the rest of the hot processing is done later with
+ lookup_attribute. */
}
else
{
@@ -5063,8 +5095,31 @@ handle_cold_attribute (tree *node, tree name, tree ARG_UNUSED (args),
name, "hot");
*no_add_attrs = true;
}
- /* Do nothing else, just set the attribute. We'll get at
- it later with lookup_attribute. */
+ else
+ {
+ tree old_opts = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node);
+
+ /* If we are optimizing, but not optimizing for space, turn on -Os
+ optimizations just for this one function. */
+ if (optimize && !optimize_size
+ && (!old_opts || old_opts == optimization_default_node))
+ {
+ /* Create the cold optimization node if needed. */
+ if (!optimization_cold_node)
+ {
+ struct cl_optimization current_options;
+ static const char *os_argv[] = { NULL, "-Os", NULL };
+
+ cl_optimization_save (&current_options);
+ decode_options (2, os_argv);
+ optimization_cold_node = build_optimization_node ();
+ cl_optimization_restore (&current_options);
+ }
+
+ DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node)
+ = optimization_cold_node;
+ }
+ }
}
else
{
@@ -6762,6 +6817,186 @@ handle_type_generic_attribute (tree *node, tree ARG_UNUSED (name),
return NULL_TREE;
}
+
+/* For handling "option" attribute. arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_option_attribute (tree *node, tree name, tree args, int flags,
+ bool *no_add_attrs)
+{
+ /* Ensure we have a function type. */
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+ else if (targetm.target_option.valid_attribute_p
+ == default_target_option_valid_attribute_p)
+ {
+ warning (OPT_Wattributes,
+ "%qE attribute is not supported on this machine",
+ name);
+ *no_add_attrs = true;
+ }
+ else if (! targetm.target_option.valid_attribute_p (*node, name, args,
+ flags))
+ *no_add_attrs = true;
+
+ return NULL_TREE;
+}
+
+/* Arguments being collected for optimization. */
+typedef const char *const_char_p; /* For DEF_VEC_P. */
+DEF_VEC_P(const_char_p);
+DEF_VEC_ALLOC_P(const_char_p, gc);
+static GTY(()) VEC(const_char_p, gc) *optimize_args;
+
+
+/* Inner function to convert a TREE_LIST to argv string to parse the optimize
+ options in ARGS. ATTR_P is true if this is for attribute(optimize), and
+ false for #pragma GCC optimize. */
+
+bool
+parse_optimize_options (tree args, bool attr_p)
+{
+ bool ret = true;
+ unsigned opt_argc;
+ unsigned i;
+ const char **opt_argv;
+ tree ap;
+
+ /* Build up argv vector. Just in case the string is stored away, use garbage
+ collected strings. */
+ VEC_truncate (const_char_p, optimize_args, 0);
+ VEC_safe_push (const_char_p, gc, optimize_args, NULL);
+
+ for (ap = args; ap != NULL_TREE; ap = TREE_CHAIN (ap))
+ {
+ tree value = TREE_VALUE (ap);
+
+ if (TREE_CODE (value) == INTEGER_CST)
+ {
+ char buffer[20];
+ sprintf (buffer, "-O%ld", (long) TREE_INT_CST_LOW (value));
+ VEC_safe_push (const_char_p, gc, optimize_args, ggc_strdup (buffer));
+ }
+
+ else if (TREE_CODE (value) == STRING_CST)
+ {
+ /* Split string into multiple substrings. */
+ size_t len = TREE_STRING_LENGTH (value);
+ char *p = ASTRDUP (TREE_STRING_POINTER (value));
+ char *end = p + len;
+ char *comma;
+ char *next_p = p;
+
+ while (next_p != NULL)
+ {
+ size_t len2;
+ char *q, *r;
+
+ p = next_p;
+ comma = strchr (p, ',');
+ if (comma)
+ {
+ len2 = comma - p;
+ *comma = '\0';
+ next_p = comma+1;
+ }
+ else
+ {
+ len2 = end - p;
+ next_p = NULL;
+ }
+
+ r = q = (char *) ggc_alloc (len2 + 3);
+
+ /* If the user supplied -Oxxx or -fxxx, only allow -Oxxx or -fxxx
+ options. */
+ if (*p == '-' && p[1] != 'O' && p[1] != 'f')
+ {
+ ret = false;
+ if (attr_p)
+ warning (OPT_Wattributes,
+ "Bad option %s to optimize attribute.", p);
+ else
+ warning (OPT_Wpragmas,
+ "Bad option %s to pragma attribute", p);
+ continue;
+ }
+
+ if (*p != '-')
+ {
+ *r++ = '-';
+
+ /* Assume that Ox is -Ox, a numeric value is -Ox, a s by
+ itself is -Os, and any other switch begins with a -f. */
+ if ((*p >= '0' && *p <= '9')
+ || (p[0] == 's' && p[1] == '\0'))
+ *r++ = 'O';
+ else if (*p != 'O')
+ *r++ = 'f';
+ }
+
+ memcpy (r, p, len2);
+ r[len2] = '\0';
+ VEC_safe_push (const_char_p, gc, optimize_args, q);
+ }
+
+ }
+ }
+
+ opt_argc = VEC_length (const_char_p, optimize_args);
+ opt_argv = (const char **) alloca (sizeof (char *) * (opt_argc + 1));
+
+ for (i = 1; i < opt_argc; i++)
+ opt_argv[i] = VEC_index (const_char_p, optimize_args, i);
+
+ /* Now parse the options. */
+ decode_options (opt_argc, opt_argv);
+
+ VEC_truncate (const_char_p, optimize_args, 0);
+ return ret;
+}
+
+/* For handling "optimize" attribute. arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_optimize_attribute (tree *node, tree name, tree args,
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ /* Ensure we have a function type. */
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+ else
+ {
+ struct cl_optimization cur_opts;
+ tree old_opts = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node);
+
+ /* Save current options. */
+ cl_optimization_save (&cur_opts);
+
+ /* If we previously had some optimization options, use them as the
+ default. */
+ if (old_opts)
+ cl_optimization_restore (TREE_OPTIMIZATION (old_opts));
+
+ /* Parse options, and update the vector. */
+ parse_optimize_options (args, true);
+ DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node)
+ = build_optimization_node ();
+
+ /* Restore current options. */
+ cl_optimization_restore (&cur_opts);
+ }
+
+ return NULL_TREE;
+}
/* Check for valid arguments being passed to a function.
ATTRS is a list of attributes. There are NARGS arguments in the array