From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2140) id E333839AF4DC; Thu, 5 Aug 2021 12:07:34 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E333839AF4DC Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Alexandre Oliva To: gcc-cvs@gcc.gnu.org Subject: [gcc(refs/users/aoliva/heads/strub)] more tests, red zones, and deferred strubbing X-Act-Checkin: gcc X-Git-Author: Alexandre Oliva X-Git-Refname: refs/users/aoliva/heads/strub X-Git-Oldrev: 5e4f646737086ddf6bdae3810b3595c2e8f95a42 X-Git-Newrev: 243fea0d9e30acef7fb3673ebf82fca1815577fe Message-Id: <20210805120734.E333839AF4DC@sourceware.org> Date: Thu, 5 Aug 2021 12:07:34 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 05 Aug 2021 12:07:35 -0000 https://gcc.gnu.org/g:243fea0d9e30acef7fb3673ebf82fca1815577fe commit 243fea0d9e30acef7fb3673ebf82fca1815577fe Author: Alexandre Oliva Date: Thu Aug 5 08:43:23 2021 -0300 more tests, red zones, and deferred strubbing Diff: --- gcc/builtins.c | 83 ++++++- gcc/ipa-strub.c | 240 +++++++++++++------ gcc/ipa-strub.h | 1 + gcc/testsuite/c-c++-common/strub-O2.c | 2 +- gcc/testsuite/c-c++-common/strub-O2fni.c | 6 +- gcc/testsuite/c-c++-common/strub-O3fni.c | 4 +- gcc/testsuite/c-c++-common/strub-Og.c | 2 +- gcc/testsuite/c-c++-common/strub-Os.c | 2 +- gcc/testsuite/c-c++-common/strub-all1.c | 4 +- gcc/testsuite/c-c++-common/strub-apply1.c | 15 ++ gcc/testsuite/c-c++-common/strub-apply2.c | 12 + gcc/testsuite/c-c++-common/strub-apply3.c | 8 + gcc/testsuite/c-c++-common/strub-apply4.c | 21 ++ gcc/testsuite/c-c++-common/strub-at-calls1.c | 4 +- gcc/testsuite/c-c++-common/strub-default1.c | 8 +- gcc/testsuite/c-c++-common/strub-internal1.c | 4 +- gcc/testsuite/c-c++-common/strub-parms1.c | 48 ++++ gcc/testsuite/c-c++-common/strub-parms2.c | 36 +++ gcc/testsuite/c-c++-common/strub-parms3.c | 58 +++++ .../c-c++-common/torture/strub-callable1.c | 13 + .../c-c++-common/torture/strub-callable2.c | 264 +++++++++++++++++++++ gcc/testsuite/c-c++-common/torture/strub-const1.c | 18 ++ gcc/testsuite/c-c++-common/torture/strub-const2.c | 22 ++ gcc/testsuite/c-c++-common/torture/strub-const3.c | 13 + gcc/testsuite/c-c++-common/torture/strub-const4.c | 17 ++ gcc/testsuite/c-c++-common/torture/strub-data5.c | 6 +- gcc/testsuite/c-c++-common/torture/strub-pure1.c | 18 ++ gcc/testsuite/c-c++-common/torture/strub-pure2.c | 22 ++ gcc/testsuite/c-c++-common/torture/strub-pure3.c | 13 + gcc/testsuite/c-c++-common/torture/strub-pure4.c | 17 ++ gcc/testsuite/c-c++-common/torture/strub-run1.c | 85 +++++++ gcc/testsuite/c-c++-common/torture/strub-run2.c | 75 ++++++ gcc/testsuite/c-c++-common/torture/strub-run3.c | 75 ++++++ .../g++.dg/{wrappers/strub1.C => strub-run1.C} | 1 + gcc/testsuite/g++.dg/wrappers/strub2.C | 22 -- gcc/testsuite/g++.dg/wrappers/strub3.C | 22 -- gcc/testsuite/g++.dg/wrappers/strub4.C | 18 -- 37 files changed, 1117 insertions(+), 162 deletions(-) diff --git a/gcc/builtins.c b/gcc/builtins.c index f387d93974f..813d02a67d2 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -80,6 +80,7 @@ along with GCC; see the file COPYING3. If not see #include "attr-fnspec.h" #include "demangle.h" #include "gimple-range.h" +#include "ipa-strub.h" struct target_builtins default_target_builtins; #if SWITCHABLE_TARGET @@ -7926,7 +7927,23 @@ expand_builtin_strub_enter (tree exp) if (optimize < 1 || flag_no_inline) return NULL_RTX; - rtx stktop = expand_builtin_stack_address (); + rtx stktop = NULL_RTX; + +#ifdef RED_ZONE_SIZE || 1 + if (tree wmptr = (optimize + ? find_watermark_parm (current_function_decl) + : NULL_TREE)) + { + tree wmtype = TREE_TYPE (TREE_TYPE (wmptr)); + tree wmtree = fold_build2 (MEM_REF, wmtype, wmptr, + build_int_cst (TREE_TYPE (wmptr), 0)); + rtx wmark = expand_expr (wmtree, NULL_RTX, ptr_mode, EXPAND_MEMORY); + stktop = force_reg (ptr_mode, wmark); + } +#endif + + if (!stktop) + stktop = expand_builtin_stack_address (); tree wmptr = CALL_EXPR_ARG (exp, 0); tree wmtype = TREE_TYPE (TREE_TYPE (wmptr)); @@ -7952,6 +7969,52 @@ expand_builtin_strub_update (tree exp) rtx stktop = expand_builtin_stack_address (); +#ifdef RED_ZONE_SIZE + /* Here's how the strub enter, update and leave functions deal with red zones. + + If it weren't for red zones, update, called from within a strub context, + would bump the watermark to the top of the stack. Enter and leave, running + in the caller, would use the caller's top of stack address both to + initialize the watermark passed to the callee, and to start strubbing the + stack afterwards. + + Ideally, we'd update the watermark so as to cover the used amount of red + zone, and strub starting at the caller's other end of the (presumably + unused) red zone. Normally, only leaf functions use the red zone, but at + this point we can't tell whether a function is a leaf, nor can we tell how + much of the red zone it uses. Furthermore, some strub contexts may have + been inlined so that update and leave are called from the same stack frame, + and the strub builtins may all have been inlined, turning a strub function + into a leaf. + + So cleaning the range from the caller's stack pointer (one end of the red + zone) to the (potentially inlined) callee's (other end of the) red zone + could scribble over the caller's own red zone. + + We avoid this possibility by arranging for callers that are strub contexts + to use their own watermark as the strub starting point. So, if A calls B, + and B calls C, B will tell A to strub up to the end of B's red zone, and + will strub itself only the part of C's stack frame and red zone that + doesn't overlap with B's. With that, we don't need to know who's leaf and + who isn't: inlined calls will shrink their strub window to zero, each + remaining call will strub some portion of the stack, and eventually the + strub context will return to a caller that isn't a strub context itself, + that will therefore use its own stack pointer as the strub starting point. + It's not a leaf, because strub contexts can't be inlined into non-strub + contexts, so it doesn't use the red zone, and it will therefore correctly + strub up the callee's stack frame up to the end of the callee's red zone. + Neat! */ + if (true /* (flags_from_decl_or_type (current_function_decl) & ECF_LEAF) */) + { + poly_int64 red_zone_size = RED_ZONE_SIZE; +#if STACK_GROWS_DOWNWARD + red_zone_size = -red_zone_size; +#endif + stktop = plus_constant (ptr_mode, stktop, red_zone_size); + stktop = force_reg (ptr_mode, stktop); + } +#endif + tree wmptr = CALL_EXPR_ARG (exp, 0); tree wmtype = TREE_TYPE (TREE_TYPE (wmptr)); tree wmtree = fold_build2 (MEM_REF, wmtype, wmptr, @@ -7982,7 +8045,23 @@ expand_builtin_strub_leave (tree exp) if (optimize < 2 || flag_no_inline) return NULL_RTX; - rtx stktop = expand_builtin_stack_address (); + rtx stktop = NULL_RTX; + +#ifdef RED_ZONE_SIZE || 1 + if (tree wmptr = (optimize + ? find_watermark_parm (current_function_decl) + : NULL_TREE)) + { + tree wmtype = TREE_TYPE (TREE_TYPE (wmptr)); + tree wmtree = fold_build2 (MEM_REF, wmtype, wmptr, + build_int_cst (TREE_TYPE (wmptr), 0)); + rtx wmark = expand_expr (wmtree, NULL_RTX, ptr_mode, EXPAND_MEMORY); + stktop = force_reg (ptr_mode, wmark); + } +#endif + + if (!stktop) + stktop = expand_builtin_stack_address (); tree wmptr = CALL_EXPR_ARG (exp, 0); tree wmtype = TREE_TYPE (TREE_TYPE (wmptr)); diff --git a/gcc/ipa-strub.c b/gcc/ipa-strub.c index e302f0ec1c5..ee9cab3318c 100644 --- a/gcc/ipa-strub.c +++ b/gcc/ipa-strub.c @@ -210,10 +210,16 @@ get_strub_mode_from_attr (tree strub_attr, bool var_p = false) return mode; } +static enum strub_mode +get_strub_mode_from_decl (tree fndecl) +{ + return get_strub_mode_from_attr (get_strub_attr_from_decl (fndecl)); +} + static enum strub_mode get_strub_mode (cgraph_node *node) { - return get_strub_mode_from_attr (get_strub_attr_from_decl (node->decl)); + return get_strub_mode_from_decl (node->decl); } static enum strub_mode @@ -263,7 +269,7 @@ calls_builtin_apply_args_p (cgraph_node *node, bool report = false) break; sorry_at (gimple_location (e->call_stmt), - "at-calls strub does not support call to %qD", + "at-calls % does not support call to %qD", cdecl); } @@ -292,7 +298,8 @@ can_strub_p (cgraph_node *node, bool report = false) return result; sorry_at (DECL_SOURCE_LOCATION (node->decl), - "%qD is not eligible for strub because of attribute %", + "%qD is not eligible for %" + " because of attribute %", node->decl); } @@ -352,7 +359,7 @@ can_strub_internally_p (cgraph_node *node, bool report = false) return result; sorry_at (DECL_SOURCE_LOCATION (node->decl), - "%qD is not eligible for internal strub" + "%qD is not eligible for internal %" " because of attribute %", node->decl); } @@ -372,7 +379,7 @@ can_strub_internally_p (cgraph_node *node, bool report = false) return result; sorry_at (gimple_location (e->call_stmt), - "internal strub does not support call to %qD", + "internal % does not support call to %qD", cdecl); } @@ -411,7 +418,7 @@ can_strub_internally_p (cgraph_node *node, bool report = false) return result; sorry_at (gimple_location (label_stmt), - "internal strub does not support user labels"); + "internal % does not support user labels"); } } @@ -425,16 +432,16 @@ can_strub_internally_p (cgraph_node *node, bool report = false) return result; sorry_at (DECL_SOURCE_LOCATION (node->decl), - "%qD has too many arguments for internal strub", + "%qD has too many arguments for internal %", node->decl); } - if (result) - /* Since we're not changing the function identity proper, just - moving its full implementation, we *could* disable - fun->cannot_be_copied_reason and/or temporarily drop a noclone - attribute. */ - gcc_checking_assert (tree_versionable_function_p (node->decl)); + /* Since we're not changing the function identity proper, just + moving its full implementation, we *could* disable + fun->cannot_be_copied_reason and/or temporarily drop a noclone + attribute. */ + gcc_checking_assert (!result || !node->has_gimple_body_p () + || tree_versionable_function_p (node->decl)); return result; } @@ -489,8 +496,22 @@ strub_callable_builtin_p (cgraph_node *node) case BUILT_IN_NONE: gcc_unreachable (); - /* ??? Make all builtins callable. We wish to make any builtin call the - compiler might introduce on its own callable. Anything that is + /* This temporarily allocates stack for the call, and we can't reasonably + update the watermark for that. Besides, we don't check the actual call + target, nor its signature, and it seems to be overkill to as much as + try to do so. */ + case BUILT_IN_APPLY: + return false; + + /* Conversely, this shouldn't be called from within strub contexts, since + the caller may have had its signature modified. STRUB_INTERNAL is ok, + the call will remain in the STRUB_WRAPPER, and removed from the + STRUB_WRAPPED clone. */ + case BUILT_IN_APPLY_ARGS: + return false; + + /* ??? Make all other builtins callable. We wish to make any builtin call + the compiler might introduce on its own callable. Anything that is predictable enough as to be known not to allow stack data that should be strubbed to unintentionally escape to non-strub contexts can be allowed, and pretty much every builtin appears to fit this description. @@ -698,7 +719,8 @@ compute_strub_mode (cgraph_node *node, tree strub_attr) { gcc_checking_assert (analyze_body); error_at (DECL_SOURCE_LOCATION (node->decl), - "%qD requires strub, but no viable strub mode was found", + "%qD requires %," + " but no viable % mode was found", node->decl); break; } @@ -751,7 +773,7 @@ set_strub_mode_to (cgraph_node *node, enum strub_mode mode) && mode == STRUB_INLINABLE)) { error_at (DECL_SOURCE_LOCATION (node->decl), - "strub mode %i selected for %qD, when %i was requested", + "% mode %i selected for %qD, when %i was requested", (int) mode, node->decl, (int) get_strub_mode_from_attr (attr)); if (node->alias) @@ -979,7 +1001,7 @@ verify_strub () if (callee_mode == STRUB_DISABLED || callee_mode == STRUB_INTERNAL) error_at (gimple_location (e->call_stmt), - "indirect non-strub call in strub context %qD", + "indirect non-% call in % context %qD", node->decl); } @@ -987,9 +1009,22 @@ verify_strub () { gcc_checking_assert (!e->indirect_unknown_callee); if (!strub_callable_from_p (e->callee, node)) - error_at (gimple_location (e->call_stmt), - "calling non-strub %qD in strub context %qD", - e->callee->decl, node->decl); + { + if (get_strub_mode (e->callee) == STRUB_INLINABLE) + error_at (gimple_location (e->call_stmt), + "calling % % %qD" + " in non-% context %qD", + e->callee->decl, node->decl); + else if (fndecl_built_in_p (e->callee->decl, BUILT_IN_APPLY_ARGS) + && get_strub_mode (node) == STRUB_INTERNAL) + /* This is ok, it will be kept in the STRUB_WRAPPER, and removed + from the STRUB_WRAPPED's strub context. */ + continue; + else + error_at (gimple_location (e->call_stmt), + "calling non-% %qD in % context %qD", + e->callee->decl, node->decl); + } } } @@ -1067,27 +1102,25 @@ public: /* Use a distinct ptr_type_node to denote the watermark, so that we can recognize it in arg lists and avoid modifying types twice. */ - DEF_TYPE (wmt, build_distinct_type_copy (ptr_type_node)) + DEF_TYPE (wmt, build_variant_type_copy (ptr_type_node)) - DEF_TYPE (pwmt, build_pointer_type (get_wmt ())) + DEF_TYPE (pwmt, build_reference_type (get_wmt ())) DEF_TYPE (qpwmt, build_qualified_type (get_pwmt (), TYPE_QUAL_RESTRICT - | TYPE_QUAL_CONST)) - - DEF_TYPE (pptr, build_pointer_type (ptr_type_node)) + /* | TYPE_QUAL_CONST */)) - DEF_TYPE (qpptr, - build_qualified_type (get_pptr (), + DEF_TYPE (qptr, + build_qualified_type (ptr_type_node, TYPE_QUAL_RESTRICT | TYPE_QUAL_CONST)) DEF_TYPE (qpvalst, - build_qualified_type (build_pointer_type + build_qualified_type (build_reference_type (va_list_type_node), TYPE_QUAL_RESTRICT - | TYPE_QUAL_CONST)) + /* | TYPE_QUAL_CONST */)) #undef DEF_TYPE @@ -1159,7 +1192,7 @@ public: DEF_IDENT (watermark_ptr) DEF_IDENT (va_list_ptr) - DEF_IDENT (apply_args_ptr) + DEF_IDENT (apply_args) #undef DEF_IDENT @@ -1493,6 +1526,39 @@ ipa_strub_set_mode_for_new_functions () last_cgraph_order = symtab->order; } +/* Return the PARM_DECL of the incoming watermark pointer, if there is one. */ +tree +find_watermark_parm (tree fndecl) +{ + switch (get_strub_mode_from_decl (fndecl)) + { + case STRUB_WRAPPED: + case STRUB_AT_CALLS: + case STRUB_AT_CALLS_OPT: + break; + + case STRUB_INTERNAL: + case STRUB_WRAPPER: + case STRUB_CALLABLE: + case STRUB_DISABLED: + case STRUB_INLINABLE: + return NULL_TREE; + + default: + gcc_unreachable (); + } + + for (tree parm = DECL_ARGUMENTS (fndecl); parm; parm = DECL_CHAIN (parm)) + if (TREE_TYPE (parm) == pass_ipa_strub::get_qpwmt ()) + { + gcc_checking_assert (DECL_NAME (parm) + == pass_ipa_strub::get_watermark_ptr ()); + return parm; + } + + gcc_unreachable (); +} + /* Adjust a STRUB_AT_CALLS function TYPE, adding a watermark pointer if it hasn't been added yet. Return the named argument count. */ int @@ -1507,7 +1573,7 @@ pass_ipa_strub::adjust_at_calls_type (tree type) tree qpwmptrt = get_qpwmt (); while (*tlist && TREE_VALUE (*tlist) != void_type_node) { - /* The type has alreayd been adjusted. */ + /* The type has already been adjusted. */ if (TREE_VALUE (*tlist) == qpwmptrt) return named_args; named_args++; @@ -1581,22 +1647,37 @@ pass_ipa_strub::adjust_at_calls_call (cgraph_edge *e, int named_args) && (TREE_TYPE (gimple_call_arg (ocall, named_args)) == get_pwmt ()))); - /* ??? If it's a (tail?) call within a strub context, maybe pass on - the strub watermark instead of wrapping the call. */ - - /* Initialize the watermark before the call. */ - tree swm = create_tmp_var (get_wmt (), ".strub.watermark"); - TREE_ADDRESSABLE (swm) = true; - tree swmp = build1 (ADDR_EXPR, get_pwmt (), swm); + /* If we're already within a strub context, pass on the incoming watermark + pointer, and omit the enter and leave calls around the modified call. */ + tree swm, swmp = (false && /* This is disabled for now, to give the + red-zone-capable builtin expanders more thorough + testing. */ + (optimize_size || optimize > 2) + ? find_watermark_parm (e->caller->decl) + : NULL_TREE); + bool omit_own_watermark = swmp; + if (omit_own_watermark) + swm = build2 (MEM_REF, + TREE_TYPE (TREE_TYPE (swmp)), + swmp, + build_int_cst (TREE_TYPE (swmp), 0)); + else + { + swm = create_tmp_var (get_wmt (), ".strub.watermark"); + TREE_ADDRESSABLE (swm) = true; + swmp = build1 (ADDR_EXPR, get_pwmt (), swm); - tree enter = get_enter (); - gcall *stptr = gimple_build_call (enter, 1, - unshare_expr (swmp)); - gsi_insert_before (&gsi, stptr, GSI_SAME_STMT); + /* Initialize the watermark before the call. */ + tree enter = get_enter (); + gcall *stptr = gimple_build_call (enter, 1, + unshare_expr (swmp)); + gsi_insert_before (&gsi, stptr, GSI_SAME_STMT); #if !IMPLICIT_CGRAPH_EDGES - e->caller->create_edge (cgraph_node::get_create (enter), - stptr, gsi_bb (gsi)->count, false); + e->caller->create_edge (cgraph_node::get_create (enter), + stptr, gsi_bb (gsi)->count, false); #endif + } + /* Replace the call with one that passes the swmp argument first. */ gcall *wrcall; @@ -1674,12 +1755,12 @@ pass_ipa_strub::adjust_at_calls_call (cgraph_edge *e, int named_args) build_tree_list (build_tree_list (NULL_TREE, build_string (2, "=m")), - swm)); + unshare_expr (swm))); vec_safe_push (inputs, build_tree_list (build_tree_list (NULL_TREE, build_string (1, "m")), - swm)); + unshare_expr (swm))); gasm *forcemod = gimple_build_asm_vec ("", inputs, outputs, NULL, NULL); gimple_seq_add_stmt (&seq, forcemod); @@ -1693,7 +1774,7 @@ pass_ipa_strub::adjust_at_calls_call (cgraph_edge *e, int named_args) build_tree_list (build_tree_list (NULL_TREE, build_string (1, "m")), - swm)); + unshare_expr (swm))); gasm *force_store = gimple_build_asm_vec ("", inputs, NULL, NULL, NULL); gsi_insert_before (&gsi, force_store, GSI_SAME_STMT); @@ -1701,17 +1782,21 @@ pass_ipa_strub::adjust_at_calls_call (cgraph_edge *e, int named_args) } #endif - gcall *sleave = gimple_build_call (get_leave (), 1, - unshare_expr (swmp)); - gimple_seq_add_stmt (&seq, sleave); + if (!omit_own_watermark) + { + gcall *sleave = gimple_build_call (get_leave (), 1, + unshare_expr (swmp)); + gimple_seq_add_stmt (&seq, sleave); - gassign *clobber = gimple_build_assign (swm, - build_clobber - (TREE_TYPE (swm))); - gimple_seq_add_stmt (&seq, clobber); + gassign *clobber = gimple_build_assign (swm, + build_clobber + (TREE_TYPE (swm))); + gimple_seq_add_stmt (&seq, clobber); + } } - gsi_insert_finally_seq_after_call (gsi, seq); + if (seq) + gsi_insert_finally_seq_after_call (gsi, seq); } unsigned int @@ -1909,7 +1994,7 @@ pass_ipa_strub::execute (function *) if (!DECL_STRUCT_FUNCTION (onode->decl)) { inform (DECL_SOURCE_LOCATION (onode->decl), - "not splitting struct-less function %qD for stack scrubbing", + "not splitting struct-less function %qD for %", onode->decl); continue; } @@ -1917,7 +2002,7 @@ pass_ipa_strub::execute (function *) if (!onode->lowered) { inform (DECL_SOURCE_LOCATION (onode->decl), - "not splitting non-lowered function %qD for stack scrubbing", + "not splitting non-lowered function %qD for %", onode->decl); continue; } @@ -1929,7 +2014,7 @@ pass_ipa_strub::execute (function *) if (!tree_versionable_function_p (onode->decl)) { inform (DECL_SOURCE_LOCATION (onode->decl), - "%qD cannot be split for stack scrubbing", + "%qD cannot be split for %", onode->decl); continue; } @@ -1956,7 +2041,7 @@ pass_ipa_strub::execute (function *) { ipa_adjusted_param aaadj = {}; aaadj.op = IPA_PARAM_OP_NEW; - aaadj.type = get_qpptr (); + aaadj.type = get_qptr (); vec_safe_push (nparms, aaadj); } @@ -1982,7 +2067,7 @@ pass_ipa_strub::execute (function *) if (!nnode) { error_at (DECL_SOURCE_LOCATION (onode->decl), - "failed to split %qD for stack scrubbing", + "failed to split %qD for %", onode->decl); continue; } @@ -2181,8 +2266,8 @@ pass_ipa_strub::execute (function *) only of reading because const/pure. */ if (apply_args) { - nspec[curlen++] = (no_writes_p ? 'r' : '.'); - nspec[curlen++] = (no_writes_p ? 't' : ' '); + nspec[curlen++] = 'r'; + nspec[curlen++] = ' '; } if (is_stdarg) { @@ -2485,24 +2570,24 @@ pass_ipa_strub::execute (function *) } { - tree aaptr = NULL_TREE; + tree aaval = NULL_TREE; tree vaptr = NULL_TREE; tree wmptr = NULL_TREE; for (tree arg = DECL_ARGUMENTS (nnode->decl); arg; arg = DECL_CHAIN (arg)) { - aaptr = vaptr; + aaval = vaptr; vaptr = wmptr; wmptr = arg; } if (!apply_args) - aaptr = NULL_TREE; + aaval = NULL_TREE; /* The trailing args are [apply_args], [va_list_ptr], and watermark. If we don't have a va_list_ptr, the penultimate argument is apply_args. */ else if (!is_stdarg) - aaptr = vaptr; + aaval = vaptr; if (!is_stdarg) vaptr = NULL_TREE; @@ -2522,10 +2607,10 @@ pass_ipa_strub::execute (function *) if (apply_args) { - DECL_NAME (aaptr) = get_apply_args_ptr (); - DECL_ARTIFICIAL (aaptr) = 1; - DECL_IGNORED_P (aaptr) = 1; - TREE_USED (aaptr) = 1; + DECL_NAME (aaval) = get_apply_args (); + DECL_ARTIFICIAL (aaval) = 1; + DECL_IGNORED_P (aaval) = 1; + TREE_USED (aaval) = 1; } push_cfun (DECL_STRUCT_FUNCTION (nnode->decl)); @@ -2582,9 +2667,10 @@ pass_ipa_strub::execute (function *) else if (fndecl && is_stdarg && fndecl_built_in_p (fndecl, BUILT_IN_VA_START)) { - if (builtin_decl_explicit (BUILT_IN_VA_START) != fndecl) - sorry_at (gimple_location (call), - "nonstandard stdarg conventions"); + /* Using a non-default stdarg ABI makes the function ineligible + for internal strub. */ + gcc_checking_assert (builtin_decl_explicit (BUILT_IN_VA_START) + == fndecl); tree bvacopy = builtin_decl_explicit (BUILT_IN_VA_COPY); gimple_call_set_fndecl (call, bvacopy); tree arg = vaptr; @@ -2607,7 +2693,9 @@ pass_ipa_strub::execute (function *) && fndecl_built_in_p (fndecl, BUILT_IN_APPLY_ARGS)) { tree lhs = gimple_call_lhs (call); - gassign *assign = gimple_build_assign (lhs, aaptr); + gimple *assign = (lhs + ? gimple_build_assign (lhs, aaval) + : gimple_build_nop ()); gsi_replace (&gsi, assign, true); cgraph_edge::remove (e); } @@ -2650,7 +2738,7 @@ pass_ipa_strub::execute (function *) if (apply_args) { - tree aalst = create_tmp_var (ptr_type_node, ".strub.appargs"); + tree aalst = create_tmp_var (ptr_type_node, ".strub.apply_args"); tree bappargs = builtin_decl_explicit (BUILT_IN_APPLY_ARGS); gcall *appargs = gimple_build_call (bappargs, 0); gimple_call_set_lhs (appargs, aalst); diff --git a/gcc/ipa-strub.h b/gcc/ipa-strub.h index cadbca5002a..ea8ee857e8e 100644 --- a/gcc/ipa-strub.h +++ b/gcc/ipa-strub.h @@ -23,3 +23,4 @@ along with GCC; see the file COPYING3. If not see doesn't have to be called directly by CALLER, but the returned value says nothing about intervening functions. */ extern bool strub_inlinable_p (cgraph_node *callee, cgraph_node *caller); +extern tree find_watermark_parm (tree fndecl); diff --git a/gcc/testsuite/c-c++-common/strub-O2.c b/gcc/testsuite/c-c++-common/strub-O2.c index 9cc39e763b1..7848c46d179 100644 --- a/gcc/testsuite/c-c++-common/strub-O2.c +++ b/gcc/testsuite/c-c++-common/strub-O2.c @@ -13,4 +13,4 @@ int f() { /* { dg-final { scan-rtl-dump-not "strub_enter" "expand" } } */ /* { dg-final { scan-rtl-dump-not "strub_update" "expand" } } */ /* { dg-final { scan-rtl-dump "strub_leave" "expand" } } */ -/* { dg-final { scan-rtl-dump "\n\[(\]call_insn\[^\n\]*strub_leave.*\n\[(\]code_label" "expand" } } */ +/* { dg-final { scan-rtl-dump "\[(\]call\[^\n\]*strub_leave.*\n\[(\]code_label" "expand" } } */ diff --git a/gcc/testsuite/c-c++-common/strub-O2fni.c b/gcc/testsuite/c-c++-common/strub-O2fni.c index 51cae845d5f..85a8f76785e 100644 --- a/gcc/testsuite/c-c++-common/strub-O2fni.c +++ b/gcc/testsuite/c-c++-common/strub-O2fni.c @@ -1,7 +1,7 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -fstrub=default -fdump-rtl-expand -fno-inline-functions" } */ +/* { dg-options "-O2 -fstrub=default -fdump-rtl-expand -fno-inline" } */ -/* With -fno-inline-functions, none of the strub builtins are inlined. */ +/* With -fno-inline, none of the strub builtins are inlined. */ int __attribute__ ((__strub__)) var; @@ -12,4 +12,4 @@ int f() { /* { dg-final { scan-rtl-dump "strub_enter" "expand" } } */ /* { dg-final { scan-rtl-dump "strub_update" "expand" } } */ /* { dg-final { scan-rtl-dump "strub_leave" "expand" } } */ -/* { dg-final { scan-rtl-dump-not "\n\[(\]call_insn\[^\n\]*strub_leave.*\n\[(\]code_label" "expand" } } */ +/* { dg-final { scan-rtl-dump-not "\[(\]call\[^\n\]*strub_leave.*\n\[(\]code_label" "expand" } } */ diff --git a/gcc/testsuite/c-c++-common/strub-O3fni.c b/gcc/testsuite/c-c++-common/strub-O3fni.c index 8f67b613be8..a2eedfd96b2 100644 --- a/gcc/testsuite/c-c++-common/strub-O3fni.c +++ b/gcc/testsuite/c-c++-common/strub-O3fni.c @@ -1,7 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-O3 -fstrub=default -fdump-rtl-expand -fno-inline" } */ -/* With -fno-inline-functions, none of the strub builtins are inlined. */ +/* With -fno-inline, none of the strub builtins are inlined. */ int __attribute__ ((__strub__)) var; @@ -12,4 +12,4 @@ int f() { /* { dg-final { scan-rtl-dump "strub_enter" "expand" } } */ /* { dg-final { scan-rtl-dump "strub_update" "expand" } } */ /* { dg-final { scan-rtl-dump "strub_leave" "expand" } } */ -/* { dg-final { scan-rtl-dump-not "\n\[(\]call_insn\[^\n\]*strub_leave.*\n\[(\]code_label" "expand" } } */ +/* { dg-final { scan-rtl-dump-not "\[(\]call\[^\n\]*strub_leave.*\n\[(\]code_label" "expand" } } */ diff --git a/gcc/testsuite/c-c++-common/strub-Og.c b/gcc/testsuite/c-c++-common/strub-Og.c index 6f60349573f..e5cb1f60541 100644 --- a/gcc/testsuite/c-c++-common/strub-Og.c +++ b/gcc/testsuite/c-c++-common/strub-Og.c @@ -13,4 +13,4 @@ int f() { /* { dg-final { scan-rtl-dump-not "strub_enter" "expand" } } */ /* { dg-final { scan-rtl-dump "strub_update" "expand" } } */ /* { dg-final { scan-rtl-dump "strub_leave" "expand" } } */ -/* { dg-final { scan-rtl-dump-not "\n\[(\]call_insn\[^\n\]*strub_leave.*\n\[(\]code_label" "expand" } } */ +/* { dg-final { scan-rtl-dump-not "\[(\]call\[^\n\]*strub_leave.*\n\[(\]code_label" "expand" } } */ diff --git a/gcc/testsuite/c-c++-common/strub-Os.c b/gcc/testsuite/c-c++-common/strub-Os.c index 5d1c08a7528..194aacc2c05 100644 --- a/gcc/testsuite/c-c++-common/strub-Os.c +++ b/gcc/testsuite/c-c++-common/strub-Os.c @@ -15,4 +15,4 @@ int f() { /* { dg-final { scan-rtl-dump-not "strub_enter" "expand" } } */ /* { dg-final { scan-rtl-dump-not "strub_update" "expand" } } */ /* { dg-final { scan-rtl-dump "strub_leave" "expand" } } */ -/* { dg-final { scan-rtl-dump-not "\n\[(\]call_insn\[^\n\]*strub_leave.*\n\[(\]code_label" "expand" } } */ +/* { dg-final { scan-rtl-dump-not "\[(\]call\[^\n\]*strub_leave.*\n\[(\]code_label" "expand" } } */ diff --git a/gcc/testsuite/c-c++-common/strub-all1.c b/gcc/testsuite/c-c++-common/strub-all1.c index 54daf84656c..46e84bf6560 100644 --- a/gcc/testsuite/c-c++-common/strub-all1.c +++ b/gcc/testsuite/c-c++-common/strub-all1.c @@ -3,9 +3,9 @@ /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub. */ -static void +static inline void __attribute__ ((__always_inline__)) -h() { /* { dg-warning "might not be inlinable" } */ +h() { } /* g becomes STRUB_AT_CALLS, because of the flag. */ diff --git a/gcc/testsuite/c-c++-common/strub-apply1.c b/gcc/testsuite/c-c++-common/strub-apply1.c new file mode 100644 index 00000000000..f180b17f30e --- /dev/null +++ b/gcc/testsuite/c-c++-common/strub-apply1.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-fstrub=default" } */ + +void __attribute__ ((__strub__ (3))) +apply_function (void *args) +{ + __builtin_apply (0, args, 0); +} + +void __attribute__ ((__strub__ (2))) +apply_args (int i, int j, double d) +{ + void *args = __builtin_apply_args (); + apply_function (args); +} diff --git a/gcc/testsuite/c-c++-common/strub-apply2.c b/gcc/testsuite/c-c++-common/strub-apply2.c new file mode 100644 index 00000000000..379a54b73b7 --- /dev/null +++ b/gcc/testsuite/c-c++-common/strub-apply2.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-fstrub=default" } */ + +extern void __attribute__ ((__strub__)) +apply_function (void *args); + +void __attribute__ ((__strub__)) +apply_args (int i, int j, double d) /* { dg-error "selected" } */ +{ + void *args = __builtin_apply_args (); /* { dg-message "does not support" } */ + apply_function (args); +} diff --git a/gcc/testsuite/c-c++-common/strub-apply3.c b/gcc/testsuite/c-c++-common/strub-apply3.c new file mode 100644 index 00000000000..9b4786be698 --- /dev/null +++ b/gcc/testsuite/c-c++-common/strub-apply3.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "-fstrub=default" } */ + +void __attribute__ ((__strub__)) +apply_function (void *args) +{ + __builtin_apply (0, args, 0); /* { dg-error "in .strub. context" } */ +} diff --git a/gcc/testsuite/c-c++-common/strub-apply4.c b/gcc/testsuite/c-c++-common/strub-apply4.c new file mode 100644 index 00000000000..409f747743e --- /dev/null +++ b/gcc/testsuite/c-c++-common/strub-apply4.c @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fstrub=default -fdump-ipa-strubm" } */ + +/* Check that implicit enabling of strub mode selects internal strub when the + function uses __builtin_apply_args, that prevents the optimization to + at-calls mode. */ + +int __attribute__ ((__strub__)) var; + +static inline void +apply_args (int i, int j, double d) +{ + var++; + __builtin_apply_args (); +} + +void f() { + apply_args (1, 2, 3); +} + +/* { dg-final { scan-ipa-dump-times "strub \[(\]2\[)\]" 1 "strubm" } } */ diff --git a/gcc/testsuite/c-c++-common/strub-at-calls1.c b/gcc/testsuite/c-c++-common/strub-at-calls1.c index 0d1b9fce833..d964b07ae5d 100644 --- a/gcc/testsuite/c-c++-common/strub-at-calls1.c +++ b/gcc/testsuite/c-c++-common/strub-at-calls1.c @@ -3,9 +3,9 @@ /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub. */ -static void +static inline void __attribute__ ((__always_inline__)) -h() { /* { dg-warning "might not be inlinable" } */ +h() { } /* g becomes STRUB_AT_CALLS, because of the flag. */ diff --git a/gcc/testsuite/c-c++-common/strub-default1.c b/gcc/testsuite/c-c++-common/strub-default1.c index a1e1803aadc..d579ec62f55 100644 --- a/gcc/testsuite/c-c++-common/strub-default1.c +++ b/gcc/testsuite/c-c++-common/strub-default1.c @@ -3,12 +3,12 @@ static int __attribute__ ((__strub__)) var; -/* h becomes STRUB_STRUB_INLINABLE, because of the use of the strub variable, +/* h becomes STRUB_INLINABLE, because of the use of the strub variable, and the always_inline flag. It would get inlined before pass_ipa_strub, if it weren't for the error. */ -static void +static inline void __attribute__ ((__always_inline__)) -h() { /* { dg-warning "might not be inlinable" } */ +h() { var++; } @@ -34,7 +34,7 @@ f() { /* { dg-final { scan-ipa-dump-times "strub \[(\]2\[)\]" 1 "strubm" } } */ /* { dg-final { scan-ipa-dump-times "strub \[(\]" 4 "strub" } } */ -/* { dg-final { scan-ipa-dump-times "strub \[(\]-3\[)\]" 1 "strubm" } } */ +/* { dg-final { scan-ipa-dump-times "strub \[(\]-3\[)\]" 1 "strub" } } */ /* { dg-final { scan-ipa-dump-times "strub \[(\]-4\[)\]" 1 "strub" } } */ /* { dg-final { scan-ipa-dump-times "strub \[(\]-1\[)\]" 1 "strub" } } */ /* { dg-final { scan-ipa-dump-times "strub \[(\]-2\[)\]" 1 "strub" } } */ diff --git a/gcc/testsuite/c-c++-common/strub-internal1.c b/gcc/testsuite/c-c++-common/strub-internal1.c index b9bd787df0a..a74658c9ac9 100644 --- a/gcc/testsuite/c-c++-common/strub-internal1.c +++ b/gcc/testsuite/c-c++-common/strub-internal1.c @@ -3,9 +3,9 @@ /* h becomes STRUB_CALLABLE, rather than STRUB_INLINABLE, because of the strub-enabling -fstrub flag, and gets inlined before pass_ipa_strub. */ -static void +static inline void __attribute__ ((__always_inline__)) -h() { /* { dg-warning "might not be inlinable" } */ +h() { } /* g becomes STRUB_INTERNAL because of the flag, and gets split into diff --git a/gcc/testsuite/c-c++-common/strub-parms1.c b/gcc/testsuite/c-c++-common/strub-parms1.c new file mode 100644 index 00000000000..0422ccc7f7d --- /dev/null +++ b/gcc/testsuite/c-c++-common/strub-parms1.c @@ -0,0 +1,48 @@ +/* { dg-do compile } */ +/* { dg-options "-fstrub=default -fdump-ipa-strub" } */ + +#include + +void __attribute__ ((__strub__ (2))) +small_args (int i, long long l, void *p, void **q, double d, char c) +{ +} + +/* { dg-final { scan-ipa-dump "\nvoid small_args.strub.\[0-9\]* \[(\]int i, long long int l, void \\* p, void \\* \\* q, double d, char c, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */ +/* { dg-final { scan-ipa-dump " small_args.strub.\[0-9\]* \[(\]\[^&\]*&.strub.watermark.\[0-9\]*\[)\]" "strub" } } */ + + +struct large_arg { + int x[128]; +}; + +void __attribute__ ((__strub__ (2))) +large_byref_arg (struct large_arg la) +{ +} + +/* { dg-final { scan-ipa-dump "\nvoid large_byref_arg.strub.\[0-9\]* \[(\]struct large_arg & la, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */ +/* { dg-final { scan-ipa-dump " large_byref_arg.strub.\[0-9\]* \[(\]&\[^&\]*&.strub.watermark.\[0-9\]*\[)\]" "strub" } } */ + +void __attribute__ ((__strub__ (2))) +std_arg (int i, ...) +{ + va_list vl; + va_start (vl, i); + va_end (vl); +} + +/* { dg-final { scan-ipa-dump "\nvoid std_arg.strub.\[0-9\]* \[(\]int i, \[^&,\]* &\[^&,\]*.strub.va_list_ptr, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */ +/* { dg-final { scan-ipa-dump " std_arg.strub.\[0-9\]* \[(\]\[^&\]*&.strub.va_list.\[0-9\]*, &.strub.watermark.\[0-9\]*\[)\]" "strub" } } */ +/* { dg-final { scan-ipa-dump-times "va_start \\(" 1 "strub" } } */ +/* { dg-final { scan-ipa-dump-times "va_copy \\(" 1 "strub" } } */ +/* { dg-final { scan-ipa-dump-times "va_end \\(" 2 "strub" } } */ + +void __attribute__ ((__strub__ (2))) +apply_args (int i, int j, double d) +{ + __builtin_apply_args (); +} + +/* { dg-final { scan-ipa-dump "\nvoid apply_args.strub.\[0-9\]* \[(\]int i, int j, double d, void \\*\[^&,\]*.strub.apply_args, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */ +/* { dg-final { scan-ipa-dump " apply_args.strub.\[0-9\]* \[(\]\[^&\]*.strub.apply_args.\[0-9\]*_\[0-9\]*, &.strub.watermark.\[0-9\]*\[)\]" "strub" } } */ diff --git a/gcc/testsuite/c-c++-common/strub-parms2.c b/gcc/testsuite/c-c++-common/strub-parms2.c new file mode 100644 index 00000000000..aaf02a2cd46 --- /dev/null +++ b/gcc/testsuite/c-c++-common/strub-parms2.c @@ -0,0 +1,36 @@ +/* { dg-do compile } */ +/* { dg-options "-fstrub=default -fdump-ipa-strub" } */ + +#include + +void __attribute__ ((__strub__ (1))) +small_args (int i, long long l, void *p, void **q, double d, char c) +{ +} + +/* { dg-final { scan-ipa-dump "\nvoid small_args \[(\]int i, long long int l, void \\* p, void \\* \\* q, double d, char c, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */ + + +struct large_arg { + int x[128]; +}; + +void __attribute__ ((__strub__ (1))) +large_byref_arg (struct large_arg la) +{ +} + +/* { dg-final { scan-ipa-dump "\nvoid large_byref_arg \[(\]struct large_arg la, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */ + +void __attribute__ ((__strub__ (1))) +std_arg (int i, ...) +{ + va_list vl; + va_start (vl, i); + va_end (vl); +} + +/* { dg-final { scan-ipa-dump "\nvoid std_arg \[(\]int i, void \\* &\[^&,\]*.strub.watermark_ptr\[, .]*\[)\]" "strub" } } */ +/* { dg-final { scan-ipa-dump-times "va_start \\(" 1 "strub" } } */ +/* { dg-final { scan-ipa-dump-not "va_copy \\(" "strub" } } */ +/* { dg-final { scan-ipa-dump-times "va_end \\(" 1 "strub" } } */ diff --git a/gcc/testsuite/c-c++-common/strub-parms3.c b/gcc/testsuite/c-c++-common/strub-parms3.c new file mode 100644 index 00000000000..2846098160d --- /dev/null +++ b/gcc/testsuite/c-c++-common/strub-parms3.c @@ -0,0 +1,58 @@ +/* { dg-do compile } */ +/* { dg-options "-fstrub=default -fdump-ipa-strub" } */ + +/* Check that uses of a strub variable implicitly enables internal strub for + publicly-visible functions, and causes the same transformations to their + signatures as those in strub-parms1.c. */ + +#include + +int __attribute__ ((__strub__)) var; + +void +small_args (int i, long long l, void *p, void **q, double d, char c) +{ + var++; +} + +/* { dg-final { scan-ipa-dump "\nvoid small_args.strub.\[0-9\]* \[(\]int i, long long int l, void \\* p, void \\* \\* q, double d, char c, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */ +/* { dg-final { scan-ipa-dump " small_args.strub.\[0-9\]* \[(\]\[^&\]*&.strub.watermark.\[0-9\]*\[)\]" "strub" } } */ + + +struct large_arg { + int x[128]; +}; + +void +large_byref_arg (struct large_arg la) +{ + var++; +} + +/* { dg-final { scan-ipa-dump "\nvoid large_byref_arg.strub.\[0-9\]* \[(\]struct large_arg & la, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */ +/* { dg-final { scan-ipa-dump " large_byref_arg.strub.\[0-9\]* \[(\]&\[^&\]*&.strub.watermark.\[0-9\]*\[)\]" "strub" } } */ + +void +std_arg (int i, ...) +{ + va_list vl; + va_start (vl, i); + var++; + va_end (vl); +} + +/* { dg-final { scan-ipa-dump "\nvoid std_arg.strub.\[0-9\]* \[(\]int i, \[^&,\]* &\[^&,\]*.strub.va_list_ptr, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */ +/* { dg-final { scan-ipa-dump " std_arg.strub.\[0-9\]* \[(\]\[^&\]*&.strub.va_list.\[0-9\]*, &.strub.watermark.\[0-9\]*\[)\]" "strub" } } */ +/* { dg-final { scan-ipa-dump-times "va_start \\(" 1 "strub" } } */ +/* { dg-final { scan-ipa-dump-times "va_copy \\(" 1 "strub" } } */ +/* { dg-final { scan-ipa-dump-times "va_end \\(" 2 "strub" } } */ + +void +apply_args (int i, int j, double d) +{ + var++; + __builtin_apply_args (); +} + +/* { dg-final { scan-ipa-dump "\nvoid apply_args.strub.\[0-9\]* \[(\]int i, int j, double d, void \\*\[^&,\]*.strub.apply_args, void \\* &\[^&,\]*.strub.watermark_ptr\[)\]" "strub" } } */ +/* { dg-final { scan-ipa-dump " apply_args.strub.\[0-9\]* \[(\]\[^&\]*.strub.apply_args.\[0-9\]*_\[0-9\]*, &.strub.watermark.\[0-9\]*\[)\]" "strub" } } */ diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable1.c b/gcc/testsuite/c-c++-common/torture/strub-callable1.c new file mode 100644 index 00000000000..45965f275c9 --- /dev/null +++ b/gcc/testsuite/c-c++-common/torture/strub-callable1.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-fstrub=default -fdump-ipa-strub -fno-inline" } */ + +/* Check that strub and non-strub functions can be called from non-strub + contexts, and that strub and callable functions can be called from strub + contexts. */ + +#define OMIT_IMPERMISSIBLE_CALLS 1 +#include "strub-callable2.c" + +/* { dg-final { scan-ipa-dump-times "strub_enter" 45 "strub" } } */ +/* { dg-final { scan-ipa-dump-times "strub_update" 4 "strub" } } */ +/* { dg-final { scan-ipa-dump-times "strub_leave" 45 "strub" } } */ diff --git a/gcc/testsuite/c-c++-common/torture/strub-callable2.c b/gcc/testsuite/c-c++-common/torture/strub-callable2.c new file mode 100644 index 00000000000..38935e3270b --- /dev/null +++ b/gcc/testsuite/c-c++-common/torture/strub-callable2.c @@ -0,0 +1,264 @@ +/* { dg-do compile } */ +/* { dg-options "-fstrub=default" } */ + +/* Check that impermissible (cross-strub-context) calls are reported. */ + +extern int __attribute__ ((__strub__ (3))) xcallable (void); +extern int __attribute__ ((__strub__ (2))) xinternal (void); +extern int __attribute__ ((__strub__ (1))) xat_calls (void); +extern int __attribute__ ((__strub__ (0))) xdisabled (void); + +int __attribute__ ((__strub__ (3))) callable (void); +int __attribute__ ((__strub__ (2))) internal (void); +int __attribute__ ((__strub__ (1))) at_calls (void); +int __attribute__ ((__strub__ (0))) disabled (void); + +int __attribute__ ((__strub__)) var; +int var_user (void); + +static inline int __attribute__ ((__always_inline__, __strub__ (3))) +icallable (void); +static inline int __attribute__ ((__always_inline__, __strub__ (2))) +iinternal (void); +static inline int __attribute__ ((__always_inline__, __strub__ (1))) +iat_calls (void); +static inline int __attribute__ ((__always_inline__, __strub__ (0))) +idisabled (void); +static inline int __attribute__ ((__always_inline__)) +ivar_user (void); + +static inline int __attribute__ ((__always_inline__, __strub__ (3))) +i_callable (void) { return 0; } +static inline int __attribute__ ((__always_inline__, __strub__ (2))) +i_internal (void) { return var; } +static inline int __attribute__ ((__always_inline__, __strub__ (1))) +i_at_calls (void) { return var; } +static inline int __attribute__ ((__always_inline__, __strub__ (0))) +i_disabled (void) { return 0; } +static inline int __attribute__ ((__always_inline__)) +i_var_user (void) { return var; } + +#define CALLS_GOOD_FOR_STRUB_CONTEXT(ISEP) \ + do { \ + ret += i ## ISEP ## at_calls (); \ + ret += i ## ISEP ## internal (); \ + ret += i ## ISEP ## var_user (); \ + } while (0) + +#define CALLS_GOOD_FOR_NONSTRUB_CONTEXT(ISEP) \ + do { \ + ret += internal (); \ + ret += disabled (); \ + ret += var_user (); \ + \ + ret += i ## ISEP ## disabled (); \ + \ + ret += xinternal (); \ + ret += xdisabled (); \ + } while (0) + +#define CALLS_GOOD_FOR_EITHER_CONTEXT(ISEP) \ + do { \ + ret += i ## ISEP ## callable (); \ + \ + ret += callable (); \ + ret += at_calls (); \ + \ + ret += xat_calls (); \ + ret += xcallable (); \ + } while (0) + +/* Not a strub context, so it can call anything. + Explicitly declared as callable even from within strub contexts. */ +int __attribute__ ((__strub__ (3))) +callable (void) { + int ret = 0; + + /* CALLS_GOOD_FOR_STRUB_CONTEXT(); */ +#if !OMIT_IMPERMISSIBLE_CALLS + ret += iat_calls (); /* { dg-error "in non-.strub. context" } */ + ret += iinternal (); /* { dg-error "in non-.strub. context" } */ + ret += ivar_user (); /* { dg-error "in non-.strub. context" } */ +#endif + CALLS_GOOD_FOR_EITHER_CONTEXT(); + CALLS_GOOD_FOR_NONSTRUB_CONTEXT(); + + return ret; +} + +/* Internal strubbing means the body is a strub context, so it can only call + strub functions, and it's not itself callable from strub functions. */ +int __attribute__ ((__strub__ (2))) +internal (void) { + int ret = var; + + CALLS_GOOD_FOR_STRUB_CONTEXT(); + CALLS_GOOD_FOR_EITHER_CONTEXT(); + /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(); */ +#if !OMIT_IMPERMISSIBLE_CALLS + ret += internal (); /* { dg-error "in .strub. context" } */ + ret += disabled (); /* { dg-error "in .strub. context" } */ + ret += var_user (); /* { dg-error "in .strub. context" } */ + + ret += idisabled (); /* { dg-error "in .strub. context" } */ + + ret += xinternal (); /* { dg-error "in .strub. context" } */ + ret += xdisabled (); /* { dg-error "in .strub. context" } */ +#endif + + return ret; +} + +int __attribute__ ((__strub__ (1))) +at_calls (void) { + int ret = var; + + CALLS_GOOD_FOR_STRUB_CONTEXT(); + CALLS_GOOD_FOR_EITHER_CONTEXT(); + /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(); */ +#if !OMIT_IMPERMISSIBLE_CALLS + ret += internal (); /* { dg-error "in .strub. context" } */ + ret += disabled (); /* { dg-error "in .strub. context" } */ + ret += var_user (); /* { dg-error "in .strub. context" } */ + + ret += idisabled (); /* { dg-error "in .strub. context" } */ + + ret += xinternal (); /* { dg-error "in .strub. context" } */ + ret += xdisabled (); /* { dg-error "in .strub. context" } */ +#endif + + return ret; +} + +int __attribute__ ((__strub__ (0))) +disabled () { + int ret = 0; + + /* CALLS_GOOD_FOR_STRUB_CONTEXT(); */ +#if !OMIT_IMPERMISSIBLE_CALLS + ret += iat_calls (); /* { dg-error "in non-.strub. context" } */ + ret += iinternal (); /* { dg-error "in non-.strub. context" } */ + ret += ivar_user (); /* { dg-error "in non-.strub. context" } */ +#endif + CALLS_GOOD_FOR_EITHER_CONTEXT(); + CALLS_GOOD_FOR_NONSTRUB_CONTEXT(); + + return ret; +} + +int +var_user (void) { + int ret = var; + + CALLS_GOOD_FOR_STRUB_CONTEXT(); + CALLS_GOOD_FOR_EITHER_CONTEXT(); + /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(); */ +#if !OMIT_IMPERMISSIBLE_CALLS + ret += internal (); /* { dg-error "in .strub. context" } */ + ret += disabled (); /* { dg-error "in .strub. context" } */ + ret += var_user (); /* { dg-error "in .strub. context" } */ + + ret += idisabled (); /* { dg-error "in .strub. context" } */ + + ret += xinternal (); /* { dg-error "in .strub. context" } */ + ret += xdisabled (); /* { dg-error "in .strub. context" } */ +#endif + + return ret; +} + +int +icallable (void) +{ + int ret = 0; + + /* CALLS_GOOD_FOR_STRUB_CONTEXT(_); */ +#if !OMIT_IMPERMISSIBLE_CALLS + ret += i_at_calls (); /* { dg-error "in non-.strub. context" } */ + ret += i_internal (); /* { dg-error "in non-.strub. context" } */ + ret += i_var_user (); /* { dg-error "in non-.strub. context" } */ +#endif + CALLS_GOOD_FOR_EITHER_CONTEXT(_); + CALLS_GOOD_FOR_NONSTRUB_CONTEXT(_); + + return ret; +} + +int +iinternal (void) { + int ret = var; + + CALLS_GOOD_FOR_STRUB_CONTEXT(_); + CALLS_GOOD_FOR_EITHER_CONTEXT(_); + /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(_); */ +#if !OMIT_IMPERMISSIBLE_CALLS + ret += internal (); /* { dg-error "in .strub. context" } */ + ret += disabled (); /* { dg-error "in .strub. context" } */ + ret += var_user (); /* { dg-error "in .strub. context" } */ + + ret += i_disabled (); /* { dg-error "in .strub. context" } */ + + ret += xinternal (); /* { dg-error "in .strub. context" } */ + ret += xdisabled (); /* { dg-error "in .strub. context" } */ +#endif + + return ret; +} + +int +iat_calls (void) { + int ret = var; + + CALLS_GOOD_FOR_STRUB_CONTEXT(_); + CALLS_GOOD_FOR_EITHER_CONTEXT(_); + /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(_); */ +#if !OMIT_IMPERMISSIBLE_CALLS + ret += internal (); /* { dg-error "in .strub. context" } */ + ret += disabled (); /* { dg-error "in .strub. context" } */ + ret += var_user (); /* { dg-error "in .strub. context" } */ + + ret += i_disabled (); /* { dg-error "in .strub. context" } */ + + ret += xinternal (); /* { dg-error "in .strub. context" } */ + ret += xdisabled (); /* { dg-error "in .strub. context" } */ +#endif + + return ret; +} + +int +idisabled () { + int ret = 0; + + /* CALLS_GOOD_FOR_STRUB_CONTEXT(_); */ +#if !OMIT_IMPERMISSIBLE_CALLS + ret += i_at_calls (); /* { dg-error "in non-.strub. context" } */ + ret += i_internal (); /* { dg-error "in non-.strub. context" } */ + ret += i_var_user (); /* { dg-error "in non-.strub. context" } */ +#endif + CALLS_GOOD_FOR_EITHER_CONTEXT(_); + CALLS_GOOD_FOR_NONSTRUB_CONTEXT(_); + + return ret; +} + +int +ivar_user (void) { + int ret = var; + + CALLS_GOOD_FOR_STRUB_CONTEXT(_); + CALLS_GOOD_FOR_EITHER_CONTEXT(_); + /* CALLS_GOOD_FOR_NONSTRUB_CONTEXT(_); */ +#if !OMIT_IMPERMISSIBLE_CALLS + ret += internal (); /* { dg-error "in .strub. context" } */ + ret += disabled (); /* { dg-error "in .strub. context" } */ + ret += var_user (); /* { dg-error "in .strub. context" } */ + + ret += i_disabled (); /* { dg-error "in .strub. context" } */ + + ret += xinternal (); /* { dg-error "in .strub. context" } */ + ret += xdisabled (); /* { dg-error "in .strub. context" } */ +#endif + + return ret; +} diff --git a/gcc/testsuite/c-c++-common/torture/strub-const1.c b/gcc/testsuite/c-c++-common/torture/strub-const1.c new file mode 100644 index 00000000000..100fb0c59a9 --- /dev/null +++ b/gcc/testsuite/c-c++-common/torture/strub-const1.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-fstrub=default -fdump-ipa-strub" } */ + +/* Check that, along with a strub const function call, we issue an asm statement + to make sure the watermark passed to it is held in memory before the call, + and another to make sure it is not assumed to be unchanged. */ + +int __attribute__ ((__strub__, __const__)) +f() { + return 0; +} + +int +g() { + return f(); +} + +/* { dg-final { scan-ipa-dump-times "__asm__" 2 "strub" } } */ diff --git a/gcc/testsuite/c-c++-common/torture/strub-const2.c b/gcc/testsuite/c-c++-common/torture/strub-const2.c new file mode 100644 index 00000000000..9e818ac9748 --- /dev/null +++ b/gcc/testsuite/c-c++-common/torture/strub-const2.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-fstrub=default -fdump-ipa-strub" } */ + +/* Check that, along with a strub implicitly-const function call, we issue an + asm statement to make sure the watermark passed to it is held in memory + before the call, and another to make sure it is not assumed to be + unchanged. */ + +int __attribute__ ((__strub__)) +#if ! __OPTIMIZE__ +__attribute__ ((__const__)) +#endif +f() { + return 0; +} + +int +g() { + return f(); +} + +/* { dg-final { scan-ipa-dump-times "__asm__" 2 "strub" } } */ diff --git a/gcc/testsuite/c-c++-common/torture/strub-const3.c b/gcc/testsuite/c-c++-common/torture/strub-const3.c new file mode 100644 index 00000000000..d40e8aa45cb --- /dev/null +++ b/gcc/testsuite/c-c++-common/torture/strub-const3.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-fstrub=default -fdump-ipa-strub" } */ + +/* Check that, along with a strub const wrapping call, we issue an asm statement + to make sure the watermark passed to it is held in memory before the call, + and another to make sure it is not assumed to be unchanged. */ + +int __attribute__ ((__strub__ (2), __const__)) +f() { + return 0; +} + +/* { dg-final { scan-ipa-dump-times "__asm__" 2 "strub" } } */ diff --git a/gcc/testsuite/c-c++-common/torture/strub-const4.c b/gcc/testsuite/c-c++-common/torture/strub-const4.c new file mode 100644 index 00000000000..d4cbdaf10f3 --- /dev/null +++ b/gcc/testsuite/c-c++-common/torture/strub-const4.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-fstrub=default -fdump-ipa-strub" } */ + +/* Check that, along with a strub implicitly-const wrapping call, we issue an + asm statement to make sure the watermark passed to it is held in memory + before the call, and another to make sure it is not assumed to be + unchanged. */ + +int __attribute__ ((__strub__ (2))) +#if ! __OPTIMIZE__ +__attribute__ ((__const__)) +#endif +f() { + return 0; +} + +/* { dg-final { scan-ipa-dump-times "__asm__" 2 "strub" } } */ diff --git a/gcc/testsuite/c-c++-common/torture/strub-data5.c b/gcc/testsuite/c-c++-common/torture/strub-data5.c index 251790d4bbb..07e25af9c53 100644 --- a/gcc/testsuite/c-c++-common/torture/strub-data5.c +++ b/gcc/testsuite/c-c++-common/torture/strub-data5.c @@ -1,15 +1,13 @@ /* { dg-do compile } */ /* { dg-options "-fstrub=default -Werror" } */ -/* The pointer itself is a strub variable, that would enable internal strubbing - if its value was used. Here, it's only overwritten, so no strub. */ typedef int __attribute__ ((__strub__)) strub_int; strub_int *ptr; int *f () { - return ptr; /* { dg-warn "incompatible" } */ + return ptr; /* { dg-warning "incompatible" } */ } strub_int *g () { - return f (); /* { dg-warn "incompatible" } */ + return f (); /* { dg-warning "incompatible" } */ } diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure1.c b/gcc/testsuite/c-c++-common/torture/strub-pure1.c new file mode 100644 index 00000000000..cb223da6efc --- /dev/null +++ b/gcc/testsuite/c-c++-common/torture/strub-pure1.c @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-fstrub=default -fdump-ipa-strub" } */ + +/* Check that, along with a strub pure function call, we issue an asm statement + to make sure the watermark passed to it is not assumed to be unchanged. */ + +int __attribute__ ((__strub__, __pure__)) +f() { + static int i; /* Stop it from being detected as const. */ + return i; +} + +int +g() { + return f(); +} + +/* { dg-final { scan-ipa-dump-times "__asm__" 1 "strub" } } */ diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure2.c b/gcc/testsuite/c-c++-common/torture/strub-pure2.c new file mode 100644 index 00000000000..67d1434b1f8 --- /dev/null +++ b/gcc/testsuite/c-c++-common/torture/strub-pure2.c @@ -0,0 +1,22 @@ +/* { dg-do compile } */ +/* { dg-options "-fstrub=default -fdump-ipa-strub" } */ + +/* Check that, along with a strub implicitly-pure function call, we issue an asm + statement to make sure the watermark passed to it is not assumed to be + unchanged. */ + +int __attribute__ ((__strub__)) +#if ! __OPTIMIZE__ /* At -O0, implicit pure detection doesn't run. */ +__attribute__ ((__pure__)) +#endif +f() { + static int i; /* Stop it from being detected as const. */ + return i; +} + +int +g() { + return f(); +} + +/* { dg-final { scan-ipa-dump-times "__asm__" 1 "strub" } } */ diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure3.c b/gcc/testsuite/c-c++-common/torture/strub-pure3.c new file mode 100644 index 00000000000..59f02ea901f --- /dev/null +++ b/gcc/testsuite/c-c++-common/torture/strub-pure3.c @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-fstrub=default -fdump-ipa-strub" } */ + +/* Check that, along with a strub pure wrapping call, we issue an asm statement + to make sure the watermark passed to it is not assumed to be unchanged. */ + +int __attribute__ ((__strub__ (2), __pure__)) +f() { + static int i; /* Stop it from being detected as const. */ + return i; +} + +/* { dg-final { scan-ipa-dump-times "__asm__" 1 "strub" } } */ diff --git a/gcc/testsuite/c-c++-common/torture/strub-pure4.c b/gcc/testsuite/c-c++-common/torture/strub-pure4.c new file mode 100644 index 00000000000..973e909217d --- /dev/null +++ b/gcc/testsuite/c-c++-common/torture/strub-pure4.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-fstrub=default -fdump-ipa-strub" } */ + +/* Check that, along with a strub implicitly-pure wrapping call, we issue an asm + statement to make sure the watermark passed to it is not assumed to be + unchanged. */ + +int __attribute__ ((__strub__ (2))) +#if ! __OPTIMIZE__ /* At -O0, implicit pure detection doesn't run. */ +__attribute__ ((__pure__)) +#endif +f() { + static int i; /* Stop it from being detected as const. */ + return i; +} + +/* { dg-final { scan-ipa-dump-times "__asm__" 1 "strub" } } */ diff --git a/gcc/testsuite/c-c++-common/torture/strub-run1.c b/gcc/testsuite/c-c++-common/torture/strub-run1.c new file mode 100644 index 00000000000..828a4cc2998 --- /dev/null +++ b/gcc/testsuite/c-c++-common/torture/strub-run1.c @@ -0,0 +1,85 @@ +/* { dg-do run } */ +/* { dg-options "-fstrub=default" } */ + +/* Check that a non-strub function leaves a string behind in the stack, and that + equivalent strub functions don't. */ + +const char test_string[] = "\x55\xde\xad\xbe\xef\xc0\x1d\xca\xfe\x55\xaa"; + +static inline __attribute__ ((__always_inline__, __strub__ (3))) +char * +leak_string (void) +{ + /* We use this variable to avoid any stack red zone. Stack scrubbing covers + it, but __builtin_stack_address, that we take as a reference, doesn't, so + if e.g. callable() were to store the string in the red zone, we wouldn't + find it because it would be outside the range we searched. */ + typedef void __attribute__ ((__strub__ (3))) callable_t (char *); + callable_t *f = 0; + + char s[sizeof (test_string)]; + __builtin_strcpy (s, test_string); + asm ("" : "+m" (s), "+r" (f)); + + if (__builtin_expect (!f, 1)) + return __builtin_stack_address (); + + f (s); + return 0; +} + +static inline __attribute__ ((__always_inline__)) +int +look_for_string (char *e) +{ + char *p = __builtin_stack_address (); + + if (p == e) + __builtin_abort (); + + if (p > e) + { + char *q = p; + p = e; + e = q; + } + + for (char *re = e - sizeof (test_string); p < re; p++) + for (int i = 0; p[i] == test_string[i]; i++) + if (i == sizeof (test_string) - 1) + return i; + + return 0; +} + +static __attribute__ ((__noinline__, __noclone__)) +char * +callable () +{ + return leak_string (); +} + +static __attribute__ ((__strub__ (1))) +char * +at_calls () +{ + return leak_string (); +} + +static __attribute__ ((__strub__ (2))) +char * +internal () +{ + return leak_string (); +} + +int main () +{ + if (!look_for_string (callable ())) + __builtin_abort (); + if (look_for_string (at_calls ())) + __builtin_abort (); + if (look_for_string (internal ())) + __builtin_abort (); + __builtin_exit (0); +} diff --git a/gcc/testsuite/c-c++-common/torture/strub-run2.c b/gcc/testsuite/c-c++-common/torture/strub-run2.c new file mode 100644 index 00000000000..5794b694b2d --- /dev/null +++ b/gcc/testsuite/c-c++-common/torture/strub-run2.c @@ -0,0 +1,75 @@ +/* { dg-do run } */ +/* { dg-options "-fstrub=default" } */ + +/* Check that a non-strub function leaves a string behind in the stack, and that + equivalent strub functions don't. */ + +const char test_string[] = "\x55\xde\xad\xbe\xef\xc0\x1d\xca\xfe\x55\xaa"; + +static inline __attribute__ ((__always_inline__, __strub__ (3))) +char * +leak_string (void) +{ + int len = sizeof (test_string); + asm ("" : "+rm" (len)); + char s[len]; + __builtin_strcpy (s, test_string); + asm ("" : "+m" (s)); + return __builtin_stack_address (); +} + +static inline __attribute__ ((__always_inline__)) +int +look_for_string (char *e) +{ + char *p = __builtin_stack_address (); + + if (p == e) + __builtin_abort (); + + if (p > e) + { + char *q = p; + p = e; + e = q; + } + + for (char *re = e - sizeof (test_string); p < re; p++) + for (int i = 0; p[i] == test_string[i]; i++) + if (i == sizeof (test_string) - 1) + return i; + + return 0; +} + +static __attribute__ ((__noinline__, __noclone__)) +char * +callable () +{ + return leak_string (); +} + +static __attribute__ ((__strub__ (1))) +char * +at_calls () +{ + return leak_string (); +} + +static __attribute__ ((__strub__ (2))) +char * +internal () +{ + return leak_string (); +} + +int main () +{ + if (!look_for_string (callable ())) + __builtin_abort (); + if (look_for_string (at_calls ())) + __builtin_abort (); + if (look_for_string (internal ())) + __builtin_abort (); + __builtin_exit (0); +} diff --git a/gcc/testsuite/c-c++-common/torture/strub-run3.c b/gcc/testsuite/c-c++-common/torture/strub-run3.c new file mode 100644 index 00000000000..7da79055959 --- /dev/null +++ b/gcc/testsuite/c-c++-common/torture/strub-run3.c @@ -0,0 +1,75 @@ +/* { dg-do run } */ +/* { dg-options "-fstrub=default" } */ +/* { dg-require-effective-target alloca } */ + +/* Check that a non-strub function leaves a string behind in the stack, and that + equivalent strub functions don't. */ + +const char test_string[] = "\x55\xde\xad\xbe\xef\xc0\x1d\xca\xfe\x55\xaa"; + +static inline __attribute__ ((__always_inline__, __strub__ (3))) +char * +leak_string (void) +{ + int len = sizeof (test_string); + char *s = __builtin_alloca (len); + __builtin_strcpy (s, test_string); + asm ("" : "+m" (s)); + return __builtin_stack_address (); +} + +static inline __attribute__ ((__always_inline__)) +int +look_for_string (char *e) +{ + char *p = __builtin_stack_address (); + + if (p == e) + __builtin_abort (); + + if (p > e) + { + char *q = p; + p = e; + e = q; + } + + for (char *re = e - sizeof (test_string); p < re; p++) + for (int i = 0; p[i] == test_string[i]; i++) + if (i == sizeof (test_string) - 1) + return i; + + return 0; +} + +static __attribute__ ((__noinline__, __noclone__)) +char * +callable () +{ + return leak_string (); +} + +static __attribute__ ((__strub__ (1))) +char * +at_calls () +{ + return leak_string (); +} + +static __attribute__ ((__strub__ (2))) +char * +internal () +{ + return leak_string (); +} + +int main () +{ + if (!look_for_string (callable ())) + __builtin_abort (); + if (look_for_string (at_calls ())) + __builtin_abort (); + if (look_for_string (internal ())) + __builtin_abort (); + __builtin_exit (0); +} diff --git a/gcc/testsuite/g++.dg/wrappers/strub1.C b/gcc/testsuite/g++.dg/strub-run1.C similarity index 90% rename from gcc/testsuite/g++.dg/wrappers/strub1.C rename to gcc/testsuite/g++.dg/strub-run1.C index a474a929649..754291eaa01 100644 --- a/gcc/testsuite/g++.dg/wrappers/strub1.C +++ b/gcc/testsuite/g++.dg/strub-run1.C @@ -1,4 +1,5 @@ // { dg-do run } +// { dg-options "-fstrub=internal" } // Check that we don't get extra copies. diff --git a/gcc/testsuite/g++.dg/wrappers/strub2.C b/gcc/testsuite/g++.dg/wrappers/strub2.C deleted file mode 100644 index 25a62166448..00000000000 --- a/gcc/testsuite/g++.dg/wrappers/strub2.C +++ /dev/null @@ -1,22 +0,0 @@ -// { dg-do run } - -// This doesn't really test anything yet. We should mark the -// variables as requiring strubbing, and somehow check that the -// wrapped functions take the parameter by reference. - -struct T { - char d[32 * sizeof(void*)]; -}; - -T foo (T q) { asm ("" : : "m"(q)); return q; } -T bar (T p) { return foo (p); } - -T tmp; -T tmp2; - -int main () { - __builtin_memset (&tmp, 0x55, sizeof (tmp)); - tmp2 = bar (tmp); - if (__builtin_memcmp (&tmp, &tmp2, sizeof (tmp))) - __builtin_abort (); -} diff --git a/gcc/testsuite/g++.dg/wrappers/strub3.C b/gcc/testsuite/g++.dg/wrappers/strub3.C deleted file mode 100644 index e1b51cd0399..00000000000 --- a/gcc/testsuite/g++.dg/wrappers/strub3.C +++ /dev/null @@ -1,22 +0,0 @@ -// { dg-do run } - -// This doesn't really test anything yet. We should mark the -// variables as requiring strubbing, and somehow check that the -// wrapped functions take the parameter by reference. - -struct T { - char d[32 * sizeof(void*)]; -}; - -static T foo (T q) { asm ("" : : "m"(q)); return q; } -static T bar (T p) { return foo (p); } - -T tmp; -T tmp2; - -int main () { - __builtin_memset (&tmp, 0x55, sizeof (tmp)); - tmp2 = bar (tmp); - if (__builtin_memcmp (&tmp, &tmp2, sizeof (tmp))) - __builtin_abort (); -} diff --git a/gcc/testsuite/g++.dg/wrappers/strub4.C b/gcc/testsuite/g++.dg/wrappers/strub4.C deleted file mode 100644 index d021fca88e4..00000000000 --- a/gcc/testsuite/g++.dg/wrappers/strub4.C +++ /dev/null @@ -1,18 +0,0 @@ -// { dg-do run } - -namespace -{ - class foo - { - public: - foo(); - }; - - foo::foo() {} - - foo bar; -} - -int main() -{ -}