diff options
author | meissner <meissner@138bc75d-0d04-0410-961f-82ee72b054a4> | 2008-07-23 10:28:06 +0000 |
---|---|---|
committer | meissner <meissner@138bc75d-0d04-0410-961f-82ee72b054a4> | 2008-07-23 10:28:06 +0000 |
commit | 46f8e3b0dc1cbb88c7dde984d0f0c2ce8935011d (patch) | |
tree | efd8e61a3d2ff9dcff5eb5bf03e25922191f7df5 /gcc/c-common.c | |
parent | e22d2ad745ca3d2ac08936833a802ffc161fc89b (diff) | |
download | gcc-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.c | 245 |
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 (¤t_options); + decode_options (2, os_argv); + optimization_hot_node = build_optimization_node (); + cl_optimization_restore (¤t_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 (¤t_options); + decode_options (2, os_argv); + optimization_cold_node = build_optimization_node (); + cl_optimization_restore (¤t_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 |