1/* strub (stack scrubbing) support.
2 Copyright (C) 2021-2024 Free Software Foundation, Inc.
3 Contributed by Alexandre Oliva <oliva@adacore.com>.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
20
21#include "config.h"
22#include "system.h"
23#include "coretypes.h"
24#include "backend.h"
25#include "tree.h"
26#include "gimple.h"
27#include "gimplify.h"
28#include "tree-pass.h"
29#include "ssa.h"
30#include "gimple-iterator.h"
31#include "gimplify-me.h"
32#include "tree-into-ssa.h"
33#include "tree-ssa.h"
34#include "tree-cfg.h"
35#include "cfghooks.h"
36#include "cfgloop.h"
37#include "cfgcleanup.h"
38#include "tree-eh.h"
39#include "except.h"
40#include "builtins.h"
41#include "attribs.h"
42#include "tree-inline.h"
43#include "cgraph.h"
44#include "alloc-pool.h"
45#include "symbol-summary.h"
46#include "sreal.h"
47#include "ipa-cp.h"
48#include "ipa-prop.h"
49#include "ipa-fnsummary.h"
50#include "gimple-fold.h"
51#include "fold-const.h"
52#include "gimple-walk.h"
53#include "tree-dfa.h"
54#include "langhooks.h"
55#include "calls.h"
56#include "vec.h"
57#include "stor-layout.h"
58#include "varasm.h"
59#include "alias.h"
60#include "diagnostic.h"
61#include "intl.h"
62#include "ipa-strub.h"
63#include "symtab-thunks.h"
64#include "attr-fnspec.h"
65#include "target.h"
66
67/* This file introduces two passes that, together, implement
68 machine-independent stack scrubbing, strub for short. It arranges
69 for stack frames that have strub enabled to be zeroed-out after
70 relinquishing control to a caller, whether by returning or by
71 propagating an exception. This admittedly unusual design decision
72 was driven by exception support (one needs a stack frame to be
73 active to propagate exceptions out of it), and it enabled an
74 implementation that is entirely machine-independent (no custom
75 epilogue code is required).
76
77 Strub modes can be selected for stack frames by attaching attribute
78 strub to functions or to variables (to their types, actually).
79 Different strub modes, with different implementation details, are
80 available, and they can be selected by an argument to the strub
81 attribute. When enabled by strub-enabled variables, whether by
82 accessing (as in reading from) statically-allocated ones, or by
83 introducing (as in declaring) automatically-allocated ones, a
84 suitable mode is selected automatically.
85
86 At-calls mode modifies the interface of a function, adding a stack
87 watermark argument, that callers use to clean up the stack frame of
88 the called function. Because of the interface change, it can only
89 be used when explicitly selected, or when a function is internal to
90 a translation unit. Strub-at-calls function types are distinct
91 from their original types (they're not modified in-place), and they
92 are not interchangeable with other function types.
93
94 Internal mode, in turn, does not modify the type or the interface
95 of a function. It is currently implemented by turning the function
96 into a wrapper, moving the function body to a separate wrapped
97 function, and scrubbing the wrapped body's stack in the wrapper.
98 Internal-strub function types are mostly interface-compatible with
99 other strub modes, namely callable (from strub functions, though
100 not strub-enabled) and disabled (not callable from strub
101 functions).
102
103 Always_inline functions can be strub functions, but they can only
104 be called from other strub functions, because strub functions must
105 never be inlined into non-strub functions. Internal and at-calls
106 modes are indistinguishable when it comes to always_inline
107 functions: they will necessarily be inlined into another strub
108 function, and will thus be integrated into the caller's stack
109 frame, whatever the mode. (Contrast with non-always_inline strub
110 functions: an at-calls function can be called from other strub
111 functions, ensuring no discontinuity in stack erasing, whereas an
112 internal-strub function can only be called from other strub
113 functions if it happens to be inlined, or if -fstrub=relaxed mode
114 is in effect (that's the default). In -fstrub=strict mode,
115 internal-strub functions are not callable from strub functions,
116 because the wrapper itself is not strubbed.
117
118 The implementation involves two simple-IPA passes. The earliest
119 one, strub-mode, assigns strub modes to functions. It needs to run
120 before any inlining, so that we can prevent inlining of strub
121 functions into non-strub functions. It notes explicit strub mode
122 requests, enables strub in response to strub variables and testing
123 options, and flags unsatisfiable requests.
124
125 Three possibilities of unsatisfiable requests come to mind: (a)
126 when a strub mode is explicitly selected, but the function uses
127 features that make it ineligible for that mode (e.g. at-calls rules
128 out calling __builtin_apply_args, because of the interface changes,
129 and internal mode rules out noclone or otherwise non-versionable
130 functions, non-default varargs, non-local or forced labels, and
131 functions with far too many arguments); (b) when some strub mode
132 must be enabled because of a strub variable, but the function is
133 not eligible or not viable for any mode; and (c) when
134 -fstrub=strict is enabled, and calls are found in strub functions
135 to functions that are not callable from strub contexts.
136 compute_strub_mode implements (a) and (b), and verify_strub
137 implements (c).
138
139 The second IPA pass modifies interfaces of at-calls-strub functions
140 and types, introduces strub calls in and around them. and splits
141 internal-strub functions. It is placed after early inlining, so
142 that even internal-strub functions get a chance of being inlined
143 into other strub functions, but before non-early inlining, so that
144 internal-strub wrapper functions still get a chance of inlining
145 after splitting.
146
147 Wrappers avoid duplicating the copying of large arguments again by
148 passing them by reference to the wrapped bodies. This involves
149 occasional SSA rewriting of address computations, because of the
150 additional indirection. Besides these changes, and the
151 introduction of the stack watermark parameter, wrappers and wrapped
152 functions cooperate to handle variable argument lists (performing
153 va_start in the wrapper, passing the list as an argument, and
154 replacing va_start calls in the wrapped body with va_copy), and
155 __builtin_apply_args (also called in the wrapper and passed to the
156 wrapped body as an argument).
157
158 Strub bodies (both internal-mode wrapped bodies, and at-calls
159 functions) always start by adjusting the watermark parameter, by
160 calling __builtin___strub_update. The compiler inserts them in the
161 main strub pass. Allocations of additional stack space for the
162 frame (__builtin_alloca) are also followed by watermark updates.
163 Stack space temporarily allocated to pass arguments to other
164 functions, released right after the call, is not regarded as part
165 of the frame. Around calls to them, i.e., in internal-mode
166 wrappers and at-calls callers (even calls through pointers), calls
167 to __builtin___strub_enter and __builtin___strub_leave are
168 inserted, the latter as a __finally block, so that it runs at
169 regular and exceptional exit paths. strub_enter only initializes
170 the stack watermark, and strub_leave is where the scrubbing takes
171 place, overwriting with zeros the stack space from the top of the
172 stack to the watermark.
173
174 These calls can be optimized in various cases. In
175 pass_ipa_strub::adjust_at_calls_call, for example, we enable
176 tail-calling and other optimized calls from one strub body to
177 another by passing on the watermark parameter. The builtins
178 themselves may undergo inline substitution during expansion,
179 dependign on optimization levels. This involves dealing with stack
180 red zones (when the builtins are called out-of-line, the red zone
181 cannot be used) and other ugly details related with inlining strub
182 bodies into other strub bodies (see expand_builtin_strub_update).
183 expand_builtin_strub_leave may even perform partial inline
184 substitution. */
185
186/* Const and pure functions that gain a watermark parameter for strub purposes
187 are still regarded as such, which may cause the inline expansions of the
188 __strub builtins to malfunction. Ideally, attribute "fn spec" would enable
189 us to inform the backend about requirements and side effects of the call, but
190 call_fusage building in calls.c:expand_call does not even look at
191 attr_fnspec, so we resort to asm loads and updates to attain an equivalent
192 effect. Once expand_call gains the ability to issue extra memory uses and
193 clobbers based on pure/const function's fnspec, we can define this to 1. */
194#define ATTR_FNSPEC_DECONST_WATERMARK 0
195
196enum strub_mode {
197 /* This mode denotes a regular function, that does not require stack
198 scrubbing (strubbing). It may call any other functions, but if
199 it calls AT_CALLS (or WRAPPED) ones, strubbing logic is
200 automatically introduced around those calls (the latter, by
201 inlining INTERNAL wrappers). */
202 STRUB_DISABLED = 0,
203
204 /* This denotes a function whose signature is (to be) modified to
205 take an extra parameter, for stack use annotation, and its
206 callers must initialize and pass that argument, and perform the
207 strubbing. Functions that are explicitly marked with attribute
208 strub must have the mark visible wherever the function is,
209 including aliases, and overriders and overriding methods.
210 Functions that are implicitly marked for strubbing, for accessing
211 variables explicitly marked as such, will only select this
212 strubbing method if they are internal to a translation unit. It
213 can only be inlined into other strubbing functions, i.e.,
214 STRUB_AT_CALLS or STRUB_WRAPPED. */
215 STRUB_AT_CALLS = 1,
216
217 /* This denotes a function that is to perform strubbing internally,
218 without any changes to its interface (the function is turned into
219 a strubbing wrapper, and its original body is moved to a separate
220 STRUB_WRAPPED function, with a modified interface). Functions
221 may be explicitly marked with attribute strub(2), and the
222 attribute must be visible at the point of definition. Functions
223 that are explicitly marked for strubbing, for accessing variables
224 explicitly marked as such, may select this strubbing mode if
225 their interface cannot change, e.g. because its interface is
226 visible to other translation units, directly, by indirection
227 (having its address taken), inheritance, etc. Functions that use
228 this method must not have the noclone attribute, nor the noipa
229 one. Functions marked as always_inline may select this mode, but
230 they are NOT wrapped, they remain unchanged, and are only inlined
231 into strubbed contexts. Once non-always_inline functions are
232 wrapped, the wrapper becomes STRUB_WRAPPER, and the wrapped becomes
233 STRUB_WRAPPED. */
234 STRUB_INTERNAL = 2,
235
236 /* This denotes a function whose stack is not strubbed, but that is
237 nevertheless explicitly or implicitly marked as callable from strubbing
238 functions. Normally, only STRUB_AT_CALLS (and STRUB_INTERNAL ->
239 STRUB_WRAPPED) functions can be called from strubbing contexts (bodies of
240 STRUB_AT_CALLS, STRUB_INTERNAL and STRUB_WRAPPED functions), but attribute
241 strub(3) enables other functions to be (indirectly) called from these
242 contexts. Some builtins and internal functions may be implicitly marked as
243 STRUB_CALLABLE. */
244 STRUB_CALLABLE = 3,
245
246 /* This denotes the function that took over the body of a
247 STRUB_INTERNAL function. At first, it's only called by its
248 wrapper, but the wrapper may be inlined. The wrapped function,
249 in turn, can only be inlined into other functions whose stack
250 frames are strubbed, i.e., that are STRUB_WRAPPED or
251 STRUB_AT_CALLS. */
252 STRUB_WRAPPED = -1,
253
254 /* This denotes the wrapper function that replaced the STRUB_INTERNAL
255 function. This mode overrides the STRUB_INTERNAL mode at the time the
256 internal to-be-wrapped function becomes a wrapper, so that inlining logic
257 can tell one from the other. */
258 STRUB_WRAPPER = -2,
259
260 /* This denotes an always_inline function that requires strubbing. It can
261 only be called from, and inlined into, other strubbing contexts. */
262 STRUB_INLINABLE = -3,
263
264 /* This denotes a function that accesses strub variables, so it would call for
265 internal strubbing (whether or not it's eligible for that), but since
266 at-calls strubbing is viable, that's selected as an optimization. This
267 mode addresses the inconvenience that such functions may have different
268 modes selected depending on optimization flags, and get a different
269 callable status depending on that choice: if we assigned them
270 STRUB_AT_CALLS mode, they would be callable when optimizing, whereas
271 STRUB_INTERNAL would not be callable. */
272 STRUB_AT_CALLS_OPT = -4,
273
274};
275
276/* Look up a strub attribute in TYPE, and return it. */
277
278static tree
279get_strub_attr_from_type (tree type)
280{
281 return lookup_attribute (attr_name: "strub", TYPE_ATTRIBUTES (type));
282}
283
284/* Look up a strub attribute in DECL or in its type, and return it. */
285
286static tree
287get_strub_attr_from_decl (tree decl)
288{
289 tree ret = lookup_attribute (attr_name: "strub", DECL_ATTRIBUTES (decl));
290 if (ret)
291 return ret;
292 return get_strub_attr_from_type (TREE_TYPE (decl));
293}
294
295#define STRUB_ID_COUNT 8
296#define STRUB_IDENT_COUNT 3
297#define STRUB_TYPE_COUNT 5
298
299#define STRUB_ID_BASE 0
300#define STRUB_IDENT_BASE (STRUB_ID_BASE + STRUB_ID_COUNT)
301#define STRUB_TYPE_BASE (STRUB_IDENT_BASE + STRUB_IDENT_COUNT)
302#define STRUB_CACHE_SIZE (STRUB_TYPE_BASE + STRUB_TYPE_COUNT)
303
304/* Keep the strub mode and temp identifiers and types from being GC'd. */
305static GTY((deletable)) tree strub_cache[STRUB_CACHE_SIZE];
306
307/* Define a function to cache identifier ID, to be used as a strub attribute
308 parameter for a strub mode named after NAME. */
309#define DEF_STRUB_IDS(IDX, NAME, ID) \
310static inline tree get_strub_mode_id_ ## NAME () { \
311 int idx = STRUB_ID_BASE + IDX; \
312 tree identifier = strub_cache[idx]; \
313 if (!identifier) \
314 strub_cache[idx] = identifier = get_identifier (ID); \
315 return identifier; \
316}
317/* Same as DEF_STRUB_IDS, but use the string expansion of NAME as ID. */
318#define DEF_STRUB_ID(IDX, NAME) \
319 DEF_STRUB_IDS (IDX, NAME, #NAME)
320
321/* Define functions for each of the strub mode identifiers.
322 Expose dashes rather than underscores. */
323DEF_STRUB_ID (0, disabled)
324DEF_STRUB_IDS (1, at_calls, "at-calls")
325DEF_STRUB_ID (2, internal)
326DEF_STRUB_ID (3, callable)
327DEF_STRUB_ID (4, wrapped)
328DEF_STRUB_ID (5, wrapper)
329DEF_STRUB_ID (6, inlinable)
330DEF_STRUB_IDS (7, at_calls_opt, "at-calls-opt")
331
332/* Release the temporary macro names. */
333#undef DEF_STRUB_IDS
334#undef DEF_STRUB_ID
335
336/* Return the identifier corresponding to strub MODE. */
337
338static tree
339get_strub_mode_attr_parm (enum strub_mode mode)
340{
341 switch (mode)
342 {
343 case STRUB_DISABLED:
344 return get_strub_mode_id_disabled ();
345
346 case STRUB_AT_CALLS:
347 return get_strub_mode_id_at_calls ();
348
349 case STRUB_INTERNAL:
350 return get_strub_mode_id_internal ();
351
352 case STRUB_CALLABLE:
353 return get_strub_mode_id_callable ();
354
355 case STRUB_WRAPPED:
356 return get_strub_mode_id_wrapped ();
357
358 case STRUB_WRAPPER:
359 return get_strub_mode_id_wrapper ();
360
361 case STRUB_INLINABLE:
362 return get_strub_mode_id_inlinable ();
363
364 case STRUB_AT_CALLS_OPT:
365 return get_strub_mode_id_at_calls_opt ();
366
367 default:
368 gcc_unreachable ();
369 }
370}
371
372/* Return the parmeters (TREE_VALUE) for a strub attribute of MODE.
373 We know we use a single parameter, so we bypass the creation of a
374 tree list. */
375
376static tree
377get_strub_mode_attr_value (enum strub_mode mode)
378{
379 return get_strub_mode_attr_parm (mode);
380}
381
382/* Determine whether ID is a well-formed strub mode-specifying attribute
383 parameter for a function (type). Only user-visible modes are accepted, and
384 ID must be non-NULL.
385
386 For unacceptable parms, return 0, otherwise a nonzero value as below.
387
388 If the parm enables strub, return positive, otherwise negative.
389
390 If the affected type must be a distinct, incompatible type,return an integer
391 of absolute value 2, otherwise 1. */
392
393int
394strub_validate_fn_attr_parm (tree id)
395{
396 int ret;
397 const char *s = NULL;
398 size_t len = 0;
399
400 /* do NOT test for NULL. This is only to be called with non-NULL arguments.
401 We assume that the strub parameter applies to a function, because only
402 functions accept an explicit argument. If we accepted NULL, and we
403 happened to be called to verify the argument for a variable, our return
404 values would be wrong. */
405 if (TREE_CODE (id) == STRING_CST)
406 {
407 s = TREE_STRING_POINTER (id);
408 len = TREE_STRING_LENGTH (id) - 1;
409 }
410 else if (TREE_CODE (id) == IDENTIFIER_NODE)
411 {
412 s = IDENTIFIER_POINTER (id);
413 len = IDENTIFIER_LENGTH (id);
414 }
415 else
416 return 0;
417
418 enum strub_mode mode;
419
420 if (len != 8)
421 return 0;
422
423 switch (s[0])
424 {
425 case 'd':
426 mode = STRUB_DISABLED;
427 ret = -1;
428 break;
429
430 case 'a':
431 mode = STRUB_AT_CALLS;
432 ret = 2;
433 break;
434
435 case 'i':
436 mode = STRUB_INTERNAL;
437 ret = 1;
438 break;
439
440 case 'c':
441 mode = STRUB_CALLABLE;
442 ret = -2;
443 break;
444
445 default:
446 /* Other parms are for internal use only. */
447 return 0;
448 }
449
450 tree mode_id = get_strub_mode_attr_parm (mode);
451
452 if (TREE_CODE (id) == IDENTIFIER_NODE
453 ? id != mode_id
454 : strncmp (s1: s, IDENTIFIER_POINTER (mode_id), n: len) != 0)
455 return 0;
456
457 return ret;
458}
459
460/* Return the strub mode from STRUB_ATTR. VAR_P should be TRUE if the attribute
461 is taken from a variable, rather than from a function, or a type thereof. */
462
463static enum strub_mode
464get_strub_mode_from_attr (tree strub_attr, bool var_p = false)
465{
466 enum strub_mode mode = STRUB_DISABLED;
467
468 if (strub_attr)
469 {
470 if (!TREE_VALUE (strub_attr))
471 mode = !var_p ? STRUB_AT_CALLS : STRUB_INTERNAL;
472 else
473 {
474 gcc_checking_assert (!var_p);
475 tree id = TREE_VALUE (strub_attr);
476 if (TREE_CODE (id) == TREE_LIST)
477 id = TREE_VALUE (id);
478 const char *s = (TREE_CODE (id) == STRING_CST
479 ? TREE_STRING_POINTER (id)
480 : IDENTIFIER_POINTER (id));
481 size_t len = (TREE_CODE (id) == STRING_CST
482 ? TREE_STRING_LENGTH (id) - 1
483 : IDENTIFIER_LENGTH (id));
484
485 switch (len)
486 {
487 case 7:
488 switch (s[6])
489 {
490 case 'r':
491 mode = STRUB_WRAPPER;
492 break;
493
494 case 'd':
495 mode = STRUB_WRAPPED;
496 break;
497
498 default:
499 gcc_unreachable ();
500 }
501 break;
502
503 case 8:
504 switch (s[0])
505 {
506 case 'd':
507 mode = STRUB_DISABLED;
508 break;
509
510 case 'a':
511 mode = STRUB_AT_CALLS;
512 break;
513
514 case 'i':
515 mode = STRUB_INTERNAL;
516 break;
517
518 case 'c':
519 mode = STRUB_CALLABLE;
520 break;
521
522 default:
523 gcc_unreachable ();
524 }
525 break;
526
527 case 9:
528 mode = STRUB_INLINABLE;
529 break;
530
531 case 12:
532 mode = STRUB_AT_CALLS_OPT;
533 break;
534
535 default:
536 gcc_unreachable ();
537 }
538
539 gcc_checking_assert (TREE_CODE (id) == IDENTIFIER_NODE
540 ? id == get_strub_mode_attr_parm (mode)
541 : strncmp (IDENTIFIER_POINTER
542 (get_strub_mode_attr_parm (mode)),
543 s, len) == 0);
544 }
545 }
546
547 return mode;
548}
549
550/* Look up, decode and return the strub mode associated with FNDECL. */
551
552static enum strub_mode
553get_strub_mode_from_fndecl (tree fndecl)
554{
555 return get_strub_mode_from_attr (strub_attr: get_strub_attr_from_decl (decl: fndecl));
556}
557
558/* Look up, decode and return the strub mode associated with NODE. */
559
560static enum strub_mode
561get_strub_mode (cgraph_node *node)
562{
563 return get_strub_mode_from_fndecl (fndecl: node->decl);
564}
565
566/* Look up, decode and return the strub mode associated with TYPE. */
567
568static enum strub_mode
569get_strub_mode_from_type (tree type)
570{
571 bool var_p = !FUNC_OR_METHOD_TYPE_P (type);
572 tree attr = get_strub_attr_from_type (type);
573
574 if (attr)
575 return get_strub_mode_from_attr (strub_attr: attr, var_p);
576
577 if (flag_strub >= -1 && !var_p)
578 return STRUB_CALLABLE;
579
580 return STRUB_DISABLED;
581}
582
583
584/* Return TRUE iff NODE calls builtin va_start. */
585
586static bool
587calls_builtin_va_start_p (cgraph_node *node)
588{
589 bool result = false;
590
591 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
592 {
593 tree cdecl = e->callee->decl;
594 if (fndecl_built_in_p (node: cdecl, name1: BUILT_IN_VA_START))
595 return true;
596 }
597
598 return result;
599}
600
601/* Return TRUE iff NODE calls builtin apply_args, and optionally REPORT it. */
602
603static bool
604calls_builtin_apply_args_p (cgraph_node *node, bool report = false)
605{
606 bool result = false;
607
608 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
609 {
610 tree cdecl = e->callee->decl;
611 if (!fndecl_built_in_p (node: cdecl, name1: BUILT_IN_APPLY_ARGS))
612 continue;
613
614 result = true;
615
616 if (!report)
617 break;
618
619 sorry_at (e->call_stmt
620 ? gimple_location (g: e->call_stmt)
621 : DECL_SOURCE_LOCATION (node->decl),
622 "at-calls %<strub%> does not support call to %qD",
623 cdecl);
624 }
625
626 return result;
627}
628
629/* Return TRUE iff NODE carries the always_inline attribute. */
630
631static inline bool
632strub_always_inline_p (cgraph_node *node)
633{
634 return lookup_attribute (attr_name: "always_inline", DECL_ATTRIBUTES (node->decl));
635}
636
637/* Return TRUE iff the target has strub support for T, a function
638 decl, or a type used in an indirect call, and optionally REPORT the
639 reasons for ineligibility. If T is a type and error REPORTing is
640 enabled, the LOCation (of the indirect call) should be provided. */
641static inline bool
642strub_target_support_p (tree t, bool report = false,
643 location_t loc = UNKNOWN_LOCATION)
644{
645 bool result = true;
646
647 if (!targetm.have_strub_support_for (t))
648 {
649 result = false;
650
651 if (!report)
652 return result;
653
654 if (DECL_P (t))
655 sorry_at (DECL_SOURCE_LOCATION (t),
656 "%qD is not eligible for %<strub%>"
657 " on the target system", t);
658 else
659 sorry_at (loc,
660 "unsupported %<strub%> call"
661 " on the target system");
662 }
663
664 return result;
665}
666
667/* Return TRUE iff NODE is potentially eligible for any strub-enabled mode, and
668 optionally REPORT the reasons for ineligibility. */
669
670static inline bool
671can_strub_p (cgraph_node *node, bool report = false)
672{
673 bool result = strub_target_support_p (t: node->decl, report);
674
675 if (!report && (!result || strub_always_inline_p (node)))
676 return result;
677
678 if (flag_split_stack)
679 {
680 result = false;
681
682 if (!report)
683 return result;
684
685 sorry_at (DECL_SOURCE_LOCATION (node->decl),
686 "%qD is not eligible for %<strub%>"
687 " because %<-fsplit-stack%> is enabled",
688 node->decl);
689 }
690
691 if (lookup_attribute (attr_name: "noipa", DECL_ATTRIBUTES (node->decl)))
692 {
693 result = false;
694
695 if (!report)
696 return result;
697
698 sorry_at (DECL_SOURCE_LOCATION (node->decl),
699 "%qD is not eligible for %<strub%>"
700 " because of attribute %<noipa%>",
701 node->decl);
702 }
703
704 /* We can't, and don't want to vectorize the watermark and other
705 strub-introduced parms. */
706 if (lookup_attribute (attr_name: "simd", DECL_ATTRIBUTES (node->decl)))
707 {
708 result = false;
709
710 if (!report)
711 return result;
712
713 sorry_at (DECL_SOURCE_LOCATION (node->decl),
714 "%qD is not eligible for %<strub%>"
715 " because of attribute %<simd%>",
716 node->decl);
717 }
718
719 return result;
720}
721
722/* Return TRUE iff NODE is eligible for at-calls strub, and optionally REPORT
723 the reasons for ineligibility. Besides general non-eligibility for
724 strub-enabled modes, at-calls rules out calling builtin apply_args. */
725
726static bool
727can_strub_at_calls_p (cgraph_node *node, bool report = false)
728{
729 bool result = !report || can_strub_p (node, report);
730
731 if (!result && !report)
732 return result;
733
734 return !calls_builtin_apply_args_p (node, report);
735}
736
737/* Return TRUE iff the called function (pointer or, if available,
738 decl) undergoes a significant type conversion for the call. Strub
739 mode changes between function types, and other non-useless type
740 conversions, are regarded as significant. When the function type
741 is overridden, the effective strub mode for the call is that of the
742 call fntype, rather than that of the pointer or of the decl.
743 Functions called with type overrides cannot undergo type changes;
744 it's as if their address was taken, so they're considered
745 non-viable for implicit at-calls strub mode. */
746
747static inline bool
748strub_call_fntype_override_p (const gcall *gs)
749{
750 if (gimple_call_internal_p (gs))
751 return false;
752 tree fn_type = TREE_TYPE (TREE_TYPE (gimple_call_fn (gs)));
753 if (tree decl = gimple_call_fndecl (gs))
754 fn_type = TREE_TYPE (decl);
755
756 /* We do NOT want to take the mode from the decl here. This
757 function is used to tell whether we can change the strub mode of
758 a function, and whether the effective mode for the call is to be
759 taken from the decl or from an overrider type. When the strub
760 mode is explicitly declared, or overridden with a type cast, the
761 difference will be noticed in function types. However, if the
762 strub mode is implicit due to e.g. strub variables or -fstrub=*
763 command-line flags, we will adjust call types along with function
764 types. In either case, the presence of type or strub mode
765 overriders in calls will prevent a function from having its strub
766 modes changed in ways that would imply type changes, but taking
767 strub modes from decls would defeat this, since we set strub
768 modes and then call this function to tell whether the original
769 type was overridden to decide whether to adjust the call. We
770 need the answer to be about the type, not the decl. */
771 enum strub_mode mode = get_strub_mode_from_type (type: fn_type);
772 return (get_strub_mode_from_type (type: gs->u.fntype) != mode
773 || !useless_type_conversion_p (gs->u.fntype, fn_type));
774}
775
776/* Return TRUE iff NODE is called directly with a type override. */
777
778static bool
779called_directly_with_type_override_p (cgraph_node *node, void *)
780{
781 for (cgraph_edge *e = node->callers; e; e = e->next_caller)
782 if (e->call_stmt && strub_call_fntype_override_p (gs: e->call_stmt))
783 return true;
784
785 return false;
786}
787
788/* Return TRUE iff NODE or any other nodes aliased to it are called
789 with type overrides. We can't safely change the type of such
790 functions. */
791
792static bool
793called_with_type_override_p (cgraph_node *node)
794{
795 return (node->call_for_symbol_thunks_and_aliases
796 (callback: called_directly_with_type_override_p, NULL, include_overwritable: true, exclude_virtual_thunks: true));
797}
798
799/* Symbolic macro for the max number of arguments that internal strub may add to
800 a function. */
801
802#define STRUB_INTERNAL_MAX_EXTRA_ARGS 3
803
804/* We can't perform internal strubbing if the function body involves certain
805 features:
806
807 - a non-default __builtin_va_start (e.g. x86's __builtin_ms_va_start) is
808 currently unsupported because we can't discover the corresponding va_copy and
809 va_end decls in the wrapper, and we don't convey the alternate variable
810 arguments ABI to the modified wrapped function. The default
811 __builtin_va_start is supported by calling va_start/va_end at the wrapper,
812 that takes variable arguments, passing a pointer to the va_list object to the
813 wrapped function, that runs va_copy from it where the original function ran
814 va_start.
815
816 __builtin_next_arg is currently unsupported because the wrapped function
817 won't be a variable argument function. We could process it in the wrapper,
818 that remains a variable argument function, and replace calls in the wrapped
819 body, but we currently don't.
820
821 __builtin_return_address is rejected because it's generally used when the
822 actual caller matters, and introducing a wrapper breaks such uses as those in
823 the unwinder. */
824
825static bool
826can_strub_internally_p (cgraph_node *node, bool report = false)
827{
828 bool result = !report || can_strub_p (node, report);
829
830 if (!result && !report)
831 return result;
832
833 if (!report && strub_always_inline_p (node))
834 return result;
835
836 /* Since we're not changing the function identity proper, just
837 moving its full implementation, we *could* disable
838 fun->cannot_be_copied_reason and/or temporarily drop a noclone
839 attribute, but we'd have to prevent remapping of the labels. */
840 if (lookup_attribute (attr_name: "noclone", DECL_ATTRIBUTES (node->decl)))
841 {
842 result = false;
843
844 if (!report)
845 return result;
846
847 sorry_at (DECL_SOURCE_LOCATION (node->decl),
848 "%qD is not eligible for internal %<strub%>"
849 " because of attribute %<noclone%>",
850 node->decl);
851 }
852
853 if (node->has_gimple_body_p ())
854 {
855 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
856 {
857 tree cdecl = e->callee->decl;
858 if (!((fndecl_built_in_p (node: cdecl, name1: BUILT_IN_VA_START)
859 && cdecl != builtin_decl_explicit (fncode: BUILT_IN_VA_START))
860 || fndecl_built_in_p (node: cdecl, name1: BUILT_IN_NEXT_ARG)
861 || fndecl_built_in_p (node: cdecl, name1: BUILT_IN_RETURN_ADDRESS)))
862 continue;
863
864 result = false;
865
866 if (!report)
867 return result;
868
869 sorry_at (e->call_stmt
870 ? gimple_location (g: e->call_stmt)
871 : DECL_SOURCE_LOCATION (node->decl),
872 "%qD is not eligible for internal %<strub%> "
873 "because it calls %qD",
874 node->decl, cdecl);
875 }
876
877 struct function *fun = DECL_STRUCT_FUNCTION (node->decl);
878 if (fun->has_nonlocal_label)
879 {
880 result = false;
881
882 if (!report)
883 return result;
884
885 sorry_at (DECL_SOURCE_LOCATION (node->decl),
886 "%qD is not eligible for internal %<strub%> "
887 "because it contains a non-local goto target",
888 node->decl);
889 }
890
891 if (fun->has_forced_label_in_static)
892 {
893 result = false;
894
895 if (!report)
896 return result;
897
898 sorry_at (DECL_SOURCE_LOCATION (node->decl),
899 "%qD is not eligible for internal %<strub%> "
900 "because the address of a local label escapes",
901 node->decl);
902 }
903
904 /* Catch any other case that would prevent versioning/cloning
905 so as to also have it covered above. */
906 gcc_checking_assert (!result /* || !node->has_gimple_body_p () */
907 || tree_versionable_function_p (node->decl));
908
909
910 /* Label values references are not preserved when copying. If referenced
911 in nested functions, as in 920415-1.c and 920721-4.c their decls get
912 remapped independently. The exclusion below might be too broad, in
913 that we might be able to support correctly cases in which the labels
914 are only used internally in a function, but disconnecting forced labels
915 from their original declarations is undesirable in general. */
916 basic_block bb;
917 FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
918 for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
919 !gsi_end_p (i: gsi); gsi_next (i: &gsi))
920 {
921 glabel *label_stmt = dyn_cast <glabel *> (p: gsi_stmt (i: gsi));
922 tree target;
923
924 if (!label_stmt)
925 break;
926
927 target = gimple_label_label (gs: label_stmt);
928
929 if (!FORCED_LABEL (target))
930 continue;
931
932 result = false;
933
934 if (!report)
935 return result;
936
937 sorry_at (gimple_location (g: label_stmt),
938 "internal %<strub%> does not support forced labels");
939 }
940 }
941
942 if (list_length (TYPE_ARG_TYPES (TREE_TYPE (node->decl)))
943 >= ((HOST_WIDE_INT_1 << IPA_PARAM_MAX_INDEX_BITS)
944 - STRUB_INTERNAL_MAX_EXTRA_ARGS))
945 {
946 result = false;
947
948 if (!report)
949 return result;
950
951 sorry_at (DECL_SOURCE_LOCATION (node->decl),
952 "%qD has too many arguments for internal %<strub%>",
953 node->decl);
954 }
955
956 return result;
957}
958
959/* Return TRUE iff NODE has any strub-requiring local variable, or accesses (as
960 in reading) any variable through a strub-requiring type. */
961
962static bool
963strub_from_body_p (cgraph_node *node)
964{
965 if (!node->has_gimple_body_p ())
966 return false;
967
968 /* If any local variable is marked for strub... */
969 unsigned i;
970 tree var;
971 FOR_EACH_LOCAL_DECL (DECL_STRUCT_FUNCTION (node->decl),
972 i, var)
973 if (get_strub_mode_from_type (TREE_TYPE (var))
974 != STRUB_DISABLED)
975 return true;
976
977 /* Now scan the body for loads with strub-requiring types.
978 ??? Compound types don't propagate the strub requirement to
979 component types. */
980 basic_block bb;
981 FOR_EACH_BB_FN (bb, DECL_STRUCT_FUNCTION (node->decl))
982 for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
983 !gsi_end_p (i: gsi); gsi_next (i: &gsi))
984 {
985 gimple *stmt = gsi_stmt (i: gsi);
986
987 if (!gimple_assign_load_p (stmt))
988 continue;
989
990 tree rhs = gimple_assign_rhs1 (gs: stmt);
991 if (get_strub_mode_from_type (TREE_TYPE (rhs))
992 != STRUB_DISABLED)
993 return true;
994 }
995
996 return false;
997}
998
999/* Return TRUE iff node is associated with a builtin that should be callable
1000 from strub contexts. */
1001
1002static inline bool
1003strub_callable_builtin_p (cgraph_node *node)
1004{
1005 if (DECL_BUILT_IN_CLASS (node->decl) != BUILT_IN_NORMAL)
1006 return false;
1007
1008 enum built_in_function fcode = DECL_FUNCTION_CODE (decl: node->decl);
1009
1010 switch (fcode)
1011 {
1012 case BUILT_IN_NONE:
1013 gcc_unreachable ();
1014
1015 /* This temporarily allocates stack for the call, and we can't reasonably
1016 update the watermark for that. Besides, we don't check the actual call
1017 target, nor its signature, and it seems to be overkill to as much as
1018 try to do so. */
1019 case BUILT_IN_APPLY:
1020 return false;
1021
1022 /* Conversely, this shouldn't be called from within strub contexts, since
1023 the caller may have had its signature modified. STRUB_INTERNAL is ok,
1024 the call will remain in the STRUB_WRAPPER, and removed from the
1025 STRUB_WRAPPED clone. */
1026 case BUILT_IN_APPLY_ARGS:
1027 return false;
1028
1029 /* ??? Make all other builtins callable. We wish to make any builtin call
1030 the compiler might introduce on its own callable. Anything that is
1031 predictable enough as to be known not to allow stack data that should
1032 be strubbed to unintentionally escape to non-strub contexts can be
1033 allowed, and pretty much every builtin appears to fit this description.
1034 The exceptions to this rule seem to be rare, and only available as
1035 explicit __builtin calls, so let's keep it simple and allow all of
1036 them... */
1037 default:
1038 return true;
1039 }
1040}
1041
1042/* Compute the strub mode to be used for NODE. STRUB_ATTR should be the strub
1043 attribute,found for NODE, if any. */
1044
1045static enum strub_mode
1046compute_strub_mode (cgraph_node *node, tree strub_attr)
1047{
1048 enum strub_mode req_mode = get_strub_mode_from_attr (strub_attr);
1049
1050 gcc_checking_assert (flag_strub >= -2 && flag_strub <= 3);
1051
1052 /* Symbolic encodings of the -fstrub-* flags. */
1053 /* Enable strub when explicitly requested through attributes to functions or
1054 variables, reporting errors if the requests cannot be satisfied. */
1055 const bool strub_flag_auto = flag_strub < 0;
1056 /* strub_flag_auto with strub call verification; without this, functions are
1057 implicitly callable. */
1058 const bool strub_flag_strict = flag_strub < -1;
1059 /* Disable strub altogether, ignore attributes entirely. */
1060 const bool strub_flag_disabled = flag_strub == 0;
1061 /* On top of _auto, also enable strub implicitly for functions that can
1062 safely undergo at-calls strubbing. Internal mode will still be used in
1063 functions that request it explicitly with attribute strub(2), or when the
1064 function body requires strubbing and at-calls strubbing is not viable. */
1065 const bool strub_flag_at_calls = flag_strub == 1;
1066 /* On top of default, also enable strub implicitly for functions that can
1067 safely undergo internal strubbing. At-calls mode will still be used in
1068 functions that requiest it explicitly with attribute strub() or strub(1),
1069 or when the function body requires strubbing and internal strubbing is not
1070 viable. */
1071 const bool strub_flag_internal = flag_strub == 2;
1072 /* On top of default, also enable strub implicitly for functions that can
1073 safely undergo strubbing in either mode. When both modes are viable,
1074 at-calls is preferred. */
1075 const bool strub_flag_either = flag_strub == 3;
1076 /* Besides the default behavior, enable strub implicitly for all viable
1077 functions. */
1078 const bool strub_flag_viable = flag_strub > 0;
1079
1080 /* The consider_* variables should be TRUE if selecting the corresponding
1081 strub modes would be consistent with requests from attributes and command
1082 line flags. Attributes associated with functions pretty much mandate a
1083 selection, and should report an error if not satisfied; strub_flag_auto
1084 implicitly enables some viable strub mode if that's required by references
1085 to variables marked for strub; strub_flag_viable enables strub if viable
1086 (even when favoring one mode, body-requested strub can still be satisfied
1087 by either mode), and falls back to callable, silently unless variables
1088 require strubbing. */
1089
1090 const bool consider_at_calls
1091 = (!strub_flag_disabled
1092 && (strub_attr
1093 ? req_mode == STRUB_AT_CALLS
1094 : true));
1095 const bool consider_internal
1096 = (!strub_flag_disabled
1097 && (strub_attr
1098 ? req_mode == STRUB_INTERNAL
1099 : true));
1100
1101 const bool consider_callable
1102 = (!strub_flag_disabled
1103 && (strub_attr
1104 ? req_mode == STRUB_CALLABLE
1105 : (!strub_flag_strict
1106 || strub_callable_builtin_p (node))));
1107
1108 /* This is a shorthand for either strub-enabled mode. */
1109 const bool consider_strub
1110 = (consider_at_calls || consider_internal);
1111
1112 /* We can cope with always_inline functions even with noipa and noclone,
1113 because we just leave them alone. */
1114 const bool is_always_inline
1115 = strub_always_inline_p (node);
1116
1117 /* Strubbing in general, and each specific strub mode, may have its own set of
1118 requirements. We require noipa for strubbing, either because of cloning
1119 required for internal strub, or because of caller enumeration required for
1120 at-calls strub. We don't consider the at-calls mode eligible if it's not
1121 even considered, it has no further requirements. Internal mode requires
1122 cloning and the absence of certain features in the body and, like at-calls,
1123 it's not eligible if it's not even under consideration.
1124
1125 ??? Do we need target hooks for further constraints? E.g., x86's
1126 "interrupt" attribute breaks internal strubbing because the wrapped clone
1127 carries the attribute and thus isn't callable; in this case, we could use a
1128 target hook to adjust the clone instead. */
1129 const bool strub_eligible
1130 = (consider_strub
1131 && (is_always_inline || can_strub_p (node)));
1132 const bool at_calls_eligible
1133 = (consider_at_calls && strub_eligible
1134 && can_strub_at_calls_p (node));
1135 const bool internal_eligible
1136 = (consider_internal && strub_eligible
1137 && (is_always_inline
1138 || can_strub_internally_p (node)));
1139
1140 /* In addition to the strict eligibility requirements, some additional
1141 constraints are placed on implicit selection of certain modes. These do
1142 not prevent the selection of a mode if explicitly specified as part of a
1143 function interface (the strub attribute), but they may prevent modes from
1144 being selected by the command line or by function bodies. The only actual
1145 constraint is on at-calls mode: since we change the function's exposed
1146 signature, we won't do it implicitly if the function can possibly be used
1147 in ways that do not expect the signature change, e.g., if the function is
1148 available to or interposable by other units, if its address is taken,
1149 etc. */
1150 const bool at_calls_viable
1151 = (at_calls_eligible
1152 && (strub_attr
1153 || (node->has_gimple_body_p ()
1154 && (!node->externally_visible
1155 || (node->binds_to_current_def_p ()
1156 && node->can_be_local_p ()))
1157 && node->only_called_directly_p ()
1158 && !called_with_type_override_p (node))));
1159 const bool internal_viable
1160 = (internal_eligible);
1161
1162 /* Shorthand. */
1163 const bool strub_viable
1164 = (at_calls_viable || internal_viable);
1165
1166 /* We wish to analyze the body, to look for implicit requests for strub, both
1167 to implicitly enable it when the body calls for it, and to report errors if
1168 the body calls for it but neither mode is viable (even if that follows from
1169 non-eligibility because of the explicit specification of some non-strubbing
1170 mode). We can refrain from scanning the body only in rare circumstances:
1171 when strub is enabled by a function attribute (scanning might be redundant
1172 in telling us to also enable it), and when we are enabling strub implicitly
1173 but there are non-viable modes: we want to know whether strubbing is
1174 required, to fallback to another mode, even if we're only enabling a
1175 certain mode, or, when either mode would do, to report an error if neither
1176 happens to be viable. */
1177 const bool analyze_body
1178 = (strub_attr
1179 ? !consider_strub
1180 : (strub_flag_auto
1181 || (strub_flag_viable && (!at_calls_viable && !internal_viable))
1182 || (strub_flag_either && !strub_viable)));
1183
1184 /* Cases in which strubbing is enabled or disabled by strub_flag_auto.
1185 Unsatisfiable requests ought to be reported. */
1186 const bool strub_required
1187 = ((strub_attr && consider_strub)
1188 || (analyze_body && strub_from_body_p (node)));
1189
1190 /* Besides the required cases, we want to abide by the requests to enabling on
1191 an if-viable basis. */
1192 const bool strub_enable
1193 = (strub_required
1194 || (strub_flag_at_calls && at_calls_viable)
1195 || (strub_flag_internal && internal_viable)
1196 || (strub_flag_either && strub_viable));
1197
1198 /* And now we're finally ready to select a mode that abides by the viability
1199 and eligibility constraints, and that satisfies the strubbing requirements
1200 and requests, subject to the constraints. If both modes are viable and
1201 strub is to be enabled, pick STRUB_AT_CALLS unless STRUB_INTERNAL was named
1202 as preferred. */
1203 const enum strub_mode mode
1204 = ((strub_enable && is_always_inline)
1205 ? (strub_required ? STRUB_INLINABLE : STRUB_CALLABLE)
1206 : (strub_enable && internal_viable
1207 && (strub_flag_internal || !at_calls_viable))
1208 ? STRUB_INTERNAL
1209 : (strub_enable && at_calls_viable)
1210 ? (strub_required && !strub_attr
1211 ? STRUB_AT_CALLS_OPT
1212 : STRUB_AT_CALLS)
1213 : consider_callable
1214 ? STRUB_CALLABLE
1215 : STRUB_DISABLED);
1216
1217 switch (mode)
1218 {
1219 case STRUB_CALLABLE:
1220 if (is_always_inline)
1221 break;
1222 /* Fall through. */
1223
1224 case STRUB_DISABLED:
1225 if (strub_enable && !strub_attr)
1226 {
1227 gcc_checking_assert (analyze_body);
1228 error_at (DECL_SOURCE_LOCATION (node->decl),
1229 "%qD requires %<strub%>,"
1230 " but no viable %<strub%> mode was found",
1231 node->decl);
1232 break;
1233 }
1234 /* Fall through. */
1235
1236 case STRUB_AT_CALLS:
1237 case STRUB_INTERNAL:
1238 case STRUB_INLINABLE:
1239 /* Differences from an mode requested through a function attribute are
1240 reported in set_strub_mode_to. */
1241 break;
1242
1243 case STRUB_AT_CALLS_OPT:
1244 /* Functions that select this mode do so because of references to strub
1245 variables. Even if we choose at-calls as an optimization, the
1246 requirements for internal strub must still be satisfied. Optimization
1247 options may render implicit at-calls strub not viable (-O0 sets
1248 force_output for static non-inline functions), and it would not be good
1249 if changing optimization options turned a well-formed into an
1250 ill-formed one. */
1251 if (!internal_viable)
1252 can_strub_internally_p (node, report: true);
1253 break;
1254
1255 case STRUB_WRAPPED:
1256 case STRUB_WRAPPER:
1257 default:
1258 gcc_unreachable ();
1259 }
1260
1261 return mode;
1262}
1263
1264/* Set FNDT's strub mode to MODE; FNDT may be a function decl or
1265 function type. If OVERRIDE, do not check whether a mode is already
1266 set. */
1267
1268static void
1269strub_set_fndt_mode_to (tree fndt, enum strub_mode mode, bool override)
1270{
1271 gcc_checking_assert (override
1272 || !(DECL_P (fndt)
1273 ? get_strub_attr_from_decl (fndt)
1274 : get_strub_attr_from_type (fndt)));
1275
1276 tree attr = tree_cons (get_identifier ("strub"),
1277 get_strub_mode_attr_value (mode),
1278 NULL_TREE);
1279 tree *attrp = NULL;
1280 if (DECL_P (fndt))
1281 {
1282 gcc_checking_assert (FUNC_OR_METHOD_TYPE_P (TREE_TYPE (fndt)));
1283 attrp = &DECL_ATTRIBUTES (fndt);
1284 }
1285 else if (FUNC_OR_METHOD_TYPE_P (fndt))
1286 attrp = &TYPE_ATTRIBUTES (fndt);
1287 else
1288 gcc_unreachable ();
1289
1290 TREE_CHAIN (attr) = *attrp;
1291 *attrp = attr;
1292}
1293
1294/* Set FNDT's strub mode to callable.
1295 FNDT may be a function decl or a function type. */
1296
1297void
1298strub_make_callable (tree fndt)
1299{
1300 strub_set_fndt_mode_to (fndt, mode: STRUB_CALLABLE, override: false);
1301}
1302
1303/* Set NODE to strub MODE. Report incompatibilities between MODE and the mode
1304 requested through explicit attributes, and cases of non-eligibility. */
1305
1306static void
1307set_strub_mode_to (cgraph_node *node, enum strub_mode mode)
1308{
1309 tree attr = get_strub_attr_from_decl (decl: node->decl);
1310 enum strub_mode req_mode = get_strub_mode_from_attr (strub_attr: attr);
1311
1312 if (attr)
1313 {
1314 /* Check for and report incompatible mode changes. */
1315 if (mode != req_mode
1316 && !(req_mode == STRUB_INTERNAL
1317 && (mode == STRUB_WRAPPED
1318 || mode == STRUB_WRAPPER))
1319 && !((req_mode == STRUB_INTERNAL
1320 || req_mode == STRUB_AT_CALLS
1321 || req_mode == STRUB_CALLABLE)
1322 && mode == STRUB_INLINABLE))
1323 {
1324 error_at (DECL_SOURCE_LOCATION (node->decl),
1325 "%<strub%> mode %qE selected for %qD, when %qE was requested",
1326 get_strub_mode_attr_parm (mode),
1327 node->decl,
1328 get_strub_mode_attr_parm (mode: req_mode));
1329 if (node->alias)
1330 {
1331 cgraph_node *target = node->ultimate_alias_target ();
1332 if (target != node)
1333 error_at (DECL_SOURCE_LOCATION (target->decl),
1334 "the incompatible selection was determined"
1335 " by ultimate alias target %qD",
1336 target->decl);
1337 }
1338
1339 /* Report any incompatibilities with explicitly-requested strub. */
1340 switch (req_mode)
1341 {
1342 case STRUB_AT_CALLS:
1343 can_strub_at_calls_p (node, report: true);
1344 break;
1345
1346 case STRUB_INTERNAL:
1347 can_strub_internally_p (node, report: true);
1348 break;
1349
1350 default:
1351 break;
1352 }
1353 }
1354
1355 /* Drop any incompatible strub attributes leading the decl attribute
1356 chain. Return if we find one with the mode we need. */
1357 for (;;)
1358 {
1359 if (mode == req_mode)
1360 return;
1361
1362 if (DECL_ATTRIBUTES (node->decl) != attr)
1363 break;
1364
1365 DECL_ATTRIBUTES (node->decl) = TREE_CHAIN (attr);
1366 attr = get_strub_attr_from_decl (decl: node->decl);
1367 if (!attr)
1368 break;
1369
1370 req_mode = get_strub_mode_from_attr (strub_attr: attr);
1371 }
1372 }
1373 else if (mode == req_mode)
1374 return;
1375
1376 strub_set_fndt_mode_to (fndt: node->decl, mode, override: attr);
1377}
1378
1379/* Compute and set NODE's strub mode. */
1380
1381static void
1382set_strub_mode (cgraph_node *node)
1383{
1384 tree attr = get_strub_attr_from_decl (decl: node->decl);
1385
1386 if (attr)
1387 switch (get_strub_mode_from_attr (strub_attr: attr))
1388 {
1389 /* These can't have been requested through user attributes, so we must
1390 have already gone through them. */
1391 case STRUB_WRAPPER:
1392 case STRUB_WRAPPED:
1393 case STRUB_INLINABLE:
1394 case STRUB_AT_CALLS_OPT:
1395 return;
1396
1397 case STRUB_DISABLED:
1398 case STRUB_AT_CALLS:
1399 case STRUB_INTERNAL:
1400 case STRUB_CALLABLE:
1401 break;
1402
1403 default:
1404 gcc_unreachable ();
1405 }
1406
1407 cgraph_node *xnode = node;
1408 if (node->alias)
1409 xnode = node->ultimate_alias_target ();
1410 /* Weakrefs may remain unresolved (the above will return node) if
1411 their targets are not defined, so make sure we compute a strub
1412 mode for them, instead of defaulting to STRUB_DISABLED and
1413 rendering them uncallable. */
1414 enum strub_mode mode = (xnode != node && !xnode->alias
1415 ? get_strub_mode (node: xnode)
1416 : compute_strub_mode (node, strub_attr: attr));
1417
1418 set_strub_mode_to (node, mode);
1419}
1420
1421
1422/* Non-strub functions shouldn't be called from within strub contexts,
1423 except through callable ones. Always inline strub functions can
1424 only be called from strub functions. */
1425
1426static bool
1427strub_callable_from_p (strub_mode caller_mode, strub_mode callee_mode)
1428{
1429 switch (caller_mode)
1430 {
1431 case STRUB_WRAPPED:
1432 case STRUB_AT_CALLS_OPT:
1433 case STRUB_AT_CALLS:
1434 case STRUB_INTERNAL:
1435 case STRUB_INLINABLE:
1436 break;
1437
1438 case STRUB_WRAPPER:
1439 case STRUB_DISABLED:
1440 case STRUB_CALLABLE:
1441 return callee_mode != STRUB_INLINABLE;
1442
1443 default:
1444 gcc_unreachable ();
1445 }
1446
1447 switch (callee_mode)
1448 {
1449 case STRUB_WRAPPED:
1450 case STRUB_AT_CALLS:
1451 case STRUB_INLINABLE:
1452 break;
1453
1454 case STRUB_AT_CALLS_OPT:
1455 case STRUB_INTERNAL:
1456 case STRUB_WRAPPER:
1457 return (flag_strub >= -1);
1458
1459 case STRUB_DISABLED:
1460 return false;
1461
1462 case STRUB_CALLABLE:
1463 break;
1464
1465 default:
1466 gcc_unreachable ();
1467 }
1468
1469 return true;
1470}
1471
1472/* Return TRUE iff CALLEE can be inlined into CALLER. We wish to avoid inlining
1473 WRAPPED functions back into their WRAPPERs. More generally, we wish to avoid
1474 inlining strubbed functions into non-strubbed ones. CALLER doesn't have to
1475 be an immediate caller of CALLEE: the immediate caller may have already been
1476 cloned for inlining, and then CALLER may be further up the original call
1477 chain. ??? It would be nice if our own caller would retry inlining callee
1478 if caller gets inlined. */
1479
1480bool
1481strub_inlinable_to_p (cgraph_node *callee, cgraph_node *caller)
1482{
1483 strub_mode callee_mode = get_strub_mode (node: callee);
1484
1485 switch (callee_mode)
1486 {
1487 case STRUB_WRAPPED:
1488 case STRUB_AT_CALLS:
1489 case STRUB_INTERNAL:
1490 case STRUB_INLINABLE:
1491 case STRUB_AT_CALLS_OPT:
1492 break;
1493
1494 case STRUB_WRAPPER:
1495 case STRUB_DISABLED:
1496 case STRUB_CALLABLE:
1497 /* When we consider inlining, we've already verified callability, so we
1498 can even inline callable and then disabled into a strub context. That
1499 will get strubbed along with the context, so it's hopefully not a
1500 problem. */
1501 return true;
1502
1503 default:
1504 gcc_unreachable ();
1505 }
1506
1507 strub_mode caller_mode = get_strub_mode (node: caller);
1508
1509 switch (caller_mode)
1510 {
1511 case STRUB_WRAPPED:
1512 case STRUB_AT_CALLS:
1513 case STRUB_INTERNAL:
1514 case STRUB_INLINABLE:
1515 case STRUB_AT_CALLS_OPT:
1516 return true;
1517
1518 case STRUB_WRAPPER:
1519 case STRUB_DISABLED:
1520 case STRUB_CALLABLE:
1521 break;
1522
1523 default:
1524 gcc_unreachable ();
1525 }
1526
1527 return false;
1528}
1529
1530/* Check that types T1 and T2 are strub-compatible. Return 1 if the strub modes
1531 are the same, 2 if they are interchangeable, and 0 otherwise. */
1532
1533int
1534strub_comptypes (tree t1, tree t2)
1535{
1536 if (TREE_CODE (t1) != TREE_CODE (t2))
1537 return 0;
1538
1539 enum strub_mode m1 = get_strub_mode_from_type (type: t1);
1540 enum strub_mode m2 = get_strub_mode_from_type (type: t2);
1541
1542 if (m1 == m2)
1543 return 1;
1544
1545 /* We're dealing with types, so only strub modes that can be selected by
1546 attributes in the front end matter. If either mode is at-calls (for
1547 functions) or internal (for variables), the conversion is not
1548 compatible. */
1549 bool var_p = !FUNC_OR_METHOD_TYPE_P (t1);
1550 enum strub_mode mr = var_p ? STRUB_INTERNAL : STRUB_AT_CALLS;
1551 if (m1 == mr || m2 == mr)
1552 return 0;
1553
1554 return 2;
1555}
1556
1557/* Return the effective strub mode used for CALL, and set *TYPEP to
1558 the effective type used for the call. The effective type and mode
1559 are those of the callee, unless the call involves a typecast. */
1560
1561static enum strub_mode
1562effective_strub_mode_for_call (gcall *call, tree *typep)
1563{
1564 tree type;
1565 enum strub_mode mode;
1566
1567 if (strub_call_fntype_override_p (gs: call))
1568 {
1569 type = gimple_call_fntype (gs: call);
1570 mode = get_strub_mode_from_type (type);
1571 }
1572 else
1573 {
1574 type = TREE_TYPE (TREE_TYPE (gimple_call_fn (call)));
1575 tree decl = gimple_call_fndecl (gs: call);
1576 if (decl)
1577 mode = get_strub_mode_from_fndecl (fndecl: decl);
1578 else
1579 mode = get_strub_mode_from_type (type);
1580 }
1581
1582 if (typep)
1583 *typep = type;
1584
1585 return mode;
1586}
1587
1588/* Create a distinct copy of the type of NODE's function, and change
1589 the fntype of all calls to it with the same main type to the new
1590 type. */
1591
1592static void
1593distinctify_node_type (cgraph_node *node)
1594{
1595 tree old_type = TREE_TYPE (node->decl);
1596 tree new_type = build_distinct_type_copy (old_type);
1597 tree new_ptr_type = NULL_TREE;
1598
1599 /* Remap any calls to node->decl that use old_type, or a variant
1600 thereof, to new_type as well. We don't look for aliases, their
1601 declarations will have their types changed independently, and
1602 we'll adjust their fntypes then. */
1603 for (cgraph_edge *e = node->callers; e; e = e->next_caller)
1604 {
1605 if (!e->call_stmt)
1606 continue;
1607 tree fnaddr = gimple_call_fn (gs: e->call_stmt);
1608 gcc_checking_assert (TREE_CODE (fnaddr) == ADDR_EXPR
1609 && TREE_OPERAND (fnaddr, 0) == node->decl);
1610 if (strub_call_fntype_override_p (gs: e->call_stmt))
1611 continue;
1612 if (!new_ptr_type)
1613 new_ptr_type = build_pointer_type (new_type);
1614 TREE_TYPE (fnaddr) = new_ptr_type;
1615 gimple_call_set_fntype (call_stmt: e->call_stmt, fntype: new_type);
1616 }
1617
1618 TREE_TYPE (node->decl) = new_type;
1619}
1620
1621/* Return TRUE iff TYPE and any variants have the same strub mode. */
1622
1623static bool
1624same_strub_mode_in_variants_p (tree type)
1625{
1626 enum strub_mode mode = get_strub_mode_from_type (type);
1627
1628 for (tree other = TYPE_MAIN_VARIANT (type);
1629 other != NULL_TREE; other = TYPE_NEXT_VARIANT (other))
1630 if (type != other && mode != get_strub_mode_from_type (type: other))
1631 return false;
1632
1633 /* Check that the canonical type, if set, either is in the same
1634 variant chain, or has the same strub mode as type. Also check
1635 the variants of the canonical type. */
1636 if (TYPE_CANONICAL (type)
1637 && (TYPE_MAIN_VARIANT (TYPE_CANONICAL (type))
1638 != TYPE_MAIN_VARIANT (type)))
1639 {
1640 if (mode != get_strub_mode_from_type (TYPE_CANONICAL (type)))
1641 return false;
1642 else
1643 return same_strub_mode_in_variants_p (TYPE_CANONICAL (type));
1644 }
1645
1646 return true;
1647}
1648
1649/* Check that strub functions don't call non-strub functions, and that
1650 always_inline strub functions are only called by strub
1651 functions. */
1652
1653static void
1654verify_strub ()
1655{
1656 cgraph_node *node;
1657
1658 /* It's expected that check strub-wise pointer type compatibility of variables
1659 and of functions is already taken care of by front-ends, on account of the
1660 attribute's being marked as affecting type identity and of the creation of
1661 distinct types. */
1662
1663 /* Check that call targets in strub contexts have strub-callable types. */
1664
1665 FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
1666 {
1667 enum strub_mode caller_mode = get_strub_mode (node);
1668
1669 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
1670 {
1671 gcc_checking_assert (e->indirect_unknown_callee);
1672
1673 if (!e->call_stmt)
1674 continue;
1675
1676 enum strub_mode callee_mode
1677 = effective_strub_mode_for_call (call: e->call_stmt, NULL);
1678
1679 if (!strub_callable_from_p (caller_mode, callee_mode))
1680 error_at (gimple_location (g: e->call_stmt),
1681 "indirect non-%<strub%> call in %<strub%> context %qD",
1682 node->decl);
1683 }
1684
1685 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
1686 {
1687 gcc_checking_assert (!e->indirect_unknown_callee);
1688
1689 if (!e->call_stmt)
1690 continue;
1691
1692 tree callee_fntype;
1693 enum strub_mode callee_mode
1694 = effective_strub_mode_for_call (call: e->call_stmt, typep: &callee_fntype);
1695
1696 if (!strub_callable_from_p (caller_mode, callee_mode))
1697 {
1698 if (callee_mode == STRUB_INLINABLE)
1699 error_at (gimple_location (g: e->call_stmt),
1700 "calling %<always_inline%> %<strub%> %qD"
1701 " in non-%<strub%> context %qD",
1702 e->callee->decl, node->decl);
1703 else if (fndecl_built_in_p (node: e->callee->decl, name1: BUILT_IN_APPLY_ARGS)
1704 && caller_mode == STRUB_INTERNAL)
1705 /* This is ok, it will be kept in the STRUB_WRAPPER, and removed
1706 from the STRUB_WRAPPED's strub context. */
1707 continue;
1708 else if (!strub_call_fntype_override_p (gs: e->call_stmt))
1709 error_at (gimple_location (g: e->call_stmt),
1710 "calling non-%<strub%> %qD in %<strub%> context %qD",
1711 e->callee->decl, node->decl);
1712 else
1713 error_at (gimple_location (g: e->call_stmt),
1714 "calling %qD using non-%<strub%> type %qT"
1715 " in %<strub%> context %qD",
1716 e->callee->decl, callee_fntype, node->decl);
1717 }
1718 }
1719 }
1720}
1721
1722namespace {
1723
1724/* Define a pass to compute strub modes. */
1725const pass_data pass_data_ipa_strub_mode = {
1726 .type: SIMPLE_IPA_PASS,
1727 .name: "strubm",
1728 .optinfo_flags: OPTGROUP_NONE,
1729 .tv_id: TV_NONE,
1730 PROP_cfg, // properties_required
1731 .properties_provided: 0, // properties_provided
1732 .properties_destroyed: 0, // properties_destroyed
1733 .todo_flags_start: 0, // properties_start
1734 .todo_flags_finish: 0, // properties_finish
1735};
1736
1737class pass_ipa_strub_mode : public simple_ipa_opt_pass
1738{
1739public:
1740 pass_ipa_strub_mode (gcc::context *ctxt)
1741 : simple_ipa_opt_pass (pass_data_ipa_strub_mode, ctxt)
1742 {}
1743 opt_pass *clone () { return new pass_ipa_strub_mode (m_ctxt); }
1744 virtual bool gate (function *) {
1745 /* In relaxed (-3) and strict (-4) settings, that only enable strub at a
1746 function or variable attribute's request, the attribute handler changes
1747 flag_strub to -1 or -2, respectively, if any strub-enabling occurence of
1748 the attribute is found. Therefore, if it remains at -3 or -4, nothing
1749 that would enable strub was found, so we can disable it and avoid the
1750 overhead. */
1751 if (flag_strub < -2)
1752 flag_strub = 0;
1753 return flag_strub;
1754 }
1755 virtual unsigned int execute (function *);
1756};
1757
1758/* Define a pass to introduce strub transformations. */
1759const pass_data pass_data_ipa_strub = {
1760 .type: SIMPLE_IPA_PASS,
1761 .name: "strub",
1762 .optinfo_flags: OPTGROUP_NONE,
1763 .tv_id: TV_NONE,
1764 PROP_cfg | PROP_ssa, // properties_required
1765 .properties_provided: 0, // properties_provided
1766 .properties_destroyed: 0, // properties_destroyed
1767 .todo_flags_start: 0, // properties_start
1768 TODO_update_ssa
1769 | TODO_cleanup_cfg
1770 | TODO_rebuild_cgraph_edges
1771 | TODO_verify_il, // properties_finish
1772};
1773
1774class pass_ipa_strub : public simple_ipa_opt_pass
1775{
1776public:
1777 pass_ipa_strub (gcc::context *ctxt)
1778 : simple_ipa_opt_pass (pass_data_ipa_strub, ctxt)
1779 {}
1780 opt_pass *clone () { return new pass_ipa_strub (m_ctxt); }
1781 virtual bool gate (function *) { return flag_strub && !seen_error (); }
1782 virtual unsigned int execute (function *);
1783
1784 /* Define on demand and cache some types we use often. */
1785#define DEF_TYPE(IDX, NAME, INIT) \
1786 static inline tree get_ ## NAME () { \
1787 int idx = STRUB_TYPE_BASE + IDX; \
1788 static tree type = strub_cache[idx]; \
1789 if (!type) \
1790 strub_cache[idx] = type = (INIT); \
1791 return type; \
1792 }
1793
1794 /* Use a distinct ptr_type_node to denote the watermark, so that we can
1795 recognize it in arg lists and avoid modifying types twice. */
1796 DEF_TYPE (0, wmt, build_variant_type_copy (ptr_type_node))
1797
1798 DEF_TYPE (1, pwmt, build_reference_type (get_wmt ()))
1799
1800 DEF_TYPE (2, qpwmt,
1801 build_qualified_type (get_pwmt (),
1802 TYPE_QUAL_RESTRICT
1803 /* | TYPE_QUAL_CONST */))
1804
1805 DEF_TYPE (3, qptr,
1806 build_qualified_type (ptr_type_node,
1807 TYPE_QUAL_RESTRICT
1808 | TYPE_QUAL_CONST))
1809
1810 DEF_TYPE (4, qpvalst,
1811 build_qualified_type (build_reference_type
1812 (va_list_type_node),
1813 TYPE_QUAL_RESTRICT
1814 /* | TYPE_QUAL_CONST */))
1815
1816#undef DEF_TYPE
1817
1818 /* Define non-strub builtins on demand. */
1819#define DEF_NM_BUILTIN(NAME, CODE, FNTYPELIST) \
1820 static tree get_ ## NAME () { \
1821 tree decl = builtin_decl_explicit (CODE); \
1822 if (!decl) \
1823 { \
1824 tree type = build_function_type_list FNTYPELIST; \
1825 decl = add_builtin_function \
1826 ("__builtin_" #NAME, \
1827 type, CODE, BUILT_IN_NORMAL, \
1828 NULL, NULL); \
1829 TREE_NOTHROW (decl) = true; \
1830 set_builtin_decl ((CODE), decl, true); \
1831 } \
1832 return decl; \
1833 }
1834
1835 DEF_NM_BUILTIN (stack_address,
1836 BUILT_IN_STACK_ADDRESS,
1837 (ptr_type_node, NULL))
1838
1839#undef DEF_NM_BUILTIN
1840
1841 /* Define strub builtins on demand. */
1842#define DEF_SS_BUILTIN(NAME, FNSPEC, CODE, FNTYPELIST) \
1843 static tree get_ ## NAME () { \
1844 tree decl = builtin_decl_explicit (CODE); \
1845 if (!decl) \
1846 { \
1847 tree type = build_function_type_list FNTYPELIST; \
1848 tree attrs = NULL; \
1849 if (FNSPEC) \
1850 attrs = tree_cons (get_identifier ("fn spec"), \
1851 build_tree_list \
1852 (NULL_TREE, \
1853 build_string (strlen (FNSPEC), \
1854 (FNSPEC))), \
1855 attrs); \
1856 decl = add_builtin_function_ext_scope \
1857 ("__builtin___strub_" #NAME, \
1858 type, CODE, BUILT_IN_NORMAL, \
1859 "__strub_" #NAME, attrs); \
1860 TREE_NOTHROW (decl) = true; \
1861 set_builtin_decl ((CODE), decl, true); \
1862 } \
1863 return decl; \
1864 }
1865
1866 DEF_SS_BUILTIN (enter, ". Ot",
1867 BUILT_IN___STRUB_ENTER,
1868 (void_type_node, get_qpwmt (), NULL))
1869 DEF_SS_BUILTIN (update, ". Wt",
1870 BUILT_IN___STRUB_UPDATE,
1871 (void_type_node, get_qpwmt (), NULL))
1872 DEF_SS_BUILTIN (leave, ". w ",
1873 BUILT_IN___STRUB_LEAVE,
1874 (void_type_node, get_qpwmt (), NULL))
1875
1876#undef DEF_SS_BUILTIN
1877
1878 /* Define strub identifiers on demand. */
1879#define DEF_IDENT(IDX, NAME) \
1880 static inline tree get_ ## NAME () { \
1881 int idx = STRUB_IDENT_BASE + IDX; \
1882 tree identifier = strub_cache[idx]; \
1883 if (!identifier) \
1884 strub_cache[idx] = identifier = get_identifier (".strub." #NAME); \
1885 return identifier; \
1886 }
1887
1888 DEF_IDENT (0, watermark_ptr)
1889 DEF_IDENT (1, va_list_ptr)
1890 DEF_IDENT (2, apply_args)
1891
1892#undef DEF_IDENT
1893
1894 static inline int adjust_at_calls_type (tree);
1895 static inline void adjust_at_calls_call (cgraph_edge *, int, tree);
1896 static inline void adjust_at_calls_calls (cgraph_node *);
1897
1898 /* Add to SEQ a call to the strub watermark update builtin, taking NODE's
1899 location if given. Optionally add the corresponding edge from NODE, with
1900 execution frequency COUNT. Return the modified SEQ. */
1901
1902 static inline gimple_seq
1903 call_update_watermark (tree wmptr, cgraph_node *node, profile_count count,
1904 gimple_seq seq = NULL)
1905 {
1906 tree uwm = get_update ();
1907 gcall *update = gimple_build_call (uwm, 1, wmptr);
1908 if (node)
1909 gimple_set_location (g: update, DECL_SOURCE_LOCATION (node->decl));
1910 gimple_seq_add_stmt (&seq, update);
1911 if (node)
1912 node->create_edge (callee: cgraph_node::get_create (uwm), call_stmt: update, count, cloning_p: false);
1913 return seq;
1914 }
1915
1916};
1917
1918} // anon namespace
1919
1920/* Gather with this type a collection of parameters that we're turning into
1921 explicit references. */
1922
1923typedef hash_set<tree> indirect_parms_t;
1924
1925/* Dereference OP's incoming turned-into-reference parm if it's an
1926 INDIRECT_PARMS or an ADDR_EXPR thereof. Set *REC and return according to
1927 gimple-walking expectations. */
1928
1929static tree
1930maybe_make_indirect (indirect_parms_t &indirect_parms, tree op, int *rec)
1931{
1932 if (DECL_P (op))
1933 {
1934 *rec = 0;
1935 if (indirect_parms.contains (k: op))
1936 {
1937 tree ret = gimple_fold_indirect_ref (op);
1938 if (!ret)
1939 ret = build2 (MEM_REF,
1940 TREE_TYPE (TREE_TYPE (op)),
1941 op,
1942 build_int_cst (TREE_TYPE (op), 0));
1943 if (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (op)))
1944 && !TREE_THIS_VOLATILE (ret))
1945 TREE_SIDE_EFFECTS (ret) = TREE_THIS_VOLATILE (ret) = 1;
1946 return ret;
1947 }
1948 }
1949 else if (TREE_CODE (op) == ADDR_EXPR
1950 && DECL_P (TREE_OPERAND (op, 0)))
1951 {
1952 *rec = 0;
1953 if (indirect_parms.contains (TREE_OPERAND (op, 0)))
1954 {
1955 op = TREE_OPERAND (op, 0);
1956 return op;
1957 }
1958 }
1959
1960 return NULL_TREE;
1961}
1962
1963/* A gimple-walking function that adds dereferencing to indirect parms. */
1964
1965static tree
1966walk_make_indirect (tree *op, int *rec, void *arg)
1967{
1968 walk_stmt_info *wi = (walk_stmt_info *)arg;
1969 indirect_parms_t &indirect_parms = *(indirect_parms_t *)wi->info;
1970
1971 if (!*op || TYPE_P (*op))
1972 {
1973 *rec = 0;
1974 return NULL_TREE;
1975 }
1976
1977 if (tree repl = maybe_make_indirect (indirect_parms, op: *op, rec))
1978 {
1979 *op = repl;
1980 wi->changed = true;
1981 }
1982
1983 return NULL_TREE;
1984}
1985
1986/* A gimple-walking function that turns any non-gimple-val ADDR_EXPRs into a
1987 separate SSA. Though addresses of e.g. parameters, and of members thereof,
1988 are gimple vals, turning parameters into references, with an extra layer of
1989 indirection and thus explicit dereferencing, need to be regimplified. */
1990
1991static tree
1992walk_regimplify_addr_expr (tree *op, int *rec, void *arg)
1993{
1994 walk_stmt_info *wi = (walk_stmt_info *)arg;
1995 gimple_stmt_iterator &gsi = *(gimple_stmt_iterator *)wi->info;
1996
1997 *rec = 0;
1998
1999 if (!*op || TREE_CODE (*op) != ADDR_EXPR)
2000 return NULL_TREE;
2001
2002 if (!is_gimple_val (*op))
2003 {
2004 tree ret = force_gimple_operand_gsi (&gsi, *op, true,
2005 NULL_TREE, true, GSI_SAME_STMT);
2006 gcc_assert (ret != *op);
2007 *op = ret;
2008 wi->changed = true;
2009 }
2010
2011 return NULL_TREE;
2012}
2013
2014/* Turn STMT's PHI arg defs into separate SSA defs if they've become
2015 non-gimple_val. Return TRUE if any edge insertions need to be committed. */
2016
2017static bool
2018walk_regimplify_phi (gphi *stmt)
2019{
2020 bool needs_commit = false;
2021
2022 for (unsigned i = 0, n = gimple_phi_num_args (gs: stmt); i < n; i++)
2023 {
2024 tree op = gimple_phi_arg_def (gs: stmt, index: i);
2025 if ((TREE_CODE (op) == ADDR_EXPR
2026 && !is_gimple_val (op))
2027 /* ??? A PARM_DECL that was addressable in the original function and
2028 had its address in PHI nodes, but that became a reference in the
2029 wrapped clone would NOT be updated by update_ssa in PHI nodes.
2030 Alas, if we were to create a default def for it now, update_ssa
2031 would complain that the symbol that needed rewriting already has
2032 SSA names associated with it. OTOH, leaving the PARM_DECL alone,
2033 it eventually causes errors because it remains unchanged in PHI
2034 nodes, but it gets rewritten as expected if it appears in other
2035 stmts. So we cheat a little here, and force the PARM_DECL out of
2036 the PHI node and into an assignment. It's a little expensive,
2037 because we insert it at the edge, which introduces a basic block
2038 that's entirely unnecessary, but it works, and the block will be
2039 removed as the default def gets propagated back into the PHI node,
2040 so the final optimized code looks just as expected. */
2041 || (TREE_CODE (op) == PARM_DECL
2042 && !TREE_ADDRESSABLE (op)))
2043 {
2044 tree temp = make_ssa_name (TREE_TYPE (op), stmt);
2045 if (TREE_CODE (op) == PARM_DECL)
2046 SET_SSA_NAME_VAR_OR_IDENTIFIER (temp, DECL_NAME (op));
2047 SET_PHI_ARG_DEF (stmt, i, temp);
2048
2049 gimple *assign = gimple_build_assign (temp, op);
2050 if (gimple_phi_arg_has_location (phi: stmt, i))
2051 gimple_set_location (g: assign, location: gimple_phi_arg_location (phi: stmt, i));
2052 gsi_insert_on_edge (gimple_phi_arg_edge (phi: stmt, i), assign);
2053 needs_commit = true;
2054 }
2055 }
2056
2057 return needs_commit;
2058}
2059
2060/* Create a reference type to use for PARM when turning it into a
2061 reference. */
2062
2063static tree
2064build_ref_type_for (tree parm)
2065{
2066 gcc_checking_assert (TREE_CODE (parm) == PARM_DECL);
2067
2068 tree ref_type = build_reference_type (TREE_TYPE (parm));
2069
2070 return ref_type;
2071}
2072
2073/* Add cgraph edges from current_function_decl to callees in SEQ with frequency
2074 COUNT, assuming all calls in SEQ are direct. */
2075
2076static void
2077add_call_edges_for_seq (gimple_seq seq, profile_count count)
2078{
2079 cgraph_node *node = cgraph_node::get_create (current_function_decl);
2080
2081 for (gimple_stmt_iterator gsi = gsi_start (seq);
2082 !gsi_end_p (i: gsi); gsi_next (i: &gsi))
2083 {
2084 gimple *stmt = gsi_stmt (i: gsi);
2085
2086 gcall *call = dyn_cast <gcall *> (p: stmt);
2087 if (!call)
2088 continue;
2089
2090 tree callee = gimple_call_fndecl (gs: call);
2091 gcc_checking_assert (callee);
2092 node->create_edge (callee: cgraph_node::get_create (callee), call_stmt: call, count, cloning_p: false);
2093 }
2094}
2095
2096/* Insert SEQ after the call at GSI, as if the call was in a try block with SEQ
2097 as finally, i.e., SEQ will run after the call whether it returns or
2098 propagates an exception. This handles block splitting, EH edge and block
2099 creation, noreturn and nothrow optimizations, and even throwing calls without
2100 preexisting local handlers. */
2101
2102static void
2103gsi_insert_finally_seq_after_call (gimple_stmt_iterator gsi, gimple_seq seq)
2104{
2105 if (!seq)
2106 return;
2107
2108 gimple *stmt = gsi_stmt (i: gsi);
2109
2110 if (gimple_has_location (g: stmt))
2111 annotate_all_with_location (seq, gimple_location (g: stmt));
2112
2113 gcall *call = dyn_cast <gcall *> (p: stmt);
2114 bool noreturn_p = call && gimple_call_noreturn_p (s: call);
2115 int eh_lp = lookup_stmt_eh_lp (stmt);
2116 bool must_not_throw_p = eh_lp < 0;
2117 bool nothrow_p = (must_not_throw_p
2118 || (call && gimple_call_nothrow_p (s: call))
2119 || (eh_lp <= 0
2120 && (TREE_NOTHROW (cfun->decl)
2121 || !opt_for_fn (cfun->decl, flag_exceptions))));
2122
2123 if (noreturn_p && nothrow_p)
2124 return;
2125
2126 /* Don't expect an EH edge if we're not to throw, or if we're not in an EH
2127 region yet. */
2128 bool no_eh_edge_p = (nothrow_p || !eh_lp);
2129 bool must_end_bb = stmt_ends_bb_p (stmt);
2130
2131 edge eft = NULL, eeh = NULL;
2132 if (must_end_bb && !(noreturn_p && no_eh_edge_p))
2133 {
2134 gcc_checking_assert (gsi_one_before_end_p (gsi));
2135
2136 edge e;
2137 edge_iterator ei;
2138 FOR_EACH_EDGE (e, ei, gsi_bb (gsi)->succs)
2139 {
2140 if ((e->flags & EDGE_EH))
2141 {
2142 gcc_checking_assert (!eeh);
2143 eeh = e;
2144#if !CHECKING_P
2145 if (eft || noreturn_p)
2146 break;
2147#endif
2148 }
2149 if ((e->flags & EDGE_FALLTHRU))
2150 {
2151 gcc_checking_assert (!eft);
2152 eft = e;
2153#if !CHECKING_P
2154 if (eeh || no_eh_edge_p)
2155 break;
2156#endif
2157 }
2158 }
2159
2160 gcc_checking_assert (!(eft && (eft->flags & EDGE_FALLTHRU))
2161 == noreturn_p);
2162 gcc_checking_assert (!(eeh && (eeh->flags & EDGE_EH))
2163 == no_eh_edge_p);
2164 gcc_checking_assert (eft != eeh);
2165 }
2166
2167 if (!noreturn_p)
2168 {
2169 gimple_seq nseq = nothrow_p ? seq : gimple_seq_copy (seq);
2170
2171 if (must_end_bb)
2172 {
2173 gcc_checking_assert (gsi_one_before_end_p (gsi));
2174 add_call_edges_for_seq (seq: nseq, count: eft->count ());
2175 gsi_insert_seq_on_edge_immediate (eft, nseq);
2176 }
2177 else
2178 {
2179 add_call_edges_for_seq (seq: nseq, count: gsi_bb (i: gsi)->count);
2180 gsi_insert_seq_after (&gsi, nseq, GSI_SAME_STMT);
2181 }
2182 }
2183
2184 if (nothrow_p)
2185 return;
2186
2187 if (eh_lp)
2188 {
2189 add_call_edges_for_seq (seq, count: eeh->count ());
2190 gsi_insert_seq_on_edge_immediate (eeh, seq);
2191 return;
2192 }
2193
2194 /* A throwing call may appear within a basic block in a function that doesn't
2195 have any EH regions. We're going to add a cleanup if so, therefore the
2196 block will have to be split. */
2197 basic_block bb = gsi_bb (i: gsi);
2198 if (!gsi_one_before_end_p (i: gsi))
2199 split_block (bb, stmt);
2200
2201 /* Create a new block for the EH cleanup. */
2202 basic_block bb_eh_cleanup = create_empty_bb (bb);
2203 if (dom_info_available_p (CDI_DOMINATORS))
2204 set_immediate_dominator (CDI_DOMINATORS, bb_eh_cleanup, bb);
2205 if (current_loops)
2206 add_bb_to_loop (bb_eh_cleanup, current_loops->tree_root);
2207
2208 /* Make the new block an EH cleanup for the call. */
2209 eh_region new_r = gen_eh_region_cleanup (NULL);
2210 eh_landing_pad lp = gen_eh_landing_pad (new_r);
2211 tree label = gimple_block_label (bb_eh_cleanup);
2212 lp->post_landing_pad = label;
2213 EH_LANDING_PAD_NR (label) = lp->index;
2214 add_stmt_to_eh_lp (stmt, lp->index);
2215
2216 /* Add the cleanup code to the EH cleanup block. */
2217 gsi = gsi_after_labels (bb: bb_eh_cleanup);
2218 gsi_insert_seq_before (&gsi, seq, GSI_SAME_STMT);
2219
2220 /* And then propagate the exception further. */
2221 gresx *resx = gimple_build_resx (new_r->index);
2222 if (gimple_has_location (g: stmt))
2223 gimple_set_location (g: resx, location: gimple_location (g: stmt));
2224 gsi_insert_before (&gsi, resx, GSI_SAME_STMT);
2225
2226 /* Finally, wire the EH cleanup block into the CFG. */
2227 edge neeh = make_eh_edge (stmt);
2228 neeh->probability = profile_probability::never ();
2229 gcc_checking_assert (neeh->dest == bb_eh_cleanup);
2230 gcc_checking_assert (!neeh->dest->count.initialized_p ());
2231 neeh->dest->count = neeh->count ();
2232 add_call_edges_for_seq (seq, count: neeh->dest->count);
2233}
2234
2235/* Copy the attribute list at *ATTRS, minus any NAME attributes, leaving
2236 shareable trailing nodes alone. */
2237
2238static inline void
2239remove_named_attribute_unsharing (const char *name, tree *attrs)
2240{
2241 while (tree found = lookup_attribute (attr_name: name, list: *attrs))
2242 {
2243 /* Copy nodes up to the next NAME attribute. */
2244 while (*attrs != found)
2245 {
2246 *attrs = tree_cons (TREE_PURPOSE (*attrs),
2247 TREE_VALUE (*attrs),
2248 TREE_CHAIN (*attrs));
2249 attrs = &TREE_CHAIN (*attrs);
2250 }
2251 /* Then drop it. */
2252 gcc_checking_assert (*attrs == found);
2253 *attrs = TREE_CHAIN (*attrs);
2254 }
2255}
2256
2257/* Record the order of the last cgraph entry whose mode we've already set, so
2258 that we can perform mode setting incrementally without duplication. */
2259static int last_cgraph_order;
2260
2261/* Set strub modes for functions introduced since the last call. */
2262
2263static void
2264ipa_strub_set_mode_for_new_functions ()
2265{
2266 if (symtab->order == last_cgraph_order)
2267 return;
2268
2269 cgraph_node *node;
2270
2271 /* Go through the functions twice, once over non-aliases, and then over
2272 aliases, so that aliases can reuse the mode computation of their ultimate
2273 targets. */
2274 for (int aliases = 0; aliases <= 1; aliases++)
2275 FOR_EACH_FUNCTION (node)
2276 {
2277 if (!node->alias != !aliases)
2278 continue;
2279
2280 /* Already done. */
2281 if (node->order < last_cgraph_order)
2282 continue;
2283
2284 set_strub_mode (node);
2285 }
2286
2287 last_cgraph_order = symtab->order;
2288}
2289
2290/* Return FALSE if NODE is a strub context, and TRUE otherwise. */
2291
2292bool
2293strub_splittable_p (cgraph_node *node)
2294{
2295 switch (get_strub_mode (node))
2296 {
2297 case STRUB_WRAPPED:
2298 case STRUB_AT_CALLS:
2299 case STRUB_AT_CALLS_OPT:
2300 case STRUB_INLINABLE:
2301 case STRUB_INTERNAL:
2302 case STRUB_WRAPPER:
2303 return false;
2304
2305 case STRUB_CALLABLE:
2306 case STRUB_DISABLED:
2307 break;
2308
2309 default:
2310 gcc_unreachable ();
2311 }
2312
2313 return true;
2314}
2315
2316/* Return the PARM_DECL of the incoming watermark pointer, if there is one. */
2317
2318tree
2319strub_watermark_parm (tree fndecl)
2320{
2321 switch (get_strub_mode_from_fndecl (fndecl))
2322 {
2323 case STRUB_WRAPPED:
2324 case STRUB_AT_CALLS:
2325 case STRUB_AT_CALLS_OPT:
2326 break;
2327
2328 case STRUB_INTERNAL:
2329 case STRUB_WRAPPER:
2330 case STRUB_CALLABLE:
2331 case STRUB_DISABLED:
2332 case STRUB_INLINABLE:
2333 return NULL_TREE;
2334
2335 default:
2336 gcc_unreachable ();
2337 }
2338
2339 for (tree parm = DECL_ARGUMENTS (fndecl); parm; parm = DECL_CHAIN (parm))
2340 /* The type (variant) compare finds the parameter even in a just-created
2341 clone, before we set its name, but the type-based compare doesn't work
2342 during builtin expansion within the lto compiler, because we'll have
2343 created a separate variant in that run. */
2344 if (TREE_TYPE (parm) == pass_ipa_strub::get_qpwmt ()
2345 || DECL_NAME (parm) == pass_ipa_strub::get_watermark_ptr ())
2346 return parm;
2347
2348 gcc_unreachable ();
2349}
2350
2351/* Adjust a STRUB_AT_CALLS function TYPE, adding a watermark pointer if it
2352 hasn't been added yet. Return the named argument count. */
2353
2354int
2355pass_ipa_strub::adjust_at_calls_type (tree type)
2356{
2357 int named_args = 0;
2358
2359 gcc_checking_assert (same_strub_mode_in_variants_p (type));
2360
2361 if (!TYPE_ARG_TYPES (type))
2362 return named_args;
2363
2364 tree *tlist = &TYPE_ARG_TYPES (type);
2365 tree qpwmptrt = get_qpwmt ();
2366 while (*tlist && TREE_VALUE (*tlist) != void_type_node)
2367 {
2368 /* The type has already been adjusted. */
2369 if (TREE_VALUE (*tlist) == qpwmptrt)
2370 return named_args;
2371 named_args++;
2372 *tlist = tree_cons (TREE_PURPOSE (*tlist),
2373 TREE_VALUE (*tlist),
2374 TREE_CHAIN (*tlist));
2375 tlist = &TREE_CHAIN (*tlist);
2376 }
2377
2378 /* Add the new argument after all named arguments, so as to not mess with
2379 attributes that reference parameters. */
2380 *tlist = tree_cons (NULL_TREE, get_qpwmt (), *tlist);
2381
2382#if ATTR_FNSPEC_DECONST_WATERMARK
2383 if (!type_already_adjusted)
2384 {
2385 int flags = flags_from_decl_or_type (type);
2386 tree fnspec = lookup_attribute ("fn spec", type);
2387
2388 if ((flags & (ECF_CONST | ECF_PURE | ECF_NOVOPS)) || fnspec)
2389 {
2390 size_t xargs = 1;
2391 size_t curlen = 0, tgtlen = 2 + 2 * (named_args + xargs);
2392 auto_vec<char> nspecv (tgtlen);
2393 char *nspec = &nspecv[0]; /* It will *not* be NUL-terminated! */
2394 if (fnspec)
2395 {
2396 tree fnspecstr = TREE_VALUE (TREE_VALUE (fnspec));
2397 curlen = TREE_STRING_LENGTH (fnspecstr);
2398 memcpy (nspec, TREE_STRING_POINTER (fnspecstr), curlen);
2399 }
2400 if (!curlen)
2401 {
2402 nspec[curlen++] = '.';
2403 nspec[curlen++] = ((flags & ECF_CONST)
2404 ? 'c'
2405 : (flags & ECF_PURE)
2406 ? 'p'
2407 : ' ');
2408 }
2409 while (curlen < tgtlen - 2 * xargs)
2410 {
2411 nspec[curlen++] = '.';
2412 nspec[curlen++] = ' ';
2413 }
2414 nspec[curlen++] = 'W';
2415 nspec[curlen++] = 't';
2416
2417 /* The type has already been copied, if needed, before adding
2418 parameters. */
2419 TYPE_ATTRIBUTES (type)
2420 = tree_cons (get_identifier ("fn spec"),
2421 build_tree_list (NULL_TREE,
2422 build_string (tgtlen, nspec)),
2423 TYPE_ATTRIBUTES (type));
2424 }
2425 }
2426#endif
2427
2428 return named_args;
2429}
2430
2431/* Adjust a call to an at-calls call target. Create a watermark local variable
2432 if needed, initialize it before, pass it to the callee according to the
2433 modified at-calls interface, and release the callee's stack space after the
2434 call, if not deferred. If the call is const or pure, arrange for the
2435 watermark to not be assumed unused or unchanged. */
2436
2437void
2438pass_ipa_strub::adjust_at_calls_call (cgraph_edge *e, int named_args,
2439 tree callee_fntype)
2440{
2441 gcc_checking_assert (e->call_stmt);
2442 gcall *ocall = e->call_stmt;
2443 gimple_stmt_iterator gsi = gsi_for_stmt (ocall);
2444
2445 /* Make sure we haven't modified this call yet. */
2446 gcc_checking_assert (!(int (gimple_call_num_args (ocall)) > named_args
2447 && (TREE_TYPE (gimple_call_arg (ocall, named_args))
2448 == get_pwmt ())));
2449
2450 tree tsup;
2451 if (!(tsup = gimple_call_fndecl (gs: ocall)))
2452 tsup = TREE_TYPE (TREE_TYPE (gimple_call_fn (ocall)));
2453 if (!strub_target_support_p (t: tsup, report: true, loc: gimple_location (g: ocall)))
2454 return;
2455
2456 /* If we're already within a strub context, pass on the incoming watermark
2457 pointer, and omit the enter and leave calls around the modified call, as an
2458 optimization, or as a means to satisfy a tail-call requirement. */
2459 tree swmp = ((opt_for_fn (e->caller->decl, optimize_size)
2460 || opt_for_fn (e->caller->decl, optimize) > 2
2461 || gimple_call_must_tail_p (s: ocall)
2462 || (opt_for_fn (e->caller->decl, optimize) == 2
2463 && gimple_call_tail_p (s: ocall)))
2464 ? strub_watermark_parm (fndecl: e->caller->decl)
2465 : NULL_TREE);
2466 bool omit_own_watermark = swmp;
2467 tree swm = NULL_TREE;
2468 if (!omit_own_watermark)
2469 {
2470 swm = create_tmp_var (get_wmt (), ".strub.watermark");
2471 TREE_ADDRESSABLE (swm) = true;
2472 swmp = build1 (ADDR_EXPR, get_pwmt (), swm);
2473
2474 /* Initialize the watermark before the call. */
2475 tree enter = get_enter ();
2476 gcall *stptr = gimple_build_call (enter, 1,
2477 unshare_expr (swmp));
2478 if (gimple_has_location (g: ocall))
2479 gimple_set_location (g: stptr, location: gimple_location (g: ocall));
2480 gsi_insert_before (&gsi, stptr, GSI_SAME_STMT);
2481 e->caller->create_edge (callee: cgraph_node::get_create (enter),
2482 call_stmt: stptr, count: gsi_bb (i: gsi)->count, cloning_p: false);
2483 }
2484
2485
2486 /* Replace the call with one that passes the swmp argument first. */
2487 gcall *wrcall;
2488 { gcall *stmt = ocall;
2489 // Mostly copied from gimple_call_copy_skip_args.
2490 int i = 0;
2491 int nargs = gimple_call_num_args (gs: stmt);
2492 auto_vec<tree> vargs (MAX (nargs, named_args) + 1);
2493 gcall *new_stmt;
2494
2495 /* pr71109.c calls a prototypeless function, then defines it with
2496 additional arguments. It's ill-formed, but after it's inlined,
2497 it somehow works out. */
2498 for (; i < named_args && i < nargs; i++)
2499 vargs.quick_push (obj: gimple_call_arg (gs: stmt, index: i));
2500 for (; i < named_args; i++)
2501 vargs.quick_push (null_pointer_node);
2502
2503 vargs.quick_push (obj: unshare_expr (swmp));
2504
2505 for (; i < nargs; i++)
2506 vargs.quick_push (obj: gimple_call_arg (gs: stmt, index: i));
2507
2508 if (gimple_call_internal_p (gs: stmt))
2509 gcc_unreachable ();
2510 else
2511 new_stmt = gimple_build_call_vec (gimple_call_fn (gs: stmt), vargs);
2512 gimple_call_set_fntype (call_stmt: new_stmt, fntype: callee_fntype);
2513
2514 if (gimple_call_lhs (gs: stmt))
2515 gimple_call_set_lhs (gs: new_stmt, lhs: gimple_call_lhs (gs: stmt));
2516
2517 gimple_move_vops (new_stmt, stmt);
2518
2519 if (gimple_has_location (g: stmt))
2520 gimple_set_location (g: new_stmt, location: gimple_location (g: stmt));
2521 gimple_call_copy_flags (dest_call: new_stmt, orig_call: stmt);
2522 gimple_call_set_chain (call_stmt: new_stmt, chain: gimple_call_chain (gs: stmt));
2523
2524 gimple_set_modified (s: new_stmt, modifiedp: true);
2525
2526 wrcall = new_stmt;
2527 }
2528
2529 update_stmt (s: wrcall);
2530 gsi_replace (&gsi, wrcall, true);
2531 cgraph_edge::set_call_stmt (e, new_stmt: wrcall, update_speculative: false);
2532
2533 /* Insert the strub code after the call. */
2534 gimple_seq seq = NULL;
2535
2536#if !ATTR_FNSPEC_DECONST_WATERMARK
2537 /* If the call will be assumed to not modify or even read the
2538 watermark, make it read and modified ourselves. */
2539 if ((gimple_call_flags (wrcall)
2540 & (ECF_CONST | ECF_PURE | ECF_NOVOPS)))
2541 {
2542 if (!swm)
2543 swm = build2 (MEM_REF,
2544 TREE_TYPE (TREE_TYPE (swmp)),
2545 swmp,
2546 build_int_cst (TREE_TYPE (swmp), 0));
2547
2548 vec<tree, va_gc> *inputs = NULL;
2549 vec<tree, va_gc> *outputs = NULL;
2550 vec_safe_push (v&: outputs,
2551 obj: build_tree_list
2552 (build_tree_list
2553 (NULL_TREE, build_string (2, "=m")),
2554 unshare_expr (swm)));
2555 vec_safe_push (v&: inputs,
2556 obj: build_tree_list
2557 (build_tree_list
2558 (NULL_TREE, build_string (1, "m")),
2559 unshare_expr (swm)));
2560 gasm *forcemod = gimple_build_asm_vec ("", inputs, outputs,
2561 NULL, NULL);
2562 gimple_seq_add_stmt (&seq, forcemod);
2563
2564 /* If the call will be assumed to not even read the watermark,
2565 make sure it is already in memory before the call. */
2566 if ((gimple_call_flags (wrcall) & ECF_CONST))
2567 {
2568 vec<tree, va_gc> *inputs = NULL;
2569 vec_safe_push (v&: inputs,
2570 obj: build_tree_list
2571 (build_tree_list
2572 (NULL_TREE, build_string (1, "m")),
2573 unshare_expr (swm)));
2574 gasm *force_store = gimple_build_asm_vec ("", inputs, NULL,
2575 NULL, NULL);
2576 if (gimple_has_location (g: wrcall))
2577 gimple_set_location (g: force_store, location: gimple_location (g: wrcall));
2578 gsi_insert_before (&gsi, force_store, GSI_SAME_STMT);
2579 }
2580 }
2581#endif
2582
2583 if (!omit_own_watermark)
2584 {
2585 gcall *sleave = gimple_build_call (get_leave (), 1,
2586 unshare_expr (swmp));
2587 gimple_seq_add_stmt (&seq, sleave);
2588
2589 gassign *clobber = gimple_build_assign (swm,
2590 build_clobber
2591 (TREE_TYPE (swm)));
2592 gimple_seq_add_stmt (&seq, clobber);
2593 }
2594
2595 gsi_insert_finally_seq_after_call (gsi, seq);
2596}
2597
2598/* Adjust all at-calls calls in NODE. */
2599
2600void
2601pass_ipa_strub::adjust_at_calls_calls (cgraph_node *node)
2602{
2603 /* Adjust unknown-callee indirect calls with STRUB_AT_CALLS types within
2604 onode. */
2605 if (node->indirect_calls)
2606 {
2607 push_cfun (DECL_STRUCT_FUNCTION (node->decl));
2608 for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
2609 {
2610 gcc_checking_assert (e->indirect_unknown_callee);
2611
2612 if (!e->call_stmt)
2613 continue;
2614
2615 tree callee_fntype;
2616 enum strub_mode callee_mode
2617 = effective_strub_mode_for_call (call: e->call_stmt, typep: &callee_fntype);
2618
2619 if (callee_mode != STRUB_AT_CALLS
2620 && callee_mode != STRUB_AT_CALLS_OPT)
2621 continue;
2622
2623 int named_args = adjust_at_calls_type (type: callee_fntype);
2624
2625 adjust_at_calls_call (e, named_args, callee_fntype);
2626 }
2627 pop_cfun ();
2628 }
2629
2630 if (node->callees)
2631 {
2632 push_cfun (DECL_STRUCT_FUNCTION (node->decl));
2633 for (cgraph_edge *e = node->callees; e; e = e->next_callee)
2634 {
2635 gcc_checking_assert (!e->indirect_unknown_callee);
2636
2637 if (!e->call_stmt)
2638 continue;
2639
2640 tree callee_fntype;
2641 enum strub_mode callee_mode
2642 = effective_strub_mode_for_call (call: e->call_stmt, typep: &callee_fntype);
2643
2644 if (callee_mode != STRUB_AT_CALLS
2645 && callee_mode != STRUB_AT_CALLS_OPT)
2646 continue;
2647
2648 int named_args = adjust_at_calls_type (type: callee_fntype);
2649
2650 adjust_at_calls_call (e, named_args, callee_fntype);
2651 }
2652 pop_cfun ();
2653 }
2654}
2655
2656/* The strubm (strub mode) pass computes a strub mode for each function in the
2657 call graph, and checks, before any inlining, that strub callability
2658 requirements in effect are satisfied. */
2659
2660unsigned int
2661pass_ipa_strub_mode::execute (function *)
2662{
2663 last_cgraph_order = 0;
2664 ipa_strub_set_mode_for_new_functions ();
2665
2666 /* Verify before any inlining or other transformations. */
2667 verify_strub ();
2668
2669 return 0;
2670}
2671
2672/* Create a strub mode pass. */
2673
2674simple_ipa_opt_pass *
2675make_pass_ipa_strub_mode (gcc::context *ctxt)
2676{
2677 return new pass_ipa_strub_mode (ctxt);
2678}
2679
2680/* The strub pass proper adjusts types, signatures, and at-calls calls, and
2681 splits internal-strub functions. */
2682
2683unsigned int
2684pass_ipa_strub::execute (function *)
2685{
2686 cgraph_node *onode;
2687
2688 ipa_strub_set_mode_for_new_functions ();
2689
2690 /* First, adjust the signature of at-calls functions. We adjust types of
2691 at-calls functions first, so that we don't modify types in place unless
2692 strub is explicitly requested. */
2693 FOR_EACH_FUNCTION (onode)
2694 {
2695 enum strub_mode mode = get_strub_mode (node: onode);
2696
2697 if (mode == STRUB_AT_CALLS
2698 || mode == STRUB_AT_CALLS_OPT)
2699 {
2700 /* Create a type variant if strubbing was not explicitly requested in
2701 the function type. */
2702 if (get_strub_mode_from_type (TREE_TYPE (onode->decl)) != mode)
2703 distinctify_node_type (node: onode);
2704
2705 int named_args = adjust_at_calls_type (TREE_TYPE (onode->decl));
2706
2707 /* An external function explicitly declared with strub won't have a
2708 body. Even with implicit at-calls strub, a function may have had its
2709 body removed after we selected the mode, and then we have nothing
2710 further to do. */
2711 if (!onode->has_gimple_body_p ())
2712 continue;
2713
2714 tree *pargs = &DECL_ARGUMENTS (onode->decl);
2715
2716 /* A noninterposable_alias reuses the same parm decl chain, don't add
2717 the parm twice. */
2718 bool aliased_parms = (onode->alias && *pargs
2719 && DECL_CONTEXT (*pargs) != onode->decl);
2720
2721 if (aliased_parms)
2722 continue;
2723
2724 for (int i = 0; i < named_args; i++)
2725 pargs = &DECL_CHAIN (*pargs);
2726
2727 tree wmptr = build_decl (DECL_SOURCE_LOCATION (onode->decl),
2728 PARM_DECL,
2729 get_watermark_ptr (),
2730 get_qpwmt ());
2731 DECL_ARTIFICIAL (wmptr) = 1;
2732 DECL_ARG_TYPE (wmptr) = get_qpwmt ();
2733 DECL_CONTEXT (wmptr) = onode->decl;
2734 TREE_USED (wmptr) = 1;
2735 DECL_CHAIN (wmptr) = *pargs;
2736 *pargs = wmptr;
2737
2738 if (onode->alias)
2739 continue;
2740
2741 cgraph_node *nnode = onode;
2742 push_cfun (DECL_STRUCT_FUNCTION (nnode->decl));
2743
2744 {
2745 edge e = single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun));
2746 gimple_seq seq = call_update_watermark (wmptr, node: nnode, count: e->src->count);
2747 gsi_insert_seq_on_edge_immediate (e, seq);
2748 }
2749
2750 if (DECL_STRUCT_FUNCTION (nnode->decl)->calls_alloca)
2751 {
2752 basic_block bb;
2753 FOR_EACH_BB_FN (bb, cfun)
2754 for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
2755 !gsi_end_p (i: gsi); gsi_next (i: &gsi))
2756 {
2757 gimple *stmt = gsi_stmt (i: gsi);
2758
2759 gcall *call = dyn_cast <gcall *> (p: stmt);
2760
2761 if (!call)
2762 continue;
2763
2764 if (gimple_alloca_call_p (call))
2765 {
2766 /* Capture stack growth. */
2767 gimple_seq seq = call_update_watermark (wmptr, NULL,
2768 count: gsi_bb (i: gsi)
2769 ->count);
2770 gsi_insert_finally_seq_after_call (gsi, seq);
2771 }
2772 }
2773 }
2774
2775 pop_cfun ();
2776 }
2777 }
2778
2779 FOR_EACH_FUNCTION (onode)
2780 {
2781 if (!onode->has_gimple_body_p ())
2782 continue;
2783
2784 enum strub_mode mode = get_strub_mode (node: onode);
2785
2786 if (mode != STRUB_INTERNAL)
2787 {
2788 adjust_at_calls_calls (node: onode);
2789 continue;
2790 }
2791
2792 bool is_stdarg = calls_builtin_va_start_p (node: onode);;
2793 bool apply_args = calls_builtin_apply_args_p (node: onode);
2794
2795 vec<ipa_adjusted_param, va_gc> *nparms = NULL;
2796 unsigned j = 0;
2797 {
2798 // The following loop copied from ipa-split.c:split_function.
2799 for (tree parm = DECL_ARGUMENTS (onode->decl);
2800 parm; parm = DECL_CHAIN (parm), j++)
2801 {
2802 ipa_adjusted_param adj = {};
2803 adj.op = IPA_PARAM_OP_COPY;
2804 adj.base_index = j;
2805 adj.prev_clone_index = j;
2806 vec_safe_push (v&: nparms, obj: adj);
2807 }
2808
2809 if (apply_args)
2810 {
2811 ipa_adjusted_param aaadj = {};
2812 aaadj.op = IPA_PARAM_OP_NEW;
2813 aaadj.type = get_qptr ();
2814 vec_safe_push (v&: nparms, obj: aaadj);
2815 }
2816
2817 if (is_stdarg)
2818 {
2819 ipa_adjusted_param vladj = {};
2820 vladj.op = IPA_PARAM_OP_NEW;
2821 vladj.type = get_qpvalst ();
2822 vec_safe_push (v&: nparms, obj: vladj);
2823 }
2824
2825 ipa_adjusted_param wmadj = {};
2826 wmadj.op = IPA_PARAM_OP_NEW;
2827 wmadj.type = get_qpwmt ();
2828 vec_safe_push (v&: nparms, obj: wmadj);
2829 }
2830 ipa_param_adjustments adj (nparms, -1, false);
2831
2832 cgraph_node *nnode = onode->create_version_clone_with_body
2833 (redirect_callers: auto_vec<cgraph_edge *> (0),
2834 NULL, param_adjustments: &adj, NULL, NULL, clone_name: "strub", NULL);
2835
2836 if (!nnode)
2837 {
2838 error_at (DECL_SOURCE_LOCATION (onode->decl),
2839 "failed to split %qD for %<strub%>",
2840 onode->decl);
2841 continue;
2842 }
2843
2844 onode->split_part = true;
2845 if (onode->calls_comdat_local)
2846 nnode->add_to_same_comdat_group (old_node: onode);
2847
2848 set_strub_mode_to (node: onode, mode: STRUB_WRAPPER);
2849 set_strub_mode_to (node: nnode, mode: STRUB_WRAPPED);
2850
2851 adjust_at_calls_calls (node: nnode);
2852
2853 /* Decide which of the wrapped function's parms we want to turn into
2854 references to the argument passed to the wrapper. In general, we want to
2855 copy small arguments, and avoid copying large ones. Variable-sized array
2856 lengths given by other arguments, as in 20020210-1.c, would lead to
2857 problems if passed by value, after resetting the original function and
2858 dropping the length computation; passing them by reference works.
2859 DECL_BY_REFERENCE is *not* a substitute for this: it involves copying
2860 anyway, but performed at the caller. */
2861 indirect_parms_t indirect_nparms (3, false);
2862 unsigned adjust_ftype = 0;
2863 unsigned named_args = 0;
2864 for (tree parm = DECL_ARGUMENTS (onode->decl),
2865 nparm = DECL_ARGUMENTS (nnode->decl),
2866 nparmt = TYPE_ARG_TYPES (TREE_TYPE (nnode->decl));
2867 parm;
2868 named_args++,
2869 parm = DECL_CHAIN (parm),
2870 nparm = DECL_CHAIN (nparm),
2871 nparmt = nparmt ? TREE_CHAIN (nparmt) : NULL_TREE)
2872 if (TREE_THIS_VOLATILE (parm)
2873 || !(0 /* DECL_BY_REFERENCE (narg) */
2874 || is_gimple_reg_type (TREE_TYPE (nparm))
2875 || VECTOR_TYPE_P (TREE_TYPE (nparm))
2876 || TREE_CODE (TREE_TYPE (nparm)) == COMPLEX_TYPE
2877 || (tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (nparm)))
2878 && (tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (nparm)))
2879 <= 4 * UNITS_PER_WORD))))
2880 {
2881 /* No point in indirecting pointer types. Presumably they
2882 won't ever pass the size-based test above, but check the
2883 assumption here, because getting this wrong would mess
2884 with attribute access and possibly others. We deal with
2885 fn spec below. */
2886 gcc_checking_assert (!POINTER_TYPE_P (TREE_TYPE (nparm)));
2887
2888 indirect_nparms.add (k: nparm);
2889
2890 /* ??? Is there any case in which it is not safe to suggest the parms
2891 turned indirect don't alias anything else? They are distinct,
2892 unaliased memory in the wrapper, and the wrapped can't possibly
2893 take pointers into them because none of the pointers passed to the
2894 wrapper can alias other incoming parameters passed by value, even
2895 if with transparent reference, and the wrapper doesn't take any
2896 extra parms that could point into wrapper's parms. So we can
2897 probably drop the TREE_ADDRESSABLE and keep the TRUE. */
2898 tree ref_type = build_ref_type_for (parm: nparm);
2899
2900 if (TREE_THIS_VOLATILE (nparm)
2901 && TYPE_VOLATILE (TREE_TYPE (nparm))
2902 && !TYPE_VOLATILE (ref_type))
2903 TREE_SIDE_EFFECTS (nparm) = TREE_THIS_VOLATILE (nparm) = 0;
2904 DECL_ARG_TYPE (nparm) = TREE_TYPE (nparm) = ref_type;
2905 relayout_decl (nparm);
2906 TREE_ADDRESSABLE (nparm) = 0;
2907 DECL_BY_REFERENCE (nparm) = 0;
2908 DECL_NOT_GIMPLE_REG_P (nparm) = 0;
2909 /* ??? This avoids mismatches in debug info bind stmts in
2910 e.g. a-chahan . */
2911 DECL_ABSTRACT_ORIGIN (nparm) = NULL;
2912
2913 if (nparmt)
2914 adjust_ftype++;
2915 }
2916
2917 /* Also adjust the wrapped function type, if needed. */
2918 if (adjust_ftype)
2919 {
2920 tree nftype = TREE_TYPE (nnode->decl);
2921
2922 /* We always add at least one argument at the end of the signature, when
2923 cloning the function, so we don't expect to need to duplicate the
2924 type here. */
2925 gcc_checking_assert (TYPE_ARG_TYPES (nftype)
2926 != TYPE_ARG_TYPES (TREE_TYPE (onode->decl)));
2927
2928 /* Check that fnspec still works for the modified function signature,
2929 and drop it otherwise. */
2930 bool drop_fnspec = false;
2931 tree fnspec = lookup_attribute (attr_name: "fn spec", TYPE_ATTRIBUTES (nftype));
2932 attr_fnspec spec = fnspec ? attr_fnspec (fnspec) : attr_fnspec ("");
2933
2934 unsigned retcopy;
2935 if (!(fnspec && spec.returns_arg (arg_no: &retcopy)))
2936 retcopy = (unsigned) -1;
2937
2938 unsigned i = 0;
2939 for (tree nparm = DECL_ARGUMENTS (nnode->decl),
2940 nparmt = TYPE_ARG_TYPES (nftype);
2941 adjust_ftype > 0;
2942 i++, nparm = DECL_CHAIN (nparm), nparmt = TREE_CHAIN (nparmt))
2943 if (indirect_nparms.contains (k: nparm))
2944 {
2945 TREE_VALUE (nparmt) = TREE_TYPE (nparm);
2946 adjust_ftype--;
2947
2948 if (fnspec && !drop_fnspec)
2949 {
2950 if (i == retcopy)
2951 drop_fnspec = true;
2952 else if (spec.arg_specified_p (i))
2953 {
2954 /* Properties that apply to pointers only must not be
2955 present, because we don't make pointers further
2956 indirect. */
2957 gcc_checking_assert
2958 (!spec.arg_max_access_size_given_by_arg_p (i, NULL));
2959 gcc_checking_assert (!spec.arg_copied_to_arg_p (i, NULL));
2960
2961 /* Any claim of direct access only is invalidated by
2962 adding an indirection level. */
2963 if (spec.arg_direct_p (i))
2964 drop_fnspec = true;
2965
2966 /* If there's a claim the argument is not read from, the
2967 added indirection invalidates it: if the argument is
2968 used at all, then the pointer will necessarily be
2969 read. */
2970 if (!spec.arg_maybe_read_p (i)
2971 && spec.arg_used_p (i))
2972 drop_fnspec = true;
2973 }
2974 }
2975 }
2976
2977 /* ??? Maybe we could adjust it instead. Note we don't need
2978 to mess with attribute access: pointer-typed parameters are
2979 not modified, so they can remain unchanged. */
2980 if (drop_fnspec)
2981 remove_named_attribute_unsharing (name: "fn spec",
2982 attrs: &TYPE_ATTRIBUTES (nftype));
2983
2984 TREE_TYPE (nnode->decl) = nftype;
2985 }
2986
2987#if ATTR_FNSPEC_DECONST_WATERMARK
2988 {
2989 int flags = flags_from_decl_or_type (nnode->decl);
2990 tree fnspec = lookup_attribute ("fn spec", TREE_TYPE (nnode->decl));
2991
2992 if ((flags & (ECF_CONST | ECF_PURE | ECF_NOVOPS)) || fnspec)
2993 {
2994 size_t xargs = 1 + int (is_stdarg) + int (apply_args);
2995 size_t curlen = 0, tgtlen = 2 + 2 * (named_args + xargs);
2996 auto_vec<char> nspecv (tgtlen);
2997 char *nspec = &nspecv[0]; /* It will *not* be NUL-terminated! */
2998 bool no_writes_p = true;
2999 if (fnspec)
3000 {
3001 tree fnspecstr = TREE_VALUE (TREE_VALUE (fnspec));
3002 curlen = TREE_STRING_LENGTH (fnspecstr);
3003 memcpy (nspec, TREE_STRING_POINTER (fnspecstr), curlen);
3004 if (!(flags & (ECF_CONST | ECF_PURE | ECF_NOVOPS))
3005 && curlen >= 2
3006 && nspec[1] != 'c' && nspec[1] != 'C'
3007 && nspec[1] != 'p' && nspec[1] != 'P')
3008 no_writes_p = false;
3009 }
3010 if (!curlen)
3011 {
3012 nspec[curlen++] = '.';
3013 nspec[curlen++] = ((flags & ECF_CONST)
3014 ? 'c'
3015 : (flags & ECF_PURE)
3016 ? 'p'
3017 : ' ');
3018 }
3019 while (curlen < tgtlen - 2 * xargs)
3020 {
3021 nspec[curlen++] = '.';
3022 nspec[curlen++] = ' ';
3023 }
3024
3025 /* These extra args are unlikely to be present in const or pure
3026 functions. It's conceivable that a function that takes variable
3027 arguments, or that passes its arguments on to another function,
3028 could be const or pure, but it would not modify the arguments, and,
3029 being pure or const, it couldn't possibly modify or even access
3030 memory referenced by them. But it can read from these internal
3031 data structures created by the wrapper, and from any
3032 argument-passing memory referenced by them, so we denote the
3033 possibility of reading from multiple levels of indirection, but
3034 only of reading because const/pure. */
3035 if (apply_args)
3036 {
3037 nspec[curlen++] = 'r';
3038 nspec[curlen++] = ' ';
3039 }
3040 if (is_stdarg)
3041 {
3042 nspec[curlen++] = (no_writes_p ? 'r' : '.');
3043 nspec[curlen++] = (no_writes_p ? 't' : ' ');
3044 }
3045
3046 nspec[curlen++] = 'W';
3047 nspec[curlen++] = 't';
3048
3049 /* The type has already been copied before adding parameters. */
3050 gcc_checking_assert (TYPE_ARG_TYPES (TREE_TYPE (nnode->decl))
3051 != TYPE_ARG_TYPES (TREE_TYPE (onode->decl)));
3052 TYPE_ATTRIBUTES (TREE_TYPE (nnode->decl))
3053 = tree_cons (get_identifier ("fn spec"),
3054 build_tree_list (NULL_TREE,
3055 build_string (tgtlen, nspec)),
3056 TYPE_ATTRIBUTES (TREE_TYPE (nnode->decl)));
3057 }
3058 }
3059#endif
3060
3061 {
3062 tree decl = onode->decl;
3063 cgraph_node *target = nnode;
3064
3065 { // copied from create_wrapper
3066
3067 /* Preserve DECL_RESULT so we get right by reference flag. */
3068 tree decl_result = DECL_RESULT (decl);
3069
3070 /* Remove the function's body but keep arguments to be reused
3071 for thunk. */
3072 onode->release_body (keep_arguments: true);
3073 onode->reset (/* unlike create_wrapper: preserve_comdat_group = */preserve_comdat_group: true);
3074
3075 DECL_UNINLINABLE (decl) = false;
3076 DECL_RESULT (decl) = decl_result;
3077 DECL_INITIAL (decl) = NULL;
3078 allocate_struct_function (decl, false);
3079 set_cfun (NULL);
3080
3081 /* Turn alias into thunk and expand it into GIMPLE representation. */
3082 onode->definition = true;
3083
3084 thunk_info::get_create (node: onode);
3085 onode->thunk = true;
3086 onode->create_edge (callee: target, NULL, count: onode->count);
3087 onode->callees->can_throw_external = !TREE_NOTHROW (target->decl);
3088
3089 tree arguments = DECL_ARGUMENTS (decl);
3090
3091 while (arguments)
3092 {
3093 TREE_ADDRESSABLE (arguments) = false;
3094 arguments = TREE_CHAIN (arguments);
3095 }
3096
3097 {
3098 tree alias = onode->callees->callee->decl;
3099 tree thunk_fndecl = decl;
3100 tree a;
3101
3102 int nxargs = 1 + is_stdarg + apply_args;
3103
3104 { // Simplified from expand_thunk.
3105 tree restype;
3106 basic_block bb, then_bb, else_bb, return_bb;
3107 gimple_stmt_iterator bsi;
3108 int nargs = 0;
3109 tree arg;
3110 int i;
3111 tree resdecl;
3112 tree restmp = NULL;
3113
3114 gcall *call;
3115 greturn *ret;
3116 bool alias_is_noreturn = TREE_THIS_VOLATILE (alias);
3117
3118 a = DECL_ARGUMENTS (thunk_fndecl);
3119
3120 current_function_decl = thunk_fndecl;
3121
3122 /* Ensure thunks are emitted in their correct sections. */
3123 resolve_unique_section (thunk_fndecl, 0,
3124 flag_function_sections);
3125
3126 bitmap_obstack_initialize (NULL);
3127
3128 /* Build the return declaration for the function. */
3129 restype = TREE_TYPE (TREE_TYPE (thunk_fndecl));
3130 if (DECL_RESULT (thunk_fndecl) == NULL_TREE)
3131 {
3132 resdecl = build_decl (input_location, RESULT_DECL, 0, restype);
3133 DECL_ARTIFICIAL (resdecl) = 1;
3134 DECL_IGNORED_P (resdecl) = 1;
3135 DECL_CONTEXT (resdecl) = thunk_fndecl;
3136 DECL_RESULT (thunk_fndecl) = resdecl;
3137 }
3138 else
3139 resdecl = DECL_RESULT (thunk_fndecl);
3140
3141 profile_count cfg_count = onode->count;
3142 if (!cfg_count.initialized_p ())
3143 cfg_count = profile_count::from_gcov_type (BB_FREQ_MAX).guessed_local ();
3144
3145 bb = then_bb = else_bb = return_bb
3146 = init_lowered_empty_function (thunk_fndecl, true, cfg_count);
3147
3148 bsi = gsi_start_bb (bb);
3149
3150 /* Build call to the function being thunked. */
3151 if (!VOID_TYPE_P (restype)
3152 && (!alias_is_noreturn
3153 || TREE_ADDRESSABLE (restype)
3154 || TREE_CODE (TYPE_SIZE_UNIT (restype)) != INTEGER_CST))
3155 {
3156 if (DECL_BY_REFERENCE (resdecl))
3157 {
3158 restmp = gimple_fold_indirect_ref (resdecl);
3159 if (!restmp)
3160 restmp = build2 (MEM_REF,
3161 TREE_TYPE (TREE_TYPE (resdecl)),
3162 resdecl,
3163 build_int_cst (TREE_TYPE (resdecl), 0));
3164 }
3165 else if (aggregate_value_p (resdecl, TREE_TYPE (thunk_fndecl)))
3166 {
3167 restmp = resdecl;
3168
3169 if (VAR_P (restmp))
3170 {
3171 add_local_decl (cfun, d: restmp);
3172 BLOCK_VARS (DECL_INITIAL (current_function_decl))
3173 = restmp;
3174 }
3175 }
3176 else
3177 restmp = create_tmp_reg (restype, "retval");
3178 }
3179
3180 for (arg = a; arg; arg = DECL_CHAIN (arg))
3181 nargs++;
3182 auto_vec<tree> vargs (nargs + nxargs);
3183 i = 0;
3184 arg = a;
3185
3186 if (nargs)
3187 for (tree nparm = DECL_ARGUMENTS (nnode->decl);
3188 i < nargs;
3189 i++, arg = DECL_CHAIN (arg), nparm = DECL_CHAIN (nparm))
3190 {
3191 tree save_arg = arg;
3192
3193 /* Arrange to pass indirectly the parms, if we decided to do
3194 so, and revert its type in the wrapper. */
3195 if (indirect_nparms.contains (k: nparm))
3196 {
3197 tree ref_type = TREE_TYPE (nparm);
3198 TREE_ADDRESSABLE (arg) = true;
3199 arg = build1 (ADDR_EXPR, ref_type, arg);
3200 }
3201 else if (!TREE_THIS_VOLATILE (arg))
3202 DECL_NOT_GIMPLE_REG_P (arg) = 0;
3203
3204 /* Convert the argument back to the type used by the calling
3205 conventions, e.g. a non-prototyped float type is passed as
3206 double, as in 930603-1.c, and needs to be converted back to
3207 double to be passed on unchanged to the wrapped
3208 function. */
3209 if (TREE_TYPE (nparm) != DECL_ARG_TYPE (nparm))
3210 {
3211 tree tmp = arg;
3212 /* If ARG is e.g. volatile, we must copy and
3213 convert in separate statements. */
3214 if (!is_gimple_val (arg))
3215 {
3216 tmp = create_tmp_reg (TYPE_MAIN_VARIANT
3217 (TREE_TYPE (arg)), "arg");
3218 gimple *stmt = gimple_build_assign (tmp, arg);
3219 gsi_insert_after (&bsi, stmt, GSI_NEW_STMT);
3220 }
3221 arg = fold_convert (DECL_ARG_TYPE (nparm), tmp);
3222 }
3223
3224 if (!is_gimple_val (arg))
3225 {
3226 tree tmp = create_tmp_reg (TYPE_MAIN_VARIANT
3227 (TREE_TYPE (arg)), "arg");
3228 gimple *stmt = gimple_build_assign (tmp, arg);
3229 gsi_insert_after (&bsi, stmt, GSI_NEW_STMT);
3230 arg = tmp;
3231 }
3232 vargs.quick_push (obj: arg);
3233 arg = save_arg;
3234 }
3235 /* These strub arguments are adjusted later. */
3236 if (apply_args)
3237 vargs.quick_push (null_pointer_node);
3238 if (is_stdarg)
3239 vargs.quick_push (null_pointer_node);
3240 vargs.quick_push (null_pointer_node);
3241 call = gimple_build_call_vec (build_fold_addr_expr_loc (0, alias),
3242 vargs);
3243 onode->callees->call_stmt = call;
3244 // gimple_call_set_from_thunk (call, true);
3245 if (DECL_STATIC_CHAIN (alias))
3246 {
3247 tree p = DECL_STRUCT_FUNCTION (alias)->static_chain_decl;
3248 tree type = TREE_TYPE (p);
3249 tree decl = build_decl (DECL_SOURCE_LOCATION (thunk_fndecl),
3250 PARM_DECL, create_tmp_var_name ("CHAIN"),
3251 type);
3252 DECL_ARTIFICIAL (decl) = 1;
3253 DECL_IGNORED_P (decl) = 1;
3254 TREE_USED (decl) = 1;
3255 DECL_CONTEXT (decl) = thunk_fndecl;
3256 DECL_ARG_TYPE (decl) = type;
3257 TREE_READONLY (decl) = 1;
3258
3259 struct function *sf = DECL_STRUCT_FUNCTION (thunk_fndecl);
3260 sf->static_chain_decl = decl;
3261
3262 gimple_call_set_chain (call_stmt: call, chain: decl);
3263 }
3264
3265 /* Return slot optimization is always possible and in fact required to
3266 return values with DECL_BY_REFERENCE. */
3267 if (aggregate_value_p (resdecl, TREE_TYPE (thunk_fndecl))
3268 && (!is_gimple_reg_type (TREE_TYPE (resdecl))
3269 || DECL_BY_REFERENCE (resdecl)))
3270 gimple_call_set_return_slot_opt (s: call, return_slot_opt_p: true);
3271
3272 if (restmp)
3273 {
3274 gimple_call_set_lhs (gs: call, lhs: restmp);
3275 gcc_assert (useless_type_conversion_p (TREE_TYPE (restmp),
3276 TREE_TYPE (TREE_TYPE (alias))));
3277 }
3278 gsi_insert_after (&bsi, call, GSI_NEW_STMT);
3279 if (!alias_is_noreturn)
3280 {
3281 /* Build return value. */
3282 if (!DECL_BY_REFERENCE (resdecl))
3283 ret = gimple_build_return (restmp);
3284 else
3285 ret = gimple_build_return (resdecl);
3286
3287 gsi_insert_after (&bsi, ret, GSI_NEW_STMT);
3288 }
3289 else
3290 {
3291 remove_edge (single_succ_edge (bb));
3292 }
3293
3294 cfun->gimple_df->in_ssa_p = true;
3295 update_max_bb_count ();
3296 profile_status_for_fn (cfun)
3297 = cfg_count.initialized_p () && cfg_count.ipa_p ()
3298 ? PROFILE_READ : PROFILE_GUESSED;
3299 /* FIXME: C++ FE should stop setting TREE_ASM_WRITTEN on thunks. */
3300 // TREE_ASM_WRITTEN (thunk_fndecl) = false;
3301 delete_unreachable_blocks ();
3302 update_ssa (TODO_update_ssa);
3303 checking_verify_flow_info ();
3304 free_dominance_info (CDI_DOMINATORS);
3305
3306 /* Since we want to emit the thunk, we explicitly mark its name as
3307 referenced. */
3308 onode->thunk = false;
3309 onode->lowered = true;
3310 bitmap_obstack_release (NULL);
3311 }
3312 current_function_decl = NULL;
3313 set_cfun (NULL);
3314 }
3315
3316 thunk_info::remove (node: onode);
3317
3318 // some more of create_wrapper at the end of the next block.
3319 }
3320 }
3321
3322 {
3323 tree aaval = NULL_TREE;
3324 tree vaptr = NULL_TREE;
3325 tree wmptr = NULL_TREE;
3326 for (tree arg = DECL_ARGUMENTS (nnode->decl); arg; arg = DECL_CHAIN (arg))
3327 {
3328 aaval = vaptr;
3329 vaptr = wmptr;
3330 wmptr = arg;
3331 }
3332
3333 if (!apply_args)
3334 aaval = NULL_TREE;
3335 /* The trailing args are [apply_args], [va_list_ptr], and
3336 watermark. If we don't have a va_list_ptr, the penultimate
3337 argument is apply_args.
3338 */
3339 else if (!is_stdarg)
3340 aaval = vaptr;
3341
3342 if (!is_stdarg)
3343 vaptr = NULL_TREE;
3344
3345 DECL_NAME (wmptr) = get_watermark_ptr ();
3346 DECL_ARTIFICIAL (wmptr) = 1;
3347 DECL_IGNORED_P (wmptr) = 1;
3348 TREE_USED (wmptr) = 1;
3349
3350 if (is_stdarg)
3351 {
3352 DECL_NAME (vaptr) = get_va_list_ptr ();
3353 DECL_ARTIFICIAL (vaptr) = 1;
3354 DECL_IGNORED_P (vaptr) = 1;
3355 TREE_USED (vaptr) = 1;
3356 }
3357
3358 if (apply_args)
3359 {
3360 DECL_NAME (aaval) = get_apply_args ();
3361 DECL_ARTIFICIAL (aaval) = 1;
3362 DECL_IGNORED_P (aaval) = 1;
3363 TREE_USED (aaval) = 1;
3364 }
3365
3366 push_cfun (DECL_STRUCT_FUNCTION (nnode->decl));
3367
3368 {
3369 edge e = single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun));
3370 gimple_seq seq = call_update_watermark (wmptr, node: nnode, count: e->src->count);
3371 gsi_insert_seq_on_edge_immediate (e, seq);
3372 }
3373
3374 bool any_indirect = !indirect_nparms.is_empty ();
3375
3376 if (any_indirect)
3377 {
3378 basic_block bb;
3379 bool needs_commit = false;
3380 FOR_EACH_BB_FN (bb, cfun)
3381 {
3382 for (gphi_iterator gsi = gsi_start_nonvirtual_phis (bb);
3383 !gsi_end_p (i: gsi);
3384 gsi_next_nonvirtual_phi (i: &gsi))
3385 {
3386 gphi *stmt = gsi.phi ();
3387
3388 walk_stmt_info wi = {};
3389 wi.info = &indirect_nparms;
3390 walk_gimple_op (stmt, walk_make_indirect, &wi);
3391 if (wi.changed && !is_gimple_debug (gs: gsi_stmt (i: gsi)))
3392 if (walk_regimplify_phi (stmt))
3393 needs_commit = true;
3394 }
3395
3396 for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
3397 !gsi_end_p (i: gsi); gsi_next (i: &gsi))
3398 {
3399 gimple *stmt = gsi_stmt (i: gsi);
3400
3401 walk_stmt_info wi = {};
3402 wi.info = &indirect_nparms;
3403 walk_gimple_op (stmt, walk_make_indirect, &wi);
3404 if (wi.changed)
3405 {
3406 if (!is_gimple_debug (gs: stmt))
3407 {
3408 wi.info = &gsi;
3409 walk_gimple_op (stmt, walk_regimplify_addr_expr,
3410 &wi);
3411 }
3412 update_stmt (s: stmt);
3413 }
3414 }
3415 }
3416 if (needs_commit)
3417 gsi_commit_edge_inserts ();
3418 }
3419
3420 if (DECL_STRUCT_FUNCTION (nnode->decl)->calls_alloca
3421 || is_stdarg || apply_args)
3422 for (cgraph_edge *e = nnode->callees, *enext; e; e = enext)
3423 {
3424 if (!e->call_stmt)
3425 continue;
3426
3427 gcall *call = e->call_stmt;
3428 gimple_stmt_iterator gsi = gsi_for_stmt (call);
3429 tree fndecl = e->callee->decl;
3430
3431 enext = e->next_callee;
3432
3433 if (gimple_alloca_call_p (call))
3434 {
3435 gimple_seq seq = call_update_watermark (wmptr, NULL,
3436 count: gsi_bb (i: gsi)->count);
3437 gsi_insert_finally_seq_after_call (gsi, seq);
3438 }
3439 else if (fndecl && is_stdarg
3440 && fndecl_built_in_p (node: fndecl, name1: BUILT_IN_VA_START))
3441 {
3442 /* Using a non-default stdarg ABI makes the function ineligible
3443 for internal strub. */
3444 gcc_checking_assert (builtin_decl_explicit (BUILT_IN_VA_START)
3445 == fndecl);
3446 tree bvacopy = builtin_decl_explicit (fncode: BUILT_IN_VA_COPY);
3447 gimple_call_set_fndecl (gs: call, decl: bvacopy);
3448 tree arg = vaptr;
3449 /* The va_copy source must be dereferenced, unless it's an array
3450 type, that would have decayed to a pointer. */
3451 if (TREE_CODE (TREE_TYPE (TREE_TYPE (vaptr))) != ARRAY_TYPE)
3452 {
3453 arg = gimple_fold_indirect_ref (vaptr);
3454 if (!arg)
3455 arg = build2 (MEM_REF,
3456 TREE_TYPE (TREE_TYPE (vaptr)),
3457 vaptr,
3458 build_int_cst (TREE_TYPE (vaptr), 0));
3459 if (!is_gimple_val (arg))
3460 arg = force_gimple_operand_gsi (&gsi, arg, true,
3461 NULL_TREE, true, GSI_SAME_STMT);
3462 }
3463 gimple_call_set_arg (gs: call, index: 1, arg);
3464 update_stmt (s: call);
3465 e->redirect_callee (n: cgraph_node::get_create (bvacopy));
3466 }
3467 else if (fndecl && apply_args
3468 && fndecl_built_in_p (node: fndecl, name1: BUILT_IN_APPLY_ARGS))
3469 {
3470 tree lhs = gimple_call_lhs (gs: call);
3471 gimple *assign = (lhs
3472 ? gimple_build_assign (lhs, aaval)
3473 : gimple_build_nop ());
3474 gsi_replace (&gsi, assign, true);
3475 cgraph_edge::remove (edge: e);
3476 }
3477 }
3478
3479 { // a little more copied from create_wrapper
3480
3481 /* Inline summary set-up. */
3482 nnode->analyze ();
3483 // inline_analyze_function (nnode);
3484 }
3485
3486 pop_cfun ();
3487 }
3488
3489 {
3490 push_cfun (DECL_STRUCT_FUNCTION (onode->decl));
3491 gimple_stmt_iterator gsi
3492 = gsi_after_labels (bb: single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
3493
3494 gcall *wrcall;
3495 while (!(wrcall = dyn_cast <gcall *> (p: gsi_stmt (i: gsi))))
3496 gsi_next (i: &gsi);
3497
3498 tree swm = create_tmp_var (get_wmt (), ".strub.watermark");
3499 TREE_ADDRESSABLE (swm) = true;
3500 tree swmp = build1 (ADDR_EXPR, get_pwmt (), swm);
3501
3502 tree enter = get_enter ();
3503 gcall *stptr = gimple_build_call (enter, 1, unshare_expr (swmp));
3504 gimple_set_location (g: stptr, location: gimple_location (g: wrcall));
3505 gsi_insert_before (&gsi, stptr, GSI_SAME_STMT);
3506 onode->create_edge (callee: cgraph_node::get_create (enter),
3507 call_stmt: stptr, count: gsi_bb (i: gsi)->count, cloning_p: false);
3508
3509 int nargs = gimple_call_num_args (gs: wrcall);
3510
3511 gimple_seq seq = NULL;
3512
3513 if (apply_args)
3514 {
3515 tree aalst = create_tmp_var (ptr_type_node, ".strub.apply_args");
3516 tree bappargs = builtin_decl_explicit (fncode: BUILT_IN_APPLY_ARGS);
3517 gcall *appargs = gimple_build_call (bappargs, 0);
3518 gimple_call_set_lhs (gs: appargs, lhs: aalst);
3519 gimple_set_location (g: appargs, location: gimple_location (g: wrcall));
3520 gsi_insert_before (&gsi, appargs, GSI_SAME_STMT);
3521 gimple_call_set_arg (gs: wrcall, index: nargs - 2 - is_stdarg, arg: aalst);
3522 onode->create_edge (callee: cgraph_node::get_create (bappargs),
3523 call_stmt: appargs, count: gsi_bb (i: gsi)->count, cloning_p: false);
3524 }
3525
3526 if (is_stdarg)
3527 {
3528 tree valst = create_tmp_var (va_list_type_node, ".strub.va_list");
3529 TREE_ADDRESSABLE (valst) = true;
3530 tree vaptr = build1 (ADDR_EXPR,
3531 build_pointer_type (va_list_type_node),
3532 valst);
3533 gimple_call_set_arg (gs: wrcall, index: nargs - 2, arg: unshare_expr (vaptr));
3534
3535 tree bvastart = builtin_decl_explicit (fncode: BUILT_IN_VA_START);
3536 gcall *vastart = gimple_build_call (bvastart, 2,
3537 unshare_expr (vaptr),
3538 integer_zero_node);
3539 gimple_set_location (g: vastart, location: gimple_location (g: wrcall));
3540 gsi_insert_before (&gsi, vastart, GSI_SAME_STMT);
3541 onode->create_edge (callee: cgraph_node::get_create (bvastart),
3542 call_stmt: vastart, count: gsi_bb (i: gsi)->count, cloning_p: false);
3543
3544 tree bvaend = builtin_decl_explicit (fncode: BUILT_IN_VA_END);
3545 gcall *vaend = gimple_build_call (bvaend, 1, unshare_expr (vaptr));
3546 gimple_set_location (g: vaend, location: gimple_location (g: wrcall));
3547 gimple_seq_add_stmt (&seq, vaend);
3548 }
3549
3550 gimple_call_set_arg (gs: wrcall, index: nargs - 1, arg: unshare_expr (swmp));
3551 // gimple_call_set_tail (wrcall, false);
3552 update_stmt (s: wrcall);
3553
3554 {
3555#if !ATTR_FNSPEC_DECONST_WATERMARK
3556 /* If the call will be assumed to not modify or even read the
3557 watermark, make it read and modified ourselves. */
3558 if ((gimple_call_flags (wrcall)
3559 & (ECF_CONST | ECF_PURE | ECF_NOVOPS)))
3560 {
3561 vec<tree, va_gc> *inputs = NULL;
3562 vec<tree, va_gc> *outputs = NULL;
3563 vec_safe_push (v&: outputs,
3564 obj: build_tree_list
3565 (build_tree_list
3566 (NULL_TREE, build_string (2, "=m")),
3567 swm));
3568 vec_safe_push (v&: inputs,
3569 obj: build_tree_list
3570 (build_tree_list
3571 (NULL_TREE, build_string (1, "m")),
3572 swm));
3573 gasm *forcemod = gimple_build_asm_vec ("", inputs, outputs,
3574 NULL, NULL);
3575 gimple_seq_add_stmt (&seq, forcemod);
3576
3577 /* If the call will be assumed to not even read the watermark,
3578 make sure it is already in memory before the call. */
3579 if ((gimple_call_flags (wrcall) & ECF_CONST))
3580 {
3581 vec<tree, va_gc> *inputs = NULL;
3582 vec_safe_push (v&: inputs,
3583 obj: build_tree_list
3584 (build_tree_list
3585 (NULL_TREE, build_string (1, "m")),
3586 swm));
3587 gasm *force_store = gimple_build_asm_vec ("", inputs, NULL,
3588 NULL, NULL);
3589 gimple_set_location (g: force_store, location: gimple_location (g: wrcall));
3590 gsi_insert_before (&gsi, force_store, GSI_SAME_STMT);
3591 }
3592 }
3593#endif
3594
3595 gcall *sleave = gimple_build_call (get_leave (), 1,
3596 unshare_expr (swmp));
3597 gimple_seq_add_stmt (&seq, sleave);
3598
3599 gassign *clobber = gimple_build_assign (swm,
3600 build_clobber
3601 (TREE_TYPE (swm)));
3602 gimple_seq_add_stmt (&seq, clobber);
3603 }
3604
3605 gsi_insert_finally_seq_after_call (gsi, seq);
3606
3607 /* For nnode, we don't rebuild edges because we wish to retain
3608 any redirections copied to it from earlier passes, so we add
3609 call graph edges explicitly there, but for onode, we create a
3610 fresh function, so we may as well just issue the calls and
3611 then rebuild all cgraph edges. */
3612 // cgraph_edge::rebuild_edges ();
3613 onode->analyze ();
3614 // inline_analyze_function (onode);
3615
3616 pop_cfun ();
3617 }
3618 }
3619
3620 return 0;
3621}
3622
3623simple_ipa_opt_pass *
3624make_pass_ipa_strub (gcc::context *ctxt)
3625{
3626 return new pass_ipa_strub (ctxt);
3627}
3628
3629#include "gt-ipa-strub.h"
3630

source code of gcc/ipa-strub.cc