@@ -7729,7 +7729,8 @@ refered_from_nonlocal_fn (struct cgraph_
bool *nonlocal_p = (bool *)data;
*nonlocal_p |= (node->used_from_other_partition
|| node->externally_visible
- || node->force_output);
+ || node->force_output
+ || lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)));
return false;
}
@@ -7789,7 +7790,9 @@ ipa_pta_execute (void)
constraints for parameters. */
bool nonlocal_p = (node->used_from_other_partition
|| node->externally_visible
- || node->force_output);
+ || node->force_output
+ || lookup_attribute ("noipa",
+ DECL_ATTRIBUTES (node->decl)));
node->call_for_symbol_thunks_and_aliases (refered_from_nonlocal_fn,
&nonlocal_p, true);
@@ -404,8 +404,8 @@ decl_attributes (tree *node, tree attrib
those targets that support it. */
if (TREE_CODE (*node) == FUNCTION_DECL
&& attributes
- && lookup_attribute_spec (get_identifier ("naked"))
- && lookup_attribute ("naked", attributes) != NULL)
+ && lookup_attribute ("naked", attributes) != NULL
+ && lookup_attribute_spec (get_identifier ("naked")))
{
if (lookup_attribute ("noinline", attributes) == NULL)
attributes = tree_cons (get_identifier ("noinline"), NULL, attributes);
@@ -414,6 +414,23 @@ decl_attributes (tree *node, tree attrib
attributes = tree_cons (get_identifier ("noclone"), NULL, attributes);
}
+ /* A "noipa" function attribute implies "noinline", "noclone" and "no_icf"
+ for those targets that support it. */
+ if (TREE_CODE (*node) == FUNCTION_DECL
+ && attributes
+ && lookup_attribute ("noipa", attributes) != NULL
+ && lookup_attribute_spec (get_identifier ("noipa")))
+ {
+ if (lookup_attribute ("noinline", attributes) == NULL)
+ attributes = tree_cons (get_identifier ("noinline"), NULL, attributes);
+
+ if (lookup_attribute ("noclone", attributes) == NULL)
+ attributes = tree_cons (get_identifier ("noclone"), NULL, attributes);
+
+ if (lookup_attribute ("no_icf", attributes) == NULL)
+ attributes = tree_cons (get_identifier ("no_icf"), NULL, attributes);
+ }
+
targetm.insert_attributes (*node, &attributes);
for (a = attributes; a; a = TREE_CHAIN (a))
@@ -0,0 +1,26 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fipa-pta -fdump-ipa-pta2-details -fdump-tree-fre3-details" } */
+
+static int __attribute__((noipa))
+foo (int *p, int *q)
+{
+ *p = 1;
+ *q = 0;
+ return *p;
+}
+
+extern void abort (void);
+
+int main()
+{
+ int a, b;
+ if (foo (&a, &b) != 1)
+ abort ();
+ return 0;
+}
+
+/* Verify we can disambiguate *p and *q in foo. */
+
+/* { dg-final { scan-ipa-dump "foo.arg0 = &a" "pta2" } } */
+/* { dg-final { scan-ipa-dump "foo.arg1 = &b" "pta2" } } */
+/* { dg-final { scan-tree-dump-not "Replaced \\\*p_2\\\(D\\\) with 1" "fre3" } } */
@@ -0,0 +1,39 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fipa-sra -fdump-tree-eipa_sra-details" } */
+
+struct bovid
+{
+ float red;
+ int green;
+ void *blue;
+};
+
+extern int printf (const char *, ...);
+extern void abort (void);
+
+static int
+__attribute__((noipa))
+ox (struct bovid cow)
+{
+ if (cow.green != 6)
+ abort ();
+
+ printf ("green: %f\nblue: %p\nblue again: %p\n", cow.green,
+ cow.blue, cow.blue);
+ return 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+ struct bovid cow;
+
+ cow.red = 7.4;
+ cow.green = 6;
+ cow.blue = &cow;
+
+ ox (cow);
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-not "About to replace expr" "eipa_sra" } } */
@@ -0,0 +1,188 @@
+/* Test the noipa attribute. */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+static inline int __attribute__((noipa))
+fn1 (void) /* { dg-warning "inline function \[^\n\]* given attribute noinline" "" } */
+{
+ return 1;
+}
+
+/* Verify the function is not inlined into its caller. */
+
+static __attribute__((noipa)) int
+fn2 (int x, int y)
+{
+ return x + y;
+}
+
+int
+fn3 (int x)
+{
+ return fn2 (x, 0);
+}
+
+/* { dg-final { scan-tree-dump "= fn2 \\(" "optimized" } } */
+
+void fn4 (char *);
+
+/* Verify the function is not cloned. */
+
+__attribute__((__noipa__)) static int
+fn5 (int x, int y)
+{
+ char *p = __builtin_alloca (x + y);
+ fn4 (p);
+ return x + y;
+}
+
+int
+fn6 (int x)
+{
+ return fn5 (x, 2);
+}
+
+/* { dg-final { scan-tree-dump "= fn5 \\(" "optimized" } } */
+/* { dg-final { scan-tree-dump-not "fn5\\.constprop" "optimized" } } */
+
+/* Verify we still remove unused function calls, even if they have
+ noipa attribute. */
+
+static void fn7 (void) __attribute__((noipa));
+static void
+fn7 (void)
+{
+}
+
+/* { dg-final { scan-tree-dump-not "fn7 \\(" "optimized" } } */
+
+/* Verify noipa functions are not ICF optimized. */
+
+static __attribute__((noipa)) int
+fn8 (int x)
+{
+ return x + 12;
+}
+
+static __attribute__((noipa)) int
+fn9 (int x)
+{
+ return x + 12;
+}
+
+int
+fn10 (int x)
+{
+ return fn8 (x) + fn9 (x);
+}
+
+/* { dg-final { scan-tree-dump "fn8 \\(int" "optimized" } } */
+/* { dg-final { scan-tree-dump "fn9 \\(int" "optimized" } } */
+
+/* Verify IPA-VRP is not performed. */
+
+void fn11 (void);
+
+static int __attribute__((noipa))
+fn12 (int x)
+{
+ if (x < 6 || x >= 29)
+ fn11 ();
+}
+
+void
+fn13 (int x)
+{
+ fn12 (6 + (x & 15));
+}
+
+/* { dg-final { scan-tree-dump "fn11 \\(\\)" "optimized" } } */
+
+void fn14 (void);
+
+__attribute__((noipa)) static int
+fn15 (int x)
+{
+ return x & 7;
+}
+
+int
+fn16 (int x)
+{
+ x = fn15 (x);
+ if (x < 0 || x >= 7)
+ fn14 ();
+}
+
+/* { dg-final { scan-tree-dump "fn14 \\(\\)" "optimized" } } */
+
+/* Verify IPA BIT CP is not performed. */
+
+void fn17 (void);
+
+__attribute__((noipa)) static int
+fn18 (int x)
+{
+ if (x & 8)
+ fn17 ();
+}
+
+void
+fn19 (void)
+{
+ fn18 (1);
+ fn18 (2);
+ fn18 (4);
+ fn18 (16);
+ fn18 (32);
+ fn18 (64);
+}
+
+/* { dg-final { scan-tree-dump "fn17 \\(\\)" "optimized" } } */
+
+/* Ensure pure/const discovery is not performed. */
+
+int var1;
+void fn20 (void);
+
+__attribute__((noipa)) static int
+fn21 (int x, int y)
+{
+ return x * y;
+}
+
+int
+fn22 (void)
+{
+ var1 = 7;
+ asm volatile ("" : "+g" (var1) : : "memory");
+ int a = var1;
+ int b = fn21 (a, a);
+ if (a != var1)
+ fn20 ();
+ return b;
+}
+
+/* { dg-final { scan-tree-dump "fn20 \\(\\)" "optimized" } } */
+
+/* Verify IPA alignment propagation is not performed. */
+
+static __attribute__ ((aligned(16))) char var2[32];
+void fn23 (void);
+
+__attribute__((noipa)) static void
+fn24 (char *p)
+{
+ if ((((__UINTPTR_TYPE__) p) & 15) != 0)
+ fn23 ();
+ asm ("");
+}
+
+void
+fn25 (void)
+{
+ fn24 (var2);
+ fn24 (var2 + 16);
+}
+
+/* { dg-final { scan-tree-dump "fn20 \\(\\)" "optimized" } } */
@@ -4473,7 +4473,8 @@ rest_of_handle_final (void)
assemble_start_function (current_function_decl, fnname);
final_start_function (get_insns (), asm_out_file, optimize);
final (get_insns (), asm_out_file, optimize);
- if (flag_ipa_ra)
+ if (flag_ipa_ra
+ && !lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl)))
collect_fn_hard_reg_usage ();
final_end_function ();
@@ -63,6 +63,7 @@ static tree handle_stack_protect_attribu
static tree handle_noinline_attribute (tree *, tree, tree, int, bool *);
static tree handle_noclone_attribute (tree *, tree, tree, int, bool *);
static tree handle_noicf_attribute (tree *, tree, tree, int, bool *);
+static tree handle_noipa_attribute (tree *, tree, tree, int, bool *);
static tree handle_leaf_attribute (tree *, tree, tree, int, bool *);
static tree handle_always_inline_attribute (tree *, tree, tree, int,
bool *);
@@ -173,6 +174,8 @@ const struct attribute_spec c_common_att
handle_noclone_attribute, false },
{ "no_icf", 0, 0, true, false, false,
handle_noicf_attribute, false },
+ { "noipa", 0, 0, true, false, false,
+ handle_noipa_attribute, false },
{ "leaf", 0, 0, true, false, false,
handle_leaf_attribute, false },
{ "always_inline", 0, 0, true, false, false,
@@ -680,6 +683,21 @@ handle_noicf_attribute (tree *node, tree
{
if (TREE_CODE (*node) != FUNCTION_DECL)
{
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "noipa" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_noipa_attribute (tree *node, tree name, tree, int, bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
warning (OPT_Wattributes, "%qE attribute ignored", name);
*no_add_attrs = true;
}
@@ -90,11 +90,12 @@ static bool
non_local_p (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
{
return !(node->only_called_directly_or_aliased_p ()
- /* i386 would need update to output thunk with locak calling
- ocnvetions. */
+ /* i386 would need update to output thunk with local calling
+ conventions. */
&& !node->thunk.thunk_p
&& node->definition
&& !DECL_EXTERNAL (node->decl)
+ && !lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl))
&& !node->externally_visible
&& !node->used_from_other_partition
&& !node->in_other_partition);
@@ -209,6 +210,8 @@ cgraph_externally_visible_p (struct cgra
if (lookup_attribute ("externally_visible",
DECL_ATTRIBUTES (node->decl)))
return true;
+ if (lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
+ return true;
if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
&& lookup_attribute ("dllexport",
DECL_ATTRIBUTES (node->decl)))
@@ -2955,6 +2955,19 @@ asm ("");
(@pxref{Extended Asm}) in the called function, to serve as a special
side-effect.
+@item noipa
+@cindex @code{noipa} function attribute
+Disable interprocedural optimizations between the function with this
+attribute and its callers, as if the body of the function is not available
+when optimizing callers and the callers are unavailable when optimizing
+the body. This attribute implies @code{noinline}, @code{noclone} and
+@code{no_icf} attributes. However, this attribute is not equivalent
+to a combination of other attributes, because its purpose is to suppress
+existing and future optimizations employing interprocedural analysis,
+including those that do not have an attribute suitable for disabling
+them individually. This attribute is supported mainly for the purpose
+of testing the compiler.
+
@item nonnull (@var{arg-index}, @dots{})
@cindex @code{nonnull} function attribute
@cindex functions with non-null pointer arguments
@@ -2255,7 +2255,8 @@ cgraph_node::get_availability (symtab_no
avail = AVAIL_AVAILABLE;
else if (transparent_alias)
ultimate_alias_target (&avail, ref);
- else if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (decl)))
+ else if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (decl))
+ || lookup_attribute ("noipa", DECL_ATTRIBUTES (decl)))
avail = AVAIL_INTERPOSABLE;
else if (!externally_visible)
avail = AVAIL_AVAILABLE;